From 65f9dbaa1eb9df092bb2261cab044438473e885e Mon Sep 17 00:00:00 2001 From: Tizen Infrastructure Date: Tue, 24 Mar 2020 02:52:35 +0000 Subject: [PATCH 001/244] Initial empty repository From c20274aaf84846a8ded2817633c2e120cb1e8e34 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 24 Mar 2020 15:07:51 +0900 Subject: [PATCH 002/244] + Initial draft Introduce project skeleton such as build envrionment and interfaces to build up code further cooperatively. Change-Id: Ie9ac38991f609d33637283134906d7cc3f2ac19e --- .gitignore | 4 + AUTHORS | 1 + LICENSE | 202 +++++++++++++++++++++++++++++++++++++++ README | 7 ++ inc/meson.build | 3 + inc/tizenvg.h | 67 +++++++++++++ meson.build | 31 ++++++ pc/tizenvg.pc.in | 10 ++ src/examples/main.cpp | 27 ++++++ src/examples/meson.build | 1 + src/lib/TvgEngine.cpp | 61 ++++++++++++ src/lib/meson.build | 8 ++ src/meson.build | 31 ++++++ test/makefile | 2 + test/test.cpp | 12 +++ tizenvg.manifest | 5 + 16 files changed, 472 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 LICENSE create mode 100644 README create mode 100644 inc/meson.build create mode 100644 inc/tizenvg.h create mode 100644 meson.build create mode 100644 pc/tizenvg.pc.in create mode 100644 src/examples/main.cpp create mode 100644 src/examples/meson.build create mode 100644 src/lib/TvgEngine.cpp create mode 100644 src/lib/meson.build create mode 100644 src/meson.build create mode 100644 test/makefile create mode 100644 test/test.cpp create mode 100644 tizenvg.manifest diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a6c4662b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build +.vscode +*.swp +test diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..13ce5113 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Hermet Park diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8a7fbe45 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2016 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/README b/README new file mode 100644 index 00000000..72cf83d4 --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +Tizen Vector Graphics 0.1.0 + +****************************************************************************** + + FOR ANY ISSUES PLEASE EMAIL: + +****************************************************************************** diff --git a/inc/meson.build b/inc/meson.build new file mode 100644 index 00000000..4046844c --- /dev/null +++ b/inc/meson.build @@ -0,0 +1,3 @@ +install_headers([ + 'tizenvg.h', + ]) diff --git a/inc/tizenvg.h b/inc/tizenvg.h new file mode 100644 index 00000000..a8597ad9 --- /dev/null +++ b/inc/tizenvg.h @@ -0,0 +1,67 @@ +/* + * 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 _TIZENVG_H_ +#define _TIZENVG_H_ + +#include + +#ifdef TIZENVG_BUILD + #define TIZENVG_EXPORT __attribute__ ((visibility ("default"))) +#else + #define TIZENVG_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +namespace tizenvg +{ + +/** + * @class Engine + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TIZENVG_EXPORT Engine final +{ +public: + /** + * @brief ... + * + * @param[in] arg ... + * + * @note ... + * + * @return ... + * + * @see ... + */ + static int init() noexcept; + static int term() noexcept; +}; + +} //namespace + +#ifdef __cplusplus +} +#endif + +#endif //_TIZENVG_H_ diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..32dd23be --- /dev/null +++ b/meson.build @@ -0,0 +1,31 @@ +project('tizenvg', + 'cpp', + default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14'], + version : '0.1.0', + license : 'Apache-2.0') + +config_h = configuration_data() + +configure_file( + output: 'config.h', + configuration: config_h +) + +headers = [include_directories('inc')] + +subdir('inc') +subdir('src') + +summary = ''' + +Summary: + tizenvg version : @0@ + Build type : @1@ + Prefix : @2@ +'''.format( + meson.project_version(), + get_option('buildtype'), + get_option('prefix'), + ) + +message(summary) diff --git a/pc/tizenvg.pc.in b/pc/tizenvg.pc.in new file mode 100644 index 00000000..631bc2ae --- /dev/null +++ b/pc/tizenvg.pc.in @@ -0,0 +1,10 @@ +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 new file mode 100644 index 00000000..4b9154bc --- /dev/null +++ b/src/examples/main.cpp @@ -0,0 +1,27 @@ +/* + * 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. + * + */ +#include + +using namespace std; + +int +main(int argc, char *argv[]) +{ + cout << "test tizenvg!" << endl; + + return 0; +} diff --git a/src/examples/meson.build b/src/examples/meson.build new file mode 100644 index 00000000..8954536e --- /dev/null +++ b/src/examples/meson.build @@ -0,0 +1 @@ +executable('tizenvg_sample', 'main.cpp') diff --git a/src/lib/TvgEngine.cpp b/src/lib/TvgEngine.cpp new file mode 100644 index 00000000..08f6bc15 --- /dev/null +++ b/src/lib/TvgEngine.cpp @@ -0,0 +1,61 @@ +/* + * 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_ENGINE_CPP_ +#define _TVG_ENGINE_CPP_ + +#include +#include +#include "tizenvg.h" + +using namespace std; +using namespace tizenvg; + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ +namespace tizenvg +{ + +class EngineImpl +{ + public: + static int init() { + return 0; + } + + static int term() { + return 0; + } +}; + +} + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +int Engine::init() noexcept +{ + return EngineImpl::init(); +} + +int Engine::term() noexcept +{ + return EngineImpl::term(); +} + +#endif /* _TVG_ENGINE_CPP_ */ diff --git a/src/lib/meson.build b/src/lib/meson.build new file mode 100644 index 00000000..1facacb6 --- /dev/null +++ b/src/lib/meson.build @@ -0,0 +1,8 @@ +source_file = [ + 'TvgEngine.cpp' +] + +src_dep = declare_dependency( + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 00000000..d3fde4d1 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,31 @@ +compiler_flags = ['-DTIZENVG_BUILD'] + +subdir('lib') +subdir('examples') + +tizenvg_lib_dep = [ src_dep ] + +tizenvg_lib = library( + 'tizenvg', + include_directories : headers, + version : meson.project_version(), + dependencies : tizenvg_lib_dep, + install : true, + cpp_args : compiler_flags, + gnu_symbol_visibility : 'hidden', +) + +tizenvg_dep = declare_dependency( + include_directories: headers, + link_with : tizenvg_lib +) + +pkg_mod = import('pkgconfig') + +pkg_mod.generate( + libraries : tizenvg_lib, + version : meson.project_version(), + name : 'libtizenvg', + filebase : 'tizenvg', + description : 'A Tizen library for rendering vector graphics' +) diff --git a/test/makefile b/test/makefile new file mode 100644 index 00000000..4dc91353 --- /dev/null +++ b/test/makefile @@ -0,0 +1,2 @@ +all: + gcc -o test test.cpp -g -lstdc++ `pkg-config --cflags --libs tizenvg` diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 00000000..6c953586 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,12 @@ +#include + +using namespace std; + +int main(int argc, char **argv) +{ + tizenvg::Engine::init(); + + //... + + tizenvg::Engine::term(); +} diff --git a/tizenvg.manifest b/tizenvg.manifest new file mode 100644 index 00000000..97e8c313 --- /dev/null +++ b/tizenvg.manifest @@ -0,0 +1,5 @@ + + + + + From df94be1d9d9648804bb1ebe18a2db60c47512f30 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 25 Mar 2020 13:54:29 +0900 Subject: [PATCH 003/244] build up base infra code for prototype. Change-Id: I117a798caf4d9fedfe5c467471dee2f0150c2630 --- inc/tizenvg.h | 137 ++++++++++++++++++++++- src/lib/meson.build | 8 +- src/lib/tvgCanvasBase.h | 46 ++++++++ src/lib/tvgCommon.h | 29 +++++ src/lib/{TvgEngine.cpp => tvgEngine.cpp} | 27 +---- src/lib/tvgGlCanvas.cpp | 71 ++++++++++++ src/lib/tvgSceneNode.cpp | 66 +++++++++++ src/lib/tvgShapeNode.cpp | 104 +++++++++++++++++ src/lib/tvgSwCanvas.cpp | 102 +++++++++++++++++ test/makefile | 2 +- test/test.cpp | 12 -- test/tvgDrawShape.cpp | 30 +++++ test/tvgGradient.cpp | 55 +++++++++ test/tvgMultipleShapes.cpp | 36 ++++++ test/tvgPath.cpp | 39 +++++++ test/tvgScene.cpp | 49 ++++++++ test/tvgStroke.cpp | 39 +++++++ test/tvgUpdate.cpp | 49 ++++++++ 18 files changed, 863 insertions(+), 38 deletions(-) create mode 100644 src/lib/tvgCanvasBase.h create mode 100644 src/lib/tvgCommon.h rename src/lib/{TvgEngine.cpp => tvgEngine.cpp} (79%) create mode 100644 src/lib/tvgGlCanvas.cpp create mode 100644 src/lib/tvgSceneNode.cpp create mode 100644 src/lib/tvgShapeNode.cpp create mode 100644 src/lib/tvgSwCanvas.cpp delete mode 100644 test/test.cpp create mode 100644 test/tvgDrawShape.cpp create mode 100644 test/tvgGradient.cpp create mode 100644 test/tvgMultipleShapes.cpp create mode 100644 test/tvgPath.cpp create mode 100644 test/tvgScene.cpp create mode 100644 test/tvgStroke.cpp create mode 100644 test/tvgUpdate.cpp diff --git a/inc/tizenvg.h b/inc/tizenvg.h index a8597ad9..cc334e0b 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -25,13 +25,146 @@ #define TIZENVG_EXPORT #endif +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "TIZENVG" + + #ifdef __cplusplus extern "C" { #endif -namespace tizenvg +#define _TIZENVG_DECLARE_PRIVATE(A) \ +private: \ + struct Impl; \ + std::unique_ptr pImpl; \ + A(const A&) = delete; \ + const A& operator=(const A&) = delete; \ + A() + +#define _TIZENVG_DISABLE_CTOR(A) \ + A() = delete; \ + ~A() = delete + +namespace tvg { +class SceneNode; + + +/** + * @class PaintNode + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TIZENVG_EXPORT PaintNode +{ +public: + virtual ~PaintNode() {} + virtual int prepare() = 0; +}; + + +/** + * @class ShapeNode + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TIZENVG_EXPORT ShapeNode final : public PaintNode +{ +public: + ~ShapeNode(); + + int prepare() noexcept override; + + static std::unique_ptr gen(); + + _TIZENVG_DECLARE_PRIVATE(ShapeNode); +}; + + +/** + * @class SceneNode + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TIZENVG_EXPORT SceneNode final : public PaintNode +{ +public: + ~SceneNode(); + + int push(std::unique_ptr shape) noexcept; + int prepare() noexcept override; + + static std::unique_ptr gen() noexcept; + + _TIZENVG_DECLARE_PRIVATE(SceneNode); +}; + + +/** + * @class SwCanvas + * + * @ingroup TizenVG + * + @brief description... + * + */ +class TIZENVG_EXPORT SwCanvas final +{ +public: + ~SwCanvas(); + + int push(std::unique_ptr paint) noexcept; + int clear() noexcept; + + int draw(bool async = true) noexcept; + int drawSync() noexcept; + + int target(uint32_t* buffer, size_t stride, size_t height) noexcept; + + static std::unique_ptr gen(uint32_t* buffer = nullptr, size_t stride = 0, size_t height = 0) noexcept; + + _TIZENVG_DECLARE_PRIVATE(SwCanvas); +}; + + +/** + * @class GlCanvas + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TIZENVG_EXPORT GlCanvas final +{ +public: + ~GlCanvas(); + + int push(std::unique_ptr paint) noexcept; + int clear() noexcept; + + //TODO: Gl Specific methods. Need gl backend configuration methods as well. + int draw(bool async = true) noexcept { return 0; } + int drawSync() noexcept { return 0; } + + static std::unique_ptr gen() noexcept; + + _TIZENVG_DECLARE_PRIVATE(GlCanvas); +}; + + /** * @class Engine * @@ -56,6 +189,8 @@ public: */ static int init() noexcept; static int term() noexcept; + + _TIZENVG_DISABLE_CTOR(Engine); }; } //namespace diff --git a/src/lib/meson.build b/src/lib/meson.build index 1facacb6..fb856bf0 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -1,5 +1,11 @@ source_file = [ - 'TvgEngine.cpp' + 'tvgCommon.h', + 'tvgEngine.cpp', + 'tvgCanvasBase.h', + 'tvgSwCanvas.cpp', + 'tvgGlCanvas.cpp', + 'tvgSceneNode.cpp', + 'tvgShapeNode.cpp' ] src_dep = declare_dependency( diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h new file mode 100644 index 00000000..83607bf4 --- /dev/null +++ b/src/lib/tvgCanvasBase.h @@ -0,0 +1,46 @@ +/* + * 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_CANVAS_CPP_ +#define _TVG_CANVAS_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct CanvasBase +{ + + int push(unique_ptr paint) + { + return 0; + } + + int clear() + { + return 0; + } + +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +#endif /* _TVG_CANVAS_CPP_ */ diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h new file mode 100644 index 00000000..f69af00f --- /dev/null +++ b/src/lib/tvgCommon.h @@ -0,0 +1,29 @@ +/* + * 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_COMMON_H_ +#define _TVG_COMMON_H_ + +#include +#include +#include +#include "tizenvg.h" + +using namespace std; +using namespace tvg; +using var = float; + +#endif //_TVG_COMMON_H_ diff --git a/src/lib/TvgEngine.cpp b/src/lib/tvgEngine.cpp similarity index 79% rename from src/lib/TvgEngine.cpp rename to src/lib/tvgEngine.cpp index 08f6bc15..838f4ca8 100644 --- a/src/lib/TvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -17,32 +17,12 @@ #ifndef _TVG_ENGINE_CPP_ #define _TVG_ENGINE_CPP_ -#include -#include -#include "tizenvg.h" - -using namespace std; -using namespace tizenvg; +#include "tvgCommon.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -namespace tizenvg -{ -class EngineImpl -{ - public: - static int init() { - return 0; - } - - static int term() { - return 0; - } -}; - -} /************************************************************************/ /* External Class Implementation */ @@ -50,12 +30,13 @@ class EngineImpl int Engine::init() noexcept { - return EngineImpl::init(); + return 0; } + int Engine::term() noexcept { - return EngineImpl::term(); + return 0; } #endif /* _TVG_ENGINE_CPP_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp new file mode 100644 index 00000000..573600eb --- /dev/null +++ b/src/lib/tvgGlCanvas.cpp @@ -0,0 +1,71 @@ +/* + * 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_GLCANVAS_CPP_ +#define _TVG_GLCANVAS_CPP_ + +#include "tvgCommon.h" +#include "tvgCanvasBase.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct GlCanvas::Impl : CanvasBase +{ + //... +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +GlCanvas::GlCanvas() : pImpl(make_unique()) +{ +} + + +GlCanvas::~GlCanvas() +{ + cout << "GlCanvas(" << this << ") destroyed!" << endl; +} + + +unique_ptr GlCanvas::gen() noexcept +{ + auto canvas = unique_ptr(new GlCanvas); + assert(canvas); + + return canvas; +} + + +int GlCanvas::push(unique_ptr paint) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->push(move(paint)); +} + +int GlCanvas::clear() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->clear(); +} + +#endif /* _TVG_GLCANVAS_CPP_ */ diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp new file mode 100644 index 00000000..8da41fca --- /dev/null +++ b/src/lib/tvgSceneNode.cpp @@ -0,0 +1,66 @@ +/* + * 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_SCENE_NODE_CPP_ +#define _TVG_SCENE_NODE_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct SceneNode::Impl +{ + +}; + + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +SceneNode :: SceneNode() : pImpl(make_unique()) +{ + +} + + +SceneNode :: ~SceneNode() +{ + cout << "SceneNode(" << this << ") destroyed!" << endl; +} + + +unique_ptr SceneNode::gen() noexcept +{ + return unique_ptr(new SceneNode); +} + +int SceneNode :: push(unique_ptr shape) noexcept +{ + return 0; +} + + +int SceneNode :: prepare() noexcept +{ + + return 0; +} + +#endif /* _TVG_SCENE_NODE_CPP_ */ diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp new file mode 100644 index 00000000..4fb4b107 --- /dev/null +++ b/src/lib/tvgShapeNode.cpp @@ -0,0 +1,104 @@ +/* + * 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_SHAPE_NODE_CPP_ +#define _TVG_SHAPE_NODE_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct ShapeFill +{ +}; + + +struct ShapeStroke +{ +}; + + +struct ShapePath +{ +}; + + +struct ShapeTransform +{ + var e[4*4]; +}; + + +struct ShapeChildren +{ + vector> v; +}; + + +struct ShapeNode::Impl +{ + ShapeChildren *children = nullptr; + ShapeTransform *transform = nullptr; + ShapeFill *fill = nullptr; + ShapeStroke *stroke = nullptr; + ShapePath *path = nullptr; + uint32_t color = 0; + uint32_t id = 0; + + + ~Impl() + { + if (path) delete(path); + if (stroke) delete(stroke); + if (fill) delete(fill); + if (transform) delete(transform); + if (children) delete(children); + } + +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +ShapeNode :: ShapeNode() : pImpl(make_unique()) +{ + +} + + +ShapeNode :: ~ShapeNode() +{ + cout << "ShapeNode(" << this << ") destroyed!" << endl; +} + + +unique_ptr ShapeNode::gen() +{ + return unique_ptr(new ShapeNode); +} + + +int ShapeNode :: prepare() noexcept +{ + return 0; +} + + +#endif //_TVG_SHAPE_NODE_CPP_ diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp new file mode 100644 index 00000000..05296cdb --- /dev/null +++ b/src/lib/tvgSwCanvas.cpp @@ -0,0 +1,102 @@ +/* + * 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_SWCANVAS_CPP_ +#define _TVG_SWCANVAS_CPP_ + +#include "tvgCommon.h" +#include "tvgCanvasBase.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct SwCanvas::Impl : CanvasBase +{ + uint32_t* buffer = nullptr; + int stride = 0; + int height = 0; +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->buffer = buffer; + impl->stride = stride; + impl->height = height; + + return 0; +} + + +int SwCanvas::draw(bool async) noexcept +{ + return 0; +} + + +int SwCanvas::drawSync() noexcept +{ + return 0; +} + + +int SwCanvas::push(unique_ptr paint) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->push(move(paint)); +} + + +int SwCanvas::clear() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->clear(); +} + + +SwCanvas::SwCanvas() : pImpl(make_unique()) +{ +} + + +SwCanvas::~SwCanvas() +{ + cout << "SwCanvas(" << this << ") destroyed!" << endl; +} + + +unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t height) noexcept +{ + auto canvas = unique_ptr(new SwCanvas); + assert(canvas); + + int ret = canvas.get()->target(buffer, stride, height); + if (ret > 0) return nullptr; + + return canvas; +} + +#endif /* _TVG_SWCANVAS_CPP_ */ diff --git a/test/makefile b/test/makefile index 4dc91353..0f89da04 100644 --- a/test/makefile +++ b/test/makefile @@ -1,2 +1,2 @@ all: - gcc -o test test.cpp -g -lstdc++ `pkg-config --cflags --libs tizenvg` + gcc -o tvgDrawShape tvgDrawShape.cpp -g -lstdc++ `pkg-config --cflags --libs tizenvg` diff --git a/test/test.cpp b/test/test.cpp deleted file mode 100644 index 6c953586..00000000 --- a/test/test.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -using namespace std; - -int main(int argc, char **argv) -{ - tizenvg::Engine::init(); - - //... - - tizenvg::Engine::term(); -} diff --git a/test/tvgDrawShape.cpp b/test/tvgDrawShape.cpp new file mode 100644 index 00000000..34f4dc9e --- /dev/null +++ b/test/tvgDrawShape.cpp @@ -0,0 +1,30 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Prepare a Shape + auto shape1 = tvg::ShapeNode::gen(); + shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius + shape1->fill(0, 255, 0, 255); + + //Draw the Shape onto the Canvas + canvas->push(move(shape1)); + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgGradient.cpp b/test/tvgGradient.cpp new file mode 100644 index 00000000..2bf2824a --- /dev/null +++ b/test/tvgGradient.cpp @@ -0,0 +1,55 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Prepare a Shape + auto shape1 = tvg::ShapeNode::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); + + //Draw the Shape onto the Canvas + canvas->push(move(shape1)); + + //Prepare Circle + auto shape2 = tvg::ShapeNode::gen(); + shape2->circle(400, 400, 200); //cx, cy, radius + shape2->fill(255, 255, 0, 255); //r, g, b, a + canvas->push(move(shape2)); + + //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); + + //Draw the Shape onto the Canvas + canvas->push(move(shape2)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgMultipleShapes.cpp b/test/tvgMultipleShapes.cpp new file mode 100644 index 00000000..fd7ea818 --- /dev/null +++ b/test/tvgMultipleShapes.cpp @@ -0,0 +1,36 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Prepare Rectangle + auto shape1 = tvg::ShapeNode::gen(); + shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius + shape1->fill(0, 255, 0, 255); //r, g, b, a + canvas->push(move(shape1)); + + //Prepare Circle + auto shape2 = tvg::ShapeNode::gen(); + shape2->circle(400, 400, 200); //cx, cy, radius + shape2->fill(255, 255, 0, 255); //r, g, b, a + canvas->push(move(shape2)); + + //Draw the Shapes onto the Canvas + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgPath.cpp b/test/tvgPath.cpp new file mode 100644 index 00000000..68f0998f --- /dev/null +++ b/test/tvgPath.cpp @@ -0,0 +1,39 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Prepare Path + auto path = tvg::Path::gen(); + path.reserve(cmdCnt, ptCnt); //command count, points count + path.moveTo(...); + path.lineTo(...); + path.cubicTo(...); + path.close(); + + //Prepare a Shape + auto shape1 = tvg::ShapeNode::gen(); + shape1->path(move(path)); //propagate owner + shape1->path(path.get()); //copy data directly + shape1->fill(0, 255, 0, 255); + + //Draw the Shape onto the Canvas + canvas->push(move(shape1)); + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgScene.cpp b/test/tvgScene.cpp new file mode 100644 index 00000000..56a9a6c1 --- /dev/null +++ b/test/tvgScene.cpp @@ -0,0 +1,49 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Create a Scene + auto scene = tvg::SceneNode::gen(3); //reserve 3 shape nodes (optional) + + //Shape1 + auto shape1 = tvg::ShapeNode::gen(); + shape1->rect(0, 0, 400, 400, 0.1); + shape1->fill(255, 0, 0, 255); + shape1->rotate(0, 0, 45); //axis x, y, z + scene->push(move(shape1)); + + //Shape2 + auto shape2 = tvg::ShapeNode::gen(); + shape2->rect(0, 0, 400, 400, 0.1); + shape2->fill(0, 255, 0, 255); + shape2->transform(matrix); //by matrix (var matrix[4 * 4];) + scene->push(move(shape2)); + + //Shape3 + auto shape3 = tvg::ShapeNode::gen(); + shape3->rect(0, 0, 400, 400, 0.1); + shape3->fill(0, 0, 255, 255); + shape3->origin(100, 100); //offset + scene->push(move(shape3)); + + //Draw the Scene onto the Canvas + canvas->push(move(scene)); + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgStroke.cpp b/test/tvgStroke.cpp new file mode 100644 index 00000000..6b90cda4 --- /dev/null +++ b/test/tvgStroke.cpp @@ -0,0 +1,39 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Prepare a Shape + auto shape1 = tvg::ShapeNode::gen(); + shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius + shape1->fill(0, 255, 0, 255); + + //Stroke Style + shape1->strokeColor(0, 0, 0, 255); //r, g, b, a + shape1->strokeWidth(1); //1px + shape1->strokeJoin(tvg::StrokeJoin::Miter); + shape1->strokeLineCap(tvg::StrokeLineCap::Butt); + + uint32_t dash[] = {3, 1, 5, 1}; + shape1->strokeDash(dash, 4); + + //Draw the Shape onto the Canvas + canvas->push(move(shape1)); + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgUpdate.cpp b/test/tvgUpdate.cpp new file mode 100644 index 00000000..5bef2b93 --- /dev/null +++ b/test/tvgUpdate.cpp @@ -0,0 +1,49 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Create a Scene + auto scene = tvg::SceneNode::gen(); + + //Shape1 + auto shape1 = tvg::ShapeNode::gen(); + auto pshape1 = shape1->get(); //acquire shape1 pointer to access directly + shape1->rect(0, 0, 400, 400, 0.1); + shape1->fill(255, 0, 0, 255); + shape1->rotate(0, 0, 45); //axis x, y, z + scene->push(move(shape1)); + + //Draw the Scene onto the Canvas + canvas->push(move(scene)); + + //Draw frame 1 + canvas->draw(); + canvas->sync(); + + //Clear previous shape path + pshape1->clear(); + pshape1->rect(0, 0, 300, 300, 0.1); + + //Prepapre for drawing + pshape1->update(); + + //Draw frame 2 + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} From bf056606666ac0dd1443fae5bcc0fb924f47e104 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 30 Mar 2020 20:51:26 +0900 Subject: [PATCH 004/244] Update sample prototypes. This is still a hard work and under the intensive settle up stage. Change-Id: Ibfbeaabe8a51dc5edeeccf8fe75e65e60b91f703 --- inc/tizenvg.h | 4 ++-- src/lib/tvgSwCanvas.cpp | 2 +- test/tvgComposition.cpp | 35 +++++++++++++++++++++++++++++++++++ test/tvgDrawShape.cpp | 12 ++++++++---- test/tvgGradient.cpp | 5 +---- test/tvgMultipleShapes.cpp | 1 + test/tvgPath.cpp | 4 ++-- test/tvgScene.cpp | 3 ++- test/tvgStroke.cpp | 2 +- test/tvgUpdate.cpp | 22 ++++++++++++++-------- 10 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 test/tvgComposition.cpp diff --git a/inc/tizenvg.h b/inc/tizenvg.h index cc334e0b..e790ea10 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -129,7 +129,7 @@ public: int clear() noexcept; int draw(bool async = true) noexcept; - int drawSync() noexcept; + int sync() noexcept; int target(uint32_t* buffer, size_t stride, size_t height) noexcept; @@ -157,7 +157,7 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. int draw(bool async = true) noexcept { return 0; } - int drawSync() noexcept { return 0; } + int sync() noexcept { return 0; } static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 05296cdb..13e91f34 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -55,7 +55,7 @@ int SwCanvas::draw(bool async) noexcept } -int SwCanvas::drawSync() noexcept +int SwCanvas::sync() noexcept { return 0; } diff --git a/test/tvgComposition.cpp b/test/tvgComposition.cpp new file mode 100644 index 00000000..cf5ed264 --- /dev/null +++ b/test/tvgComposition.cpp @@ -0,0 +1,35 @@ +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //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::ShapeNode::gen(); + shape->composite(canvas, tvg::CompMaskAdd); + + //Draw the Scene onto the Canvas + canvas2->push(move(shape)); + canvas2->draw(); + canvas2->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/tvgDrawShape.cpp b/test/tvgDrawShape.cpp index 34f4dc9e..7aaba5be 100644 --- a/test/tvgDrawShape.cpp +++ b/test/tvgDrawShape.cpp @@ -15,13 +15,17 @@ int main(int argc, char **argv) //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //Prepare a Shape + //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); - shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius - shape1->fill(0, 255, 0, 255); +// shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius +// shape1->fill(0, 255, 0, 255); //r, g, b, a - //Draw the Shape onto the Canvas + /* 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->draw(); canvas->sync(); diff --git a/test/tvgGradient.cpp b/test/tvgGradient.cpp index 2bf2824a..a696839b 100644 --- a/test/tvgGradient.cpp +++ b/test/tvgGradient.cpp @@ -27,14 +27,11 @@ int main(int argc, char **argv) fill1->color(1, 0, 0, 255, 255); //color Stop 2: Blue shape1.fill(fill1); - //Draw the Shape onto the Canvas canvas->push(move(shape1)); //Prepare Circle auto shape2 = tvg::ShapeNode::gen(); shape2->circle(400, 400, 200); //cx, cy, radius - shape2->fill(255, 255, 0, 255); //r, g, b, a - canvas->push(move(shape2)); //Radial Gradient Fill auto fill2 = tvg::RadialFill::gen(); @@ -44,9 +41,9 @@ int main(int argc, char **argv) fill2->color(1, 0, 0, 255, 255); //color Stop 2: Blue shape2.fill(fill2); - //Draw the Shape onto the Canvas canvas->push(move(shape2)); + //Draw the Shapes onto the Canvas canvas->draw(); canvas->sync(); diff --git a/test/tvgMultipleShapes.cpp b/test/tvgMultipleShapes.cpp index fd7ea818..feeb9644 100644 --- a/test/tvgMultipleShapes.cpp +++ b/test/tvgMultipleShapes.cpp @@ -14,6 +14,7 @@ int main(int argc, char **argv) //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + canvas->reserve(2); //reserve 2 shape nodes (optional) //Prepare Rectangle auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/tvgPath.cpp b/test/tvgPath.cpp index 68f0998f..e260682f 100644 --- a/test/tvgPath.cpp +++ b/test/tvgPath.cpp @@ -25,8 +25,8 @@ int main(int argc, char **argv) //Prepare a Shape auto shape1 = tvg::ShapeNode::gen(); - shape1->path(move(path)); //propagate owner - shape1->path(path.get()); //copy data directly + shape1->path(move(path)); //migrate owner otherwise, + shape1->path(path.get()); //copy raw data directly for performance shape1->fill(0, 255, 0, 255); //Draw the Shape onto the Canvas diff --git a/test/tvgScene.cpp b/test/tvgScene.cpp index 56a9a6c1..f3010dca 100644 --- a/test/tvgScene.cpp +++ b/test/tvgScene.cpp @@ -16,7 +16,8 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Create a Scene - auto scene = tvg::SceneNode::gen(3); //reserve 3 shape nodes (optional) + auto scene = tvg::SceneNode::gen(); + scene->reserve(3); //reserve 3 shape nodes (optional) //Shape1 auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/tvgStroke.cpp b/test/tvgStroke.cpp index 6b90cda4..6a514123 100644 --- a/test/tvgStroke.cpp +++ b/test/tvgStroke.cpp @@ -26,7 +26,7 @@ int main(int argc, char **argv) shape1->strokeJoin(tvg::StrokeJoin::Miter); shape1->strokeLineCap(tvg::StrokeLineCap::Butt); - uint32_t dash[] = {3, 1, 5, 1}; + uint32_t dash[] = {3, 1, 5, 1}; //dash pattern shape1->strokeDash(dash, 4); //Draw the Shape onto the Canvas diff --git a/test/tvgUpdate.cpp b/test/tvgUpdate.cpp index 5bef2b93..3a812897 100644 --- a/test/tvgUpdate.cpp +++ b/test/tvgUpdate.cpp @@ -20,30 +20,36 @@ int main(int argc, char **argv) //Shape1 auto shape1 = tvg::ShapeNode::gen(); - auto pshape1 = shape1->get(); //acquire shape1 pointer to access directly + + /* Acquire shape1 pointer to access directly later. + instead, you should consider not to interrupt this pointer life-cycle. */ + auto pshape1 = shape1->get(); + shape1->rect(0, 0, 400, 400, 0.1); shape1->fill(255, 0, 0, 255); shape1->rotate(0, 0, 45); //axis x, y, z - scene->push(move(shape1)); - //Draw the Scene onto the Canvas + scene->push(move(shape1)); canvas->push(move(scene)); - //Draw frame 1 + //Draw first frame canvas->draw(); canvas->sync(); - //Clear previous shape path - pshape1->clear(); + /* Clear the previous shape path and Prepare a new shape path. + You can call clear() to explicitly clear path data. */ pshape1->rect(0, 0, 300, 300, 0.1); - //Prepapre for drawing + //Prepapre for drawing (this may work asynchronously) pshape1->update(); - //Draw frame 2 + //Draw second frame canvas->draw(); canvas->sync(); + //Explicitly clear all retained paint nodes. + canvas->clear(); + //Terminate TizenVG Engine tvg::Engine::term(); } From 02b2d812e4754b1432edea53c4ddb43f4004529c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 1 Apr 2020 19:48:37 +0900 Subject: [PATCH 005/244] implement basic interfaces major functions are added for Path specification. added backend engine infra skeleton. Change-Id: Ia923b02649cff545fa768ab8538ad7187195826f --- .gitignore | 2 +- inc/tizenvg.h | 15 +- src/lib/gl_engine/meson.build | 9 ++ src/lib/gl_engine/tvgGlRaster.cpp | 61 +++++++ src/lib/gl_engine/tvgGlRaster.h | 38 +++++ src/lib/meson.build | 5 + src/lib/sw_engine/meson.build | 9 ++ src/lib/sw_engine/tvgSwRaster.cpp | 61 +++++++ src/lib/sw_engine/tvgSwRaster.h | 38 +++++ src/lib/tvgCanvasBase.h | 50 +++++- src/lib/tvgCommon.h | 20 ++- src/lib/tvgEngine.cpp | 16 +- src/lib/tvgGlCanvas.cpp | 3 +- src/lib/tvgSceneNode.cpp | 2 +- src/lib/tvgShapeNode.cpp | 86 +++++++--- src/lib/tvgShapePath.h | 149 ++++++++++++++++++ src/lib/tvgSwCanvas.cpp | 5 + src/meson.build | 2 +- test/makefile | 2 +- ...tvgComposition.cpp => testComposition.cpp} | 0 test/{tvgGradient.cpp => testGradient.cpp} | 0 ...tipleShapes.cpp => testMultipleShapes.cpp} | 0 test/{tvgPath.cpp => testPath.cpp} | 0 test/{tvgScene.cpp => testScene.cpp} | 0 test/{tvgDrawShape.cpp => testShape.cpp} | 4 +- test/{tvgStroke.cpp => testStroke.cpp} | 0 test/{tvgUpdate.cpp => testUpdate.cpp} | 0 27 files changed, 541 insertions(+), 36 deletions(-) create mode 100644 src/lib/gl_engine/meson.build create mode 100644 src/lib/gl_engine/tvgGlRaster.cpp create mode 100644 src/lib/gl_engine/tvgGlRaster.h create mode 100644 src/lib/sw_engine/meson.build create mode 100644 src/lib/sw_engine/tvgSwRaster.cpp create mode 100644 src/lib/sw_engine/tvgSwRaster.h create mode 100644 src/lib/tvgShapePath.h rename test/{tvgComposition.cpp => testComposition.cpp} (100%) rename test/{tvgGradient.cpp => testGradient.cpp} (100%) rename test/{tvgMultipleShapes.cpp => testMultipleShapes.cpp} (100%) rename test/{tvgPath.cpp => testPath.cpp} (100%) rename test/{tvgScene.cpp => testScene.cpp} (100%) rename test/{tvgDrawShape.cpp => testShape.cpp} (85%) rename test/{tvgStroke.cpp => testStroke.cpp} (100%) rename test/{tvgUpdate.cpp => testUpdate.cpp} (100%) diff --git a/.gitignore b/.gitignore index a6c4662b..45329ec6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ build .vscode *.swp -test +testShape diff --git a/inc/tizenvg.h b/inc/tizenvg.h index e790ea10..aeea75f2 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -50,7 +50,7 @@ private: \ namespace tvg { -class SceneNode; +enum class TIZENVG_EXPORT PathCommand { Close, MoveTo, LineTo, CubicTo }; /** @@ -65,7 +65,7 @@ class TIZENVG_EXPORT PaintNode { public: virtual ~PaintNode() {} - virtual int prepare() = 0; + virtual int update() = 0; }; @@ -82,7 +82,12 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode public: ~ShapeNode(); - int prepare() noexcept override; + int update() noexcept override; + + int appendRect(float x, float y, float w, float h, float radius) noexcept; + int appendCircle(float cx, float cy, float radius) noexcept; + int fill(uint32_t r, uint32_t g, uint32_t b, uint32_t a) noexcept; + int clear() noexcept; static std::unique_ptr gen(); @@ -103,8 +108,9 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode public: ~SceneNode(); + int update() noexcept override; + int push(std::unique_ptr shape) noexcept; - int prepare() noexcept override; static std::unique_ptr gen() noexcept; @@ -128,6 +134,7 @@ public: int push(std::unique_ptr paint) noexcept; int clear() noexcept; + int update(PaintNode* node) noexcept; int draw(bool async = true) noexcept; int sync() noexcept; diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build new file mode 100644 index 00000000..2c3fe062 --- /dev/null +++ b/src/lib/gl_engine/meson.build @@ -0,0 +1,9 @@ +source_file = [ + 'tvgGlRaster.h', + 'tvgGlRaster.cpp', +] + +glraster_dep = declare_dependency( + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/lib/gl_engine/tvgGlRaster.cpp b/src/lib/gl_engine/tvgGlRaster.cpp new file mode 100644 index 00000000..eca8c47c --- /dev/null +++ b/src/lib/gl_engine/tvgGlRaster.cpp @@ -0,0 +1,61 @@ +/* + * 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_GL_RASTER_CPP_ +#define _TVG_GL_RASTER_CPP_ + +#include "tvgCommon.h" +#include "tvgGlRaster.h" + + +static GlRaster* pInst = nullptr; + +int GlRaster::prepare(ShapeNode *shape) +{ + cout << "GlRaster prepare!!" << endl; + + return 0; +} + + +int GlRaster::init() +{ + if (pInst) return -1; + pInst = new GlRaster(); + assert(pInst); + + return 0; +} + + +int GlRaster::term() +{ + if (!pInst) return -1; + cout << "GlRaster(" << pInst << ") destroyed!" << endl; + delete(pInst); + pInst = nullptr; + return 0; +} + + +GlRaster* GlRaster::inst() +{ + assert(pInst); + return pInst; +} + + +#endif /* _TVG_GL_RASTER_CPP_ */ diff --git a/src/lib/gl_engine/tvgGlRaster.h b/src/lib/gl_engine/tvgGlRaster.h new file mode 100644 index 00000000..10c44625 --- /dev/null +++ b/src/lib/gl_engine/tvgGlRaster.h @@ -0,0 +1,38 @@ +/* + * 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_GL_RASTER_H_ +#define _TVG_GL_RASTER_H_ + +namespace tvg +{ + +class GlRaster : public RasterMethod +{ +public: + int prepare(ShapeNode *shape) override; + static GlRaster* inst(); + static int init(); + static int term(); + +private: + GlRaster(){}; + ~GlRaster(){}; +}; + +} + +#endif /* _TVG_GL_RASTER_H_ */ diff --git a/src/lib/meson.build b/src/lib/meson.build index fb856bf0..b2243fe7 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -1,7 +1,11 @@ +subdir('sw_engine') +subdir('gl_engine') + source_file = [ 'tvgCommon.h', 'tvgEngine.cpp', 'tvgCanvasBase.h', + 'tvgShapePath.h', 'tvgSwCanvas.cpp', 'tvgGlCanvas.cpp', 'tvgSceneNode.cpp', @@ -12,3 +16,4 @@ src_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) + diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build new file mode 100644 index 00000000..0a29e22b --- /dev/null +++ b/src/lib/sw_engine/meson.build @@ -0,0 +1,9 @@ +source_file = [ + 'tvgSwRaster.h', + 'tvgSwRaster.cpp', +] + +swraster_dep = declare_dependency( + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp new file mode 100644 index 00000000..fa9a8452 --- /dev/null +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -0,0 +1,61 @@ +/* + * 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_SW_RASTER_CPP_ +#define _TVG_SW_RASTER_CPP_ + +#include "tvgCommon.h" +#include "tvgSwRaster.h" + + +static SwRaster* pInst = nullptr; + +int SwRaster::prepare(ShapeNode *shape) +{ + cout << "SWRaster prepare!!" << endl; + + return 0; +} + + +int SwRaster::init() +{ + if (pInst) return -1; + pInst = new SwRaster(); + assert(pInst); + + return 0; +} + + +int SwRaster::term() +{ + if (!pInst) return -1; + cout << "SwRaster(" << pInst << ") destroyed!" << endl; + delete(pInst); + pInst = nullptr; + return 0; +} + + +SwRaster* SwRaster::inst() +{ + assert(pInst); + return pInst; +} + + +#endif /* _TVG_SW_RASTER_CPP_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.h b/src/lib/sw_engine/tvgSwRaster.h new file mode 100644 index 00000000..e79f6280 --- /dev/null +++ b/src/lib/sw_engine/tvgSwRaster.h @@ -0,0 +1,38 @@ +/* + * 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_SW_RASTER_H_ +#define _TVG_SW_RASTER_H_ + +namespace tvg +{ + +class SwRaster : public RasterMethod +{ +public: + int prepare(ShapeNode *shape) override; + static SwRaster* inst(); + static int init(); + static int term(); + +private: + SwRaster(){}; + ~SwRaster(){}; +}; + +} + +#endif /* _TVG_SW_RASTER_H_ */ diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index 83607bf4..2a4632ec 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_CANVAS_CPP_ -#define _TVG_CANVAS_CPP_ +#ifndef _TVG_CANVAS_BASE_CPP_ +#define _TVG_CANVAS_BASE_CPP_ #include "tvgCommon.h" @@ -25,17 +25,59 @@ struct CanvasBase { + vector nodes; + RasterMethod* raster; - int push(unique_ptr paint) + CanvasBase(RasterMethod *pRaster):raster(pRaster) { + + } + + ~CanvasBase() + { + clear(); + } + + int reserve(size_t n) + { + nodes.reserve(n); + return 0; } int clear() { + for (auto node : nodes) { + delete(node); + } + nodes.clear(); + return 0; } + int push(unique_ptr paint) + { + PaintNode *node = paint.release(); + assert(node); + + nodes.push_back(node); + + int ret = node->update(); + if (ret) return ret; + + if (SceneNode *scene = dynamic_cast(node)) { + + //TODO: + + } else if (ShapeNode *shape = dynamic_cast(node)) { + return raster->prepare(shape); + } + + cout << "What type of PaintNode? = " << node << endl; + + return -1; + } + }; @@ -43,4 +85,4 @@ struct CanvasBase /* External Class Implementation */ /************************************************************************/ -#endif /* _TVG_CANVAS_CPP_ */ +#endif /* _TVG_CANVAS_BASE_CPP_ */ diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index f69af00f..0140cc8e 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -24,6 +24,24 @@ using namespace std; using namespace tvg; -using var = float; + +namespace tvg +{ + +struct Point +{ + float x, y; +}; + +class RasterMethod +{ +public: + virtual ~RasterMethod() {} + virtual int prepare(ShapeNode *shape) = 0; +}; + + +} + #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index 838f4ca8..5f8f533a 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -18,6 +18,8 @@ #define _TVG_ENGINE_CPP_ #include "tvgCommon.h" +#include "tvgSwRaster.h" +#include "tvgGlRaster.h" /************************************************************************/ /* Internal Class Implementation */ @@ -30,13 +32,23 @@ int Engine::init() noexcept { - return 0; + //TODO: Initialize Raster engines by configuration. + + int ret = 0; + ret |= SwRaster::init(); + ret |= GlRaster::init(); + + return ret; } int Engine::term() noexcept { - return 0; + int ret = 0; + ret |= SwRaster::term(); + ret |= GlRaster::term(); + + return ret; } #endif /* _TVG_ENGINE_CPP_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 573600eb..49828ac4 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -19,6 +19,7 @@ #include "tvgCommon.h" #include "tvgCanvasBase.h" +#include "tvgGlRaster.h" /************************************************************************/ /* Internal Class Implementation */ @@ -26,7 +27,7 @@ struct GlCanvas::Impl : CanvasBase { - //... + Impl() : CanvasBase(GlRaster::inst()) {} }; diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp index 8da41fca..68ddbc99 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgSceneNode.cpp @@ -57,7 +57,7 @@ int SceneNode :: push(unique_ptr shape) noexcept } -int SceneNode :: prepare() noexcept +int SceneNode :: update() noexcept { return 0; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 4fb4b107..59b40a77 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -18,6 +18,7 @@ #define _TVG_SHAPE_NODE_CPP_ #include "tvgCommon.h" +#include "tvgShapePath.h" /************************************************************************/ /* Internal Class Implementation */ @@ -33,33 +34,25 @@ struct ShapeStroke }; -struct ShapePath -{ -}; - - struct ShapeTransform { - var e[4*4]; -}; - - -struct ShapeChildren -{ - vector> v; + float e[4*4]; }; struct ShapeNode::Impl { - ShapeChildren *children = nullptr; ShapeTransform *transform = nullptr; ShapeFill *fill = nullptr; ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; - uint32_t color = 0; - uint32_t id = 0; + uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a + + Impl() : path(new ShapePath) + { + + } ~Impl() { @@ -67,9 +60,7 @@ struct ShapeNode::Impl if (stroke) delete(stroke); if (fill) delete(fill); if (transform) delete(transform); - if (children) delete(children); } - }; @@ -95,10 +86,69 @@ unique_ptr ShapeNode::gen() } -int ShapeNode :: prepare() noexcept +int ShapeNode :: update() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return 0; +} + + +int ShapeNode :: clear() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->path->clear(); +} + + +int ShapeNode ::appendCircle(float cx, float cy, float radius) noexcept { return 0; } +int ShapeNode :: appendRect(float x, float y, float w, float h, float radius) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + //clamping radius by minimum size + auto min = (w < h ? w : h) * 0.5f; + if (radius > min) radius = min; + + //rectangle + if (radius == 0) { + impl->path->reserve(5, 4); + impl->path->moveTo(x, y); + impl->path->lineTo(x + w, y); + impl->path->lineTo(x + w, y + h); + impl->path->lineTo(x, y + h); + impl->path->close(); + //circle + } else if (w == h && radius * 2 == w) { + appendCircle(x + (w * 0.5f), y + (h * 0.5f), radius); + } else { + //... + } + + return 0; +} + + +int ShapeNode :: fill(uint32_t r, uint32_t g, uint32_t b, uint32_t a) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->color[0] = r; + impl->color[1] = g; + impl->color[2] = b; + impl->color[3] = a; + + return 0; +} + #endif //_TVG_SHAPE_NODE_CPP_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h new file mode 100644 index 00000000..eb3849ee --- /dev/null +++ b/src/lib/tvgShapePath.h @@ -0,0 +1,149 @@ +/* + * 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_SHAPE_PATH_CPP_ +#define _TVG_SHAPE_PATH_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct ShapePath +{ + PathCommand* cmds = nullptr; + uint32_t cmdCnt = 0; + uint32_t reservedCmdCnt = 0; + + Point *pts = nullptr; + uint32_t ptsCnt = 0; + uint32_t reservedPtsCnt = 0; + + + ~ShapePath() + { + if (cmds) delete(cmds); + if (pts) delete(pts); + } + + int reserveCmd(uint32_t cmdCnt) + { + if (cmdCnt > reservedCmdCnt) { + reservedCmdCnt = cmdCnt; + cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); + assert(cmds); + } + return 0; + } + + int reservePts(uint32_t ptsCnt) + { + if (ptsCnt > reservedPtsCnt) { + reservedPtsCnt = ptsCnt; + pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); + assert(pts); + } + return 0; + } + + int reserve(uint32_t cmdCnt, uint32_t ptsCnt) + { + reserveCmd(cmdCnt); + reservePts(ptsCnt); + + return 0; + } + + int clear() + { + cmdCnt = 0; + ptsCnt = 0; + + return 0; + } + + int moveTo(float x, float y) + { + if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); + if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); + + cmds[cmdCnt++] = PathCommand::MoveTo; + pts[ptsCnt++] = {x, y}; + + return 0; + } + + int lineTo(float x, float y) + { + if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); + if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); + + cmds[cmdCnt++] = PathCommand::LineTo; + pts[ptsCnt++] = {x, y}; + + return 0; + } + + int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) + { + if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); + if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2); + + cmds[cmdCnt++] = PathCommand::CubicTo; + pts[ptsCnt++] = {cx1, cy1}; + pts[ptsCnt++] = {cx2, cy2}; + pts[ptsCnt++] = {x, y}; + + return 0; + } + + int close() + { + if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); + cmds[cmdCnt++] = PathCommand::Close; + + return 0; + } + + int bounds(float& x, float& y, float& w, float& h) + { + if (ptsCnt == 0) return -1; + + Point min = { pts[0].x, pts[0].y }; + Point max = { pts[0].x, pts[0].y }; + + for(uint32_t i = 1; i <= ptsCnt; ++i) { + if (pts[i].x < min.x) min.x = pts[i].x; + if (pts[i].y < min.y) min.y = pts[i].y; + if (pts[i].x > max.x) max.x = pts[i].x; + if (pts[i].y > max.y) max.y = pts[i].y; + } + + x = min.x; + y = min.y; + w = max.x - min.x; + h = max.y - min.y; + + return 0; + } +}; + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +#endif //_TVG_SHAPE_PATH_CPP_ diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 13e91f34..00338ef1 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -19,6 +19,8 @@ #include "tvgCommon.h" #include "tvgCanvasBase.h" +#include "tvgSwRaster.h" + /************************************************************************/ /* Internal Class Implementation */ @@ -29,6 +31,8 @@ struct SwCanvas::Impl : CanvasBase uint32_t* buffer = nullptr; int stride = 0; int height = 0; + + Impl() : CanvasBase(SwRaster::inst()) {} }; @@ -65,6 +69,7 @@ int SwCanvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); assert(impl); + return impl->push(move(paint)); } diff --git a/src/meson.build b/src/meson.build index d3fde4d1..495e4c79 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,7 +3,7 @@ compiler_flags = ['-DTIZENVG_BUILD'] subdir('lib') subdir('examples') -tizenvg_lib_dep = [ src_dep ] +tizenvg_lib_dep = [ src_dep, swraster_dep, glraster_dep ] tizenvg_lib = library( 'tizenvg', diff --git a/test/makefile b/test/makefile index 0f89da04..5fdc45c4 100644 --- a/test/makefile +++ b/test/makefile @@ -1,2 +1,2 @@ all: - gcc -o tvgDrawShape tvgDrawShape.cpp -g -lstdc++ `pkg-config --cflags --libs tizenvg` + gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs tizenvg` diff --git a/test/tvgComposition.cpp b/test/testComposition.cpp similarity index 100% rename from test/tvgComposition.cpp rename to test/testComposition.cpp diff --git a/test/tvgGradient.cpp b/test/testGradient.cpp similarity index 100% rename from test/tvgGradient.cpp rename to test/testGradient.cpp diff --git a/test/tvgMultipleShapes.cpp b/test/testMultipleShapes.cpp similarity index 100% rename from test/tvgMultipleShapes.cpp rename to test/testMultipleShapes.cpp diff --git a/test/tvgPath.cpp b/test/testPath.cpp similarity index 100% rename from test/tvgPath.cpp rename to test/testPath.cpp diff --git a/test/tvgScene.cpp b/test/testScene.cpp similarity index 100% rename from test/tvgScene.cpp rename to test/testScene.cpp diff --git a/test/tvgDrawShape.cpp b/test/testShape.cpp similarity index 85% rename from test/tvgDrawShape.cpp rename to test/testShape.cpp index 7aaba5be..64603aea 100644 --- a/test/tvgDrawShape.cpp +++ b/test/testShape.cpp @@ -17,8 +17,8 @@ int main(int argc, char **argv) //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); -// shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius -// shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius + shape1->fill(0, 255, 0, 255); //r, g, b, a /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/tvgStroke.cpp b/test/testStroke.cpp similarity index 100% rename from test/tvgStroke.cpp rename to test/testStroke.cpp diff --git a/test/tvgUpdate.cpp b/test/testUpdate.cpp similarity index 100% rename from test/tvgUpdate.cpp rename to test/testUpdate.cpp From 701b482131d9a6dbc58b08f9633419bb4ced7b0c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 3 Apr 2020 16:09:09 +0900 Subject: [PATCH 006/244] implement sw engine basic sequence. Change-Id: Ide27c9b191088109f95e03fcd1c80ad3ecc058cd --- inc/tizenvg.h | 23 ++++- src/lib/gl_engine/tvgGlRaster.cpp | 4 +- src/lib/gl_engine/tvgGlRaster.h | 2 +- src/lib/sw_engine/meson.build | 2 + src/lib/sw_engine/tvgSwCommon.h | 48 +++++++++ src/lib/sw_engine/tvgSwRaster.cpp | 20 +++- src/lib/sw_engine/tvgSwRaster.h | 7 +- src/lib/sw_engine/tvgSwShape.cpp | 159 ++++++++++++++++++++++++++++++ src/lib/tvgCanvasBase.h | 7 +- src/lib/tvgCommon.h | 9 +- src/lib/tvgGlCanvas.cpp | 14 +++ src/lib/tvgSceneNode.cpp | 3 +- src/lib/tvgShapeNode.cpp | 36 +++++-- src/lib/tvgSwCanvas.cpp | 14 +++ 14 files changed, 307 insertions(+), 41 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwCommon.h create mode 100644 src/lib/sw_engine/tvgSwShape.cpp diff --git a/inc/tizenvg.h b/inc/tizenvg.h index aeea75f2..c9abb03c 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -52,6 +52,14 @@ namespace tvg enum class TIZENVG_EXPORT PathCommand { Close, MoveTo, LineTo, CubicTo }; +class RasterMethod; + +struct Point +{ + float x; + float y; +}; + /** * @class PaintNode @@ -65,7 +73,7 @@ class TIZENVG_EXPORT PaintNode { public: virtual ~PaintNode() {} - virtual int update() = 0; + virtual int update(RasterMethod* engine) = 0; }; @@ -82,14 +90,16 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode public: ~ShapeNode(); - int update() noexcept override; + int update(RasterMethod* engine) noexcept override; int appendRect(float x, float y, float w, float h, float radius) noexcept; int appendCircle(float cx, float cy, float radius) noexcept; int fill(uint32_t r, uint32_t g, uint32_t b, uint32_t a) noexcept; int clear() noexcept; + int pathCommands(const PathCommand** cmds) noexcept; + int pathCoords(const Point** pts) noexcept; - static std::unique_ptr gen(); + static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(ShapeNode); }; @@ -108,7 +118,7 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode public: ~SceneNode(); - int update() noexcept override; + int update(RasterMethod* engine) noexcept override; int push(std::unique_ptr shape) noexcept; @@ -134,9 +144,10 @@ public: int push(std::unique_ptr paint) noexcept; int clear() noexcept; - int update(PaintNode* node) noexcept; + int update() noexcept; int draw(bool async = true) noexcept; int sync() noexcept; + RasterMethod* engine() noexcept; int target(uint32_t* buffer, size_t stride, size_t height) noexcept; @@ -163,8 +174,10 @@ public: int clear() noexcept; //TODO: Gl Specific methods. Need gl backend configuration methods as well. + int update() noexcept; int draw(bool async = true) noexcept { return 0; } int sync() noexcept { return 0; } + RasterMethod* engine() noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRaster.cpp b/src/lib/gl_engine/tvgGlRaster.cpp index eca8c47c..f99205b5 100644 --- a/src/lib/gl_engine/tvgGlRaster.cpp +++ b/src/lib/gl_engine/tvgGlRaster.cpp @@ -23,11 +23,11 @@ static GlRaster* pInst = nullptr; -int GlRaster::prepare(ShapeNode *shape) +void* GlRaster::prepare(ShapeNode* shape, void* data) { cout << "GlRaster prepare!!" << endl; - return 0; + return nullptr; } diff --git a/src/lib/gl_engine/tvgGlRaster.h b/src/lib/gl_engine/tvgGlRaster.h index 10c44625..f0db8bf7 100644 --- a/src/lib/gl_engine/tvgGlRaster.h +++ b/src/lib/gl_engine/tvgGlRaster.h @@ -23,7 +23,7 @@ namespace tvg class GlRaster : public RasterMethod { public: - int prepare(ShapeNode *shape) override; + void* prepare(ShapeNode* shape, void* data) override; static GlRaster* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index 0a29e22b..df72f386 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,6 +1,8 @@ source_file = [ + 'tvgSwCommon.h', 'tvgSwRaster.h', 'tvgSwRaster.cpp', + 'tvgSwShape.cpp', ] swraster_dep = declare_dependency( diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h new file mode 100644 index 00000000..e77c3fac --- /dev/null +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -0,0 +1,48 @@ +/* + * 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_SW_COMMON_H_ +#define _TVG_SW_COMMON_H_ + +#include "tvgCommon.h" + +using namespace tvg; +using SwPos = signed long; + +struct SwVector +{ + SwPos x; + SwPos y; +}; + +struct SwOutline +{ + short* cntrs; /* the contour end points */ + short cntrsCnt; /* number of contours in glyph */ + SwVector* pts; /* the outline's points */ + short ptsCnt; /* number of points in the glyph */ + char* tags; /* the points flags */ + int flags; /* outline masks */ +}; + +struct SwShape +{ + SwOutline outline; +}; + +bool shapeGenOutline(ShapeNode *shape, SwShape* sdata); + +#endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index fa9a8452..88f81b24 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -17,17 +17,27 @@ #ifndef _TVG_SW_RASTER_CPP_ #define _TVG_SW_RASTER_CPP_ -#include "tvgCommon.h" +#include "tvgSwCommon.h" #include "tvgSwRaster.h" +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ static SwRaster* pInst = nullptr; -int SwRaster::prepare(ShapeNode *shape) -{ - cout << "SWRaster prepare!!" << endl; - return 0; +void* SwRaster::prepare(ShapeNode *shape, void* data) +{ + SwShape *sdata = static_cast(data); + if (!sdata) { + sdata = static_cast(calloc(1, sizeof(SwShape))); + assert(sdata); + } + + bool closed = shapeGenOutline(shape, sdata); + + return sdata; } diff --git a/src/lib/sw_engine/tvgSwRaster.h b/src/lib/sw_engine/tvgSwRaster.h index e79f6280..e16837e3 100644 --- a/src/lib/sw_engine/tvgSwRaster.h +++ b/src/lib/sw_engine/tvgSwRaster.h @@ -17,13 +17,10 @@ #ifndef _TVG_SW_RASTER_H_ #define _TVG_SW_RASTER_H_ -namespace tvg -{ - class SwRaster : public RasterMethod { public: - int prepare(ShapeNode *shape) override; + void* prepare(ShapeNode* shape, void* data) override; static SwRaster* inst(); static int init(); static int term(); @@ -33,6 +30,4 @@ private: ~SwRaster(){}; }; -} - #endif /* _TVG_SW_RASTER_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp new file mode 100644 index 00000000..f9826e86 --- /dev/null +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -0,0 +1,159 @@ +/* + * 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_SW_SHAPE_H_ +#define _TVG_SW_SHAPE_H_ + +#include "tvgSwCommon.h" + +static void growOutlineContour(SwShape *sdata, size_t n) +{ + sdata->outline.cntrsCnt = n; + + if (n == 0) { + free(sdata->outline.cntrs); + sdata->outline.cntrs = nullptr; + return; + } + sdata->outline.cntrs = static_cast(realloc(sdata->outline.cntrs, n * sizeof(short))); + assert(sdata->outline.cntrs); +} + + +static void growOutlinePoint(SwShape *sdata, size_t n) +{ + sdata->outline.ptsCnt = n; + + if (n == 0) { + free(sdata->outline.pts); + sdata->outline.pts = nullptr; + free(sdata->outline.tags); + sdata->outline.tags = nullptr; + return; + } + + sdata->outline.pts = static_cast(realloc(sdata->outline.pts, n * sizeof(SwVector))); + assert(sdata->outline.pts); + sdata->outline.tags = static_cast(realloc(sdata->outline.tags, n * sizeof(char))); + assert(sdata->outline.tags); +} + + +static void outlineEnd(SwShape* sdata) +{ + //grow contour 1 +} + + +static void outlineMoveTo(SwShape* sdata, const Point* pt) +{ + //grow pts 1, + //grow contour 1 +} + + +static void outlineLineTo(SwShape* sdata, const Point* pt) +{ + //grow pts 1 +} + + +static void outlineCubicTo(SwShape* sdata, const Point* ctrl1, const Point* ctrl2, const Point* pt) +{ + //grow pts 3 +} + + +static void outlineClose(SwShape* sdata) +{ + //grow pts 1 +} + + +bool shapeGenOutline(ShapeNode *shape, SwShape* sdata) +{ + bool closed = false; + + const PathCommand* cmds = nullptr; + auto cmdCnt = shape->pathCommands(&cmds); + + const Point* pts = nullptr; + shape->pathCoords(&pts); + + //reservation + auto outlinePtsCnt = 0; + auto outlineCntrsCnt = 0; + + for (auto i = 0; i < cmdCnt; ++i) { + switch(*cmds) { + case PathCommand::Close: { + ++outlinePtsCnt; + break; + } + case PathCommand::MoveTo: { + ++outlineCntrsCnt; + ++outlinePtsCnt; + break; + } + case PathCommand::LineTo: { + ++outlinePtsCnt; + break; + } + case PathCommand::CubicTo: { + outlinePtsCnt += 3; + break; + } + } + } + + ++outlinePtsCnt; //for close + + growOutlinePoint(sdata, outlinePtsCnt); + growOutlineContour(sdata, outlineCntrsCnt); + + //Generate Outlines + while (cmdCnt-- > 0) { + switch(*cmds) { + case PathCommand::Close: { + outlineClose(sdata); + break; + } + case PathCommand::MoveTo: { + outlineMoveTo(sdata, pts); + ++pts; + break; + } + case PathCommand::LineTo: { + outlineLineTo(sdata, pts); + ++pts; + break; + } + case PathCommand::CubicTo: { + outlineCubicTo(sdata, pts, pts + 1, pts + 2); + pts += 3; + break; + } + } + ++cmds; + } + + outlineEnd(sdata); + + return closed; +} + + +#endif /* _TVG_SW_SHAPE_H_ */ diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index 2a4632ec..48fd7bd8 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -62,15 +62,10 @@ struct CanvasBase nodes.push_back(node); - int ret = node->update(); - if (ret) return ret; - if (SceneNode *scene = dynamic_cast(node)) { - //TODO: - } else if (ShapeNode *shape = dynamic_cast(node)) { - return raster->prepare(shape); + return shape->update(raster); } cout << "What type of PaintNode? = " << node << endl; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 0140cc8e..5d7f85c2 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -28,20 +28,13 @@ using namespace tvg; namespace tvg { -struct Point -{ - float x, y; -}; - class RasterMethod { public: virtual ~RasterMethod() {} - virtual int prepare(ShapeNode *shape) = 0; + virtual void* prepare(ShapeNode* shape, void* data) = 0; }; - } - #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 49828ac4..66f54488 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -69,4 +69,18 @@ int GlCanvas::clear() noexcept return impl->clear(); } + +int GlCanvas::update() noexcept +{ + return 0; +} + + +RasterMethod* GlCanvas::engine() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->raster; +} + #endif /* _TVG_GLCANVAS_CPP_ */ diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp index 68ddbc99..7c4bb589 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgSceneNode.cpp @@ -51,13 +51,14 @@ unique_ptr SceneNode::gen() noexcept return unique_ptr(new SceneNode); } + int SceneNode :: push(unique_ptr shape) noexcept { return 0; } -int SceneNode :: update() noexcept +int SceneNode :: update(RasterMethod* engine) noexcept { return 0; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 59b40a77..b3726f04 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -46,12 +46,11 @@ struct ShapeNode::Impl ShapeFill *fill = nullptr; ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; - uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a + void *edata = nullptr; //engine data Impl() : path(new ShapePath) { - } ~Impl() @@ -70,7 +69,6 @@ struct ShapeNode::Impl ShapeNode :: ShapeNode() : pImpl(make_unique()) { - } @@ -80,18 +78,20 @@ ShapeNode :: ~ShapeNode() } -unique_ptr ShapeNode::gen() +unique_ptr ShapeNode::gen() noexcept { return unique_ptr(new ShapeNode); } -int ShapeNode :: update() noexcept +int ShapeNode :: update(RasterMethod* engine) noexcept { auto impl = pImpl.get(); assert(impl); - return 0; + impl->edata = engine->prepare(this, impl->edata); + if (impl->edata) return 0; + return - 1; } @@ -104,7 +104,29 @@ int ShapeNode :: clear() noexcept } -int ShapeNode ::appendCircle(float cx, float cy, float radius) noexcept +int ShapeNode :: pathCommands(const PathCommand** cmds) noexcept +{ + auto impl = pImpl.get(); + assert(impl && cmds); + + *cmds = impl->path->cmds; + + return impl->path->cmdCnt; +} + + +int ShapeNode :: pathCoords(const Point** pts) noexcept +{ + auto impl = pImpl.get(); + assert(impl && pts); + + *pts = impl->path->pts; + + return impl->path->ptsCnt; +} + + +int ShapeNode :: appendCircle(float cx, float cy, float radius) noexcept { return 0; } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 00338ef1..82da4530 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -104,4 +104,18 @@ unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t heigh return canvas; } + +int SwCanvas::update() noexcept +{ + return 0; +} + + +RasterMethod* SwCanvas::engine() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->raster; +} + #endif /* _TVG_SWCANVAS_CPP_ */ From f9fcd5874471b0c3bcb4eeedbd7d9abd134e52b3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 4 Apr 2020 01:14:11 +0900 Subject: [PATCH 007/244] implement shape basics sw engine. Change-Id: I93788f40f7c4f59bcc9ab4dff9127bcb4e6c1466 --- inc/tizenvg.h | 11 +- src/lib/gl_engine/tvgGlRaster.cpp | 17 ++- src/lib/gl_engine/tvgGlRaster.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 30 +++-- src/lib/sw_engine/tvgSwRaster.cpp | 21 ++- src/lib/sw_engine/tvgSwRaster.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 204 +++++++++++++++++++++++------- src/lib/tvgCanvasBase.h | 8 +- src/lib/tvgCommon.h | 2 +- src/lib/tvgShapeNode.cpp | 22 +++- src/lib/tvgShapePath.h | 16 +-- 11 files changed, 249 insertions(+), 86 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c9abb03c..2c43a85c 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -91,13 +91,16 @@ public: ~ShapeNode(); int update(RasterMethod* engine) noexcept override; + int clear() noexcept; int appendRect(float x, float y, float w, float h, float radius) noexcept; int appendCircle(float cx, float cy, float radius) noexcept; - int fill(uint32_t r, uint32_t g, uint32_t b, uint32_t a) noexcept; - int clear() noexcept; - int pathCommands(const PathCommand** cmds) noexcept; - int pathCoords(const Point** pts) noexcept; + + int fill(size_t r, size_t g, size_t b, size_t a) noexcept; + + int pathCommands(const PathCommand** cmds) const noexcept; + int pathCoords(const Point** pts) const noexcept; + int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRaster.cpp b/src/lib/gl_engine/tvgGlRaster.cpp index f99205b5..c3bb4079 100644 --- a/src/lib/gl_engine/tvgGlRaster.cpp +++ b/src/lib/gl_engine/tvgGlRaster.cpp @@ -23,11 +23,22 @@ static GlRaster* pInst = nullptr; -void* GlRaster::prepare(ShapeNode* shape, void* data) +struct GlShape { - cout << "GlRaster prepare!!" << endl; + //TODO: +}; - return nullptr; + +void* GlRaster::prepare(const ShapeNode& shape, void* data) +{ + //prepare shape data + GlShape* sdata = static_cast(data); + if (!sdata) { + sdata = static_cast(calloc(1, sizeof(GlShape))); + assert(sdata); + } + + return sdata; } diff --git a/src/lib/gl_engine/tvgGlRaster.h b/src/lib/gl_engine/tvgGlRaster.h index f0db8bf7..d6da2fe7 100644 --- a/src/lib/gl_engine/tvgGlRaster.h +++ b/src/lib/gl_engine/tvgGlRaster.h @@ -23,7 +23,7 @@ namespace tvg class GlRaster : public RasterMethod { public: - void* prepare(ShapeNode* shape, void* data) override; + void* prepare(const ShapeNode& shape, void* data) override; static GlRaster* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index e77c3fac..a1531025 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -20,29 +20,31 @@ #include "tvgCommon.h" using namespace tvg; -using SwPos = signed long; -struct SwVector -{ - SwPos x; - SwPos y; -}; +constexpr auto SW_CURVE_TAG_ON = 1; +constexpr auto SW_CURVE_TAG_CUBIC = 2; struct SwOutline { - short* cntrs; /* the contour end points */ - short cntrsCnt; /* number of contours in glyph */ - SwVector* pts; /* the outline's points */ - short ptsCnt; /* number of points in the glyph */ - char* tags; /* the points flags */ - int flags; /* outline masks */ + size_t* cntrs; //the contour end points + size_t cntrsCnt; //number of contours in glyph + size_t reservedCntrsCnt; + Point* pts; //the outline's points + size_t ptsCnt; //number of points in the glyph + size_t reservedPtsCnt; + char* tags; //the points flags + size_t flags; //outline masks }; struct SwShape { - SwOutline outline; +// SwRleRaster raster; + SwOutline* outline; }; -bool shapeGenOutline(ShapeNode *shape, SwShape* sdata); +bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata); +void shapeDelOutline(const ShapeNode& shape, SwShape& sdata); +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata); +bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 88f81b24..a1afdda2 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -26,16 +26,31 @@ static SwRaster* pInst = nullptr; +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ -void* SwRaster::prepare(ShapeNode *shape, void* data) +void* SwRaster::prepare(const ShapeNode& shape, void* data) { - SwShape *sdata = static_cast(data); + //prepare shape data + SwShape* sdata = static_cast(data); if (!sdata) { sdata = static_cast(calloc(1, sizeof(SwShape))); assert(sdata); } - bool closed = shapeGenOutline(shape, sdata); + //invisible? + size_t alpha; + shape.fill(nullptr, nullptr, nullptr, &alpha); + if (alpha == 0) return sdata; + + if (!shapeGenOutline(shape, *sdata)) return sdata; + + //TODO: From below sequence starts threading? + if (!shapeGenRle(shape, *sdata)) return sdata; + if (!shapeUpdateBBox(shape, *sdata)) return sdata; + + shapeDelOutline(shape, *sdata); return sdata; } diff --git a/src/lib/sw_engine/tvgSwRaster.h b/src/lib/sw_engine/tvgSwRaster.h index e16837e3..07fc274e 100644 --- a/src/lib/sw_engine/tvgSwRaster.h +++ b/src/lib/sw_engine/tvgSwRaster.h @@ -20,7 +20,7 @@ class SwRaster : public RasterMethod { public: - void* prepare(ShapeNode* shape, void* data) override; + void* prepare(const ShapeNode& shape, void* data) override; static SwRaster* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index f9826e86..364ac3e9 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -19,86 +19,188 @@ #include "tvgSwCommon.h" -static void growOutlineContour(SwShape *sdata, size_t n) -{ - sdata->outline.cntrsCnt = n; +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ +static void growOutlineContour(SwOutline& outline, size_t n) +{ if (n == 0) { - free(sdata->outline.cntrs); - sdata->outline.cntrs = nullptr; + free(outline.cntrs); + outline.cntrs = nullptr; + outline.cntrsCnt = 0; + outline.reservedCntrsCnt = 0; return; } - sdata->outline.cntrs = static_cast(realloc(sdata->outline.cntrs, n * sizeof(short))); - assert(sdata->outline.cntrs); + if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; + + cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;; + outline.reservedCntrsCnt = n; + outline.cntrs = static_cast(realloc(outline.cntrs, n * sizeof(size_t))); + assert(outline.cntrs); } -static void growOutlinePoint(SwShape *sdata, size_t n) +static void growOutlinePoint(SwOutline& outline, size_t n) { - sdata->outline.ptsCnt = n; - if (n == 0) { - free(sdata->outline.pts); - sdata->outline.pts = nullptr; - free(sdata->outline.tags); - sdata->outline.tags = nullptr; + free(outline.pts); + outline.pts = nullptr; + free(outline.tags); + outline.tags = nullptr; + outline.reservedPtsCnt = 0; + outline.ptsCnt = 0; return; } - sdata->outline.pts = static_cast(realloc(sdata->outline.pts, n * sizeof(SwVector))); - assert(sdata->outline.pts); - sdata->outline.tags = static_cast(realloc(sdata->outline.tags, n * sizeof(char))); - assert(sdata->outline.tags); + if (outline.reservedPtsCnt >= outline.ptsCnt + n) return; + + cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl; + outline.reservedPtsCnt = n; + outline.pts = static_cast(realloc(outline.pts, n * sizeof(Point))); + assert(outline.pts); + outline.tags = static_cast(realloc(outline.tags, n * sizeof(char))); + assert(outline.tags); } -static void outlineEnd(SwShape* sdata) +static void outlineEnd(SwOutline& outline) { - //grow contour 1 + growOutlineContour(outline, 1); + if (outline.ptsCnt > 0) { + outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1; + ++outline.cntrs; + } } -static void outlineMoveTo(SwShape* sdata, const Point* pt) +static void outlineMoveTo(SwOutline& outline, const Point* pt) { - //grow pts 1, - //grow contour 1 + assert(pt); + + growOutlinePoint(outline, 1); + + outline.pts[outline.ptsCnt] = *pt; + outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + + if (outline.ptsCnt > 0) { + growOutlineContour(outline, 1); + outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1; + ++outline.cntrsCnt; + } + + ++outline.ptsCnt; } -static void outlineLineTo(SwShape* sdata, const Point* pt) +static void outlineLineTo(SwOutline& outline, const Point* pt) { - //grow pts 1 + assert(pt); + + growOutlinePoint(outline, 1); + + outline.pts[outline.ptsCnt] = *pt; + outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + + ++outline.ptsCnt; } -static void outlineCubicTo(SwShape* sdata, const Point* ctrl1, const Point* ctrl2, const Point* pt) +static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* pt) { - //grow pts 3 + assert(ctrl1 && ctrl2 && pt); + + growOutlinePoint(outline, 3); + + outline.pts[outline.ptsCnt] = *ctrl1; + outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; + ++outline.ptsCnt; + + outline.pts[outline.ptsCnt] = *ctrl2; + outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; + ++outline.ptsCnt; + + outline.pts[outline.ptsCnt] = *ctrl1; + outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + ++outline.ptsCnt; } -static void outlineClose(SwShape* sdata) +static bool outlineClose(SwOutline& outline) { - //grow pts 1 + size_t i = 0; + + if (outline.cntrsCnt > 0) { + i = outline.cntrs[outline.cntrsCnt - 1] + 1; + } else { + i = 0; //First Path + } + + //Make sure there is at least one point in the current path + if (outline.ptsCnt == i) return false; + + //Close the path + growOutlinePoint(outline, 1); + + outline.pts[outline.ptsCnt] = outline.pts[i]; + outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + ++outline.ptsCnt; + + return true; } -bool shapeGenOutline(ShapeNode *shape, SwShape* sdata) -{ - bool closed = false; +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +{ + //TODO: rle + + return true; +} + + +bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata) +{ + //TODO: + return true; +} + + +void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) +{ + if (!sdata.outline) return; + + SwOutline* outline = sdata.outline; + if (outline->cntrs) free(outline->cntrs); + if (outline->pts) free(outline->pts); + if (outline->tags) free(outline->tags); + free(outline); + + sdata.outline = nullptr; +} + + +bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) +{ const PathCommand* cmds = nullptr; - auto cmdCnt = shape->pathCommands(&cmds); + auto cmdCnt = shape.pathCommands(&cmds); const Point* pts = nullptr; - shape->pathCoords(&pts); + auto ptsCnt = shape.pathCoords(&pts); - //reservation + //No actual shape data + if (cmdCnt == 0 || ptsCnt == 0) return false; + + //smart reservation auto outlinePtsCnt = 0; auto outlineCntrsCnt = 0; +// auto closed = false; for (auto i = 0; i < cmdCnt; ++i) { - switch(*cmds) { + switch(*(cmds + i)) { case PathCommand::Close: { ++outlinePtsCnt; break; @@ -119,30 +221,40 @@ bool shapeGenOutline(ShapeNode *shape, SwShape* sdata) } } - ++outlinePtsCnt; //for close + ++outlinePtsCnt; //for close + ++outlineCntrsCnt; //for end - growOutlinePoint(sdata, outlinePtsCnt); - growOutlineContour(sdata, outlineCntrsCnt); + SwOutline* outline = sdata.outline; + + if (!outline) { + outline = static_cast(calloc(1, sizeof(SwOutline))); + assert(outline); + } else { + cout << "Outline was already allocated? How?" << endl; + } + + growOutlinePoint(*outline, outlinePtsCnt); + growOutlineContour(*outline, outlineCntrsCnt); //Generate Outlines while (cmdCnt-- > 0) { switch(*cmds) { case PathCommand::Close: { - outlineClose(sdata); + outlineClose(*outline); break; } case PathCommand::MoveTo: { - outlineMoveTo(sdata, pts); + outlineMoveTo(*outline, pts); ++pts; break; } case PathCommand::LineTo: { - outlineLineTo(sdata, pts); + outlineLineTo(*outline, pts); ++pts; break; } case PathCommand::CubicTo: { - outlineCubicTo(sdata, pts, pts + 1, pts + 2); + outlineCubicTo(*outline, pts, pts + 1, pts + 2); pts += 3; break; } @@ -150,9 +262,11 @@ bool shapeGenOutline(ShapeNode *shape, SwShape* sdata) ++cmds; } - outlineEnd(sdata); + outlineEnd(*outline); - return closed; + sdata.outline = outline; + + return true; } diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index 48fd7bd8..f200d29d 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -61,13 +61,17 @@ struct CanvasBase assert(node); nodes.push_back(node); - +#if 0 if (SceneNode *scene = dynamic_cast(node)) { } else if (ShapeNode *shape = dynamic_cast(node)) { return shape->update(raster); } - +#else + if (ShapeNode *shape = dynamic_cast(node)) { + return shape->update(raster); + } +#endif cout << "What type of PaintNode? = " << node << endl; return -1; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 5d7f85c2..dfd908f0 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -32,7 +32,7 @@ class RasterMethod { public: virtual ~RasterMethod() {} - virtual void* prepare(ShapeNode* shape, void* data) = 0; + virtual void* prepare(const ShapeNode& shape, void* data) = 0; }; } diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index b3726f04..26735c08 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -89,7 +89,7 @@ int ShapeNode :: update(RasterMethod* engine) noexcept auto impl = pImpl.get(); assert(impl); - impl->edata = engine->prepare(this, impl->edata); + impl->edata = engine->prepare(*this, impl->edata); if (impl->edata) return 0; return - 1; } @@ -104,7 +104,7 @@ int ShapeNode :: clear() noexcept } -int ShapeNode :: pathCommands(const PathCommand** cmds) noexcept +int ShapeNode :: pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); assert(impl && cmds); @@ -115,7 +115,7 @@ int ShapeNode :: pathCommands(const PathCommand** cmds) noexcept } -int ShapeNode :: pathCoords(const Point** pts) noexcept +int ShapeNode :: pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); assert(impl && pts); @@ -160,7 +160,7 @@ int ShapeNode :: appendRect(float x, float y, float w, float h, float radius) no } -int ShapeNode :: fill(uint32_t r, uint32_t g, uint32_t b, uint32_t a) noexcept +int ShapeNode :: fill(size_t r, size_t g, size_t b, size_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -173,4 +173,18 @@ int ShapeNode :: fill(uint32_t r, uint32_t g, uint32_t b, uint32_t a) noexcept return 0; } + +int ShapeNode :: fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (r) *r = impl->color[0]; + if (g) *g = impl->color[0]; + if (b) *b = impl->color[0]; + if (a) *a = impl->color[0]; + + return 0; +} + #endif //_TVG_SHAPE_NODE_CPP_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index eb3849ee..0d11cdf4 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -26,12 +26,12 @@ struct ShapePath { PathCommand* cmds = nullptr; - uint32_t cmdCnt = 0; - uint32_t reservedCmdCnt = 0; + size_t cmdCnt = 0; + size_t reservedCmdCnt = 0; Point *pts = nullptr; - uint32_t ptsCnt = 0; - uint32_t reservedPtsCnt = 0; + size_t ptsCnt = 0; + size_t reservedPtsCnt = 0; ~ShapePath() @@ -40,7 +40,7 @@ struct ShapePath if (pts) delete(pts); } - int reserveCmd(uint32_t cmdCnt) + int reserveCmd(size_t cmdCnt) { if (cmdCnt > reservedCmdCnt) { reservedCmdCnt = cmdCnt; @@ -50,7 +50,7 @@ struct ShapePath return 0; } - int reservePts(uint32_t ptsCnt) + int reservePts(size_t ptsCnt) { if (ptsCnt > reservedPtsCnt) { reservedPtsCnt = ptsCnt; @@ -60,7 +60,7 @@ struct ShapePath return 0; } - int reserve(uint32_t cmdCnt, uint32_t ptsCnt) + int reserve(size_t cmdCnt, size_t ptsCnt) { reserveCmd(cmdCnt); reservePts(ptsCnt); @@ -126,7 +126,7 @@ struct ShapePath Point min = { pts[0].x, pts[0].y }; Point max = { pts[0].x, pts[0].y }; - for(uint32_t i = 1; i <= ptsCnt; ++i) { + for(size_t i = 1; i <= ptsCnt; ++i) { if (pts[i].x < min.x) min.x = pts[i].x; if (pts[i].y < min.y) min.y = pts[i].y; if (pts[i].x > max.x) max.x = pts[i].x; From 70c9860d8f1190a978f54e730460b0eb907593e4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 11 Apr 2020 15:23:37 +0900 Subject: [PATCH 008/244] implement rle raster. Change-Id: Ie21dfbf0ff1aed43bfa750eeef3b8c033a986416 --- src/lib/gl_engine/tvgGlRaster.cpp | 2 +- src/lib/gl_engine/tvgGlRaster.h | 2 +- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwCommon.h | 47 ++++- src/lib/sw_engine/tvgSwRaster.cpp | 19 +- src/lib/sw_engine/tvgSwRaster.h | 2 +- src/lib/sw_engine/tvgSwRle.cpp | 336 ++++++++++++++++++++++++++++++ src/lib/sw_engine/tvgSwShape.cpp | 74 ++++++- src/lib/tvgCommon.h | 4 +- src/lib/tvgShapeNode.cpp | 8 +- 10 files changed, 461 insertions(+), 34 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwRle.cpp diff --git a/src/lib/gl_engine/tvgGlRaster.cpp b/src/lib/gl_engine/tvgGlRaster.cpp index c3bb4079..50ed465f 100644 --- a/src/lib/gl_engine/tvgGlRaster.cpp +++ b/src/lib/gl_engine/tvgGlRaster.cpp @@ -29,7 +29,7 @@ struct GlShape }; -void* GlRaster::prepare(const ShapeNode& shape, void* data) +void* GlRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRaster.h b/src/lib/gl_engine/tvgGlRaster.h index d6da2fe7..08f750c3 100644 --- a/src/lib/gl_engine/tvgGlRaster.h +++ b/src/lib/gl_engine/tvgGlRaster.h @@ -23,7 +23,7 @@ namespace tvg class GlRaster : public RasterMethod { public: - void* prepare(const ShapeNode& shape, void* data) override; + void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; static GlRaster* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index df72f386..4937d595 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -3,6 +3,7 @@ source_file = [ 'tvgSwRaster.h', 'tvgSwRaster.cpp', 'tvgSwShape.cpp', + 'tvgSwRle.cpp', ] swraster_dep = declare_dependency( diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index a1531025..2269cfb4 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -20,31 +20,58 @@ #include "tvgCommon.h" using namespace tvg; +using SwPoint = Point; +constexpr auto SW_CURVE_TAG_CONIC = 0; constexpr auto SW_CURVE_TAG_ON = 1; constexpr auto SW_CURVE_TAG_CUBIC = 2; struct SwOutline { - size_t* cntrs; //the contour end points - size_t cntrsCnt; //number of contours in glyph - size_t reservedCntrsCnt; - Point* pts; //the outline's points - size_t ptsCnt; //number of points in the glyph - size_t reservedPtsCnt; - char* tags; //the points flags - size_t flags; //outline masks + size_t* cntrs; //the contour end points + size_t cntrsCnt; //number of contours in glyph + size_t reservedCntrsCnt; + SwPoint* pts; //the outline's points + size_t ptsCnt; //number of points in the glyph + size_t reservedPtsCnt; + char* tags; //the points flags + size_t flags; //outline masks +}; + +struct SwSpan +{ + size_t x; + size_t y; + size_t len; + uint8_t coverage; +}; + +struct SwRleData +{ + size_t alloc; + size_t size; + SwSpan *spans; +}; + +struct SwBBox +{ + size_t xMin, yMin; + size_t xMax, yMax; }; struct SwShape { -// SwRleRaster raster; SwOutline* outline; + SwRleData rle; + SwBBox bbox; }; bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata); void shapeDelOutline(const ShapeNode& shape, SwShape& sdata); bool shapeGenRle(const ShapeNode& shape, SwShape& sdata); -bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata); +void shapeDelRle(const ShapeNode& shape, SwShape& sdata); +bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); + +bool rleRender(SwShape& sdata); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index a1afdda2..a7d2928b 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -26,11 +26,12 @@ static SwRaster* pInst = nullptr; + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -void* SwRaster::prepare(const ShapeNode& shape, void* data) +void* SwRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -39,18 +40,20 @@ void* SwRaster::prepare(const ShapeNode& shape, void* data) assert(sdata); } + if (flags == UpdateFlag::None) return nullptr; + //invisible? size_t alpha; shape.fill(nullptr, nullptr, nullptr, &alpha); if (alpha == 0) return sdata; - if (!shapeGenOutline(shape, *sdata)) return sdata; - - //TODO: From below sequence starts threading? - if (!shapeGenRle(shape, *sdata)) return sdata; - if (!shapeUpdateBBox(shape, *sdata)) return sdata; - - shapeDelOutline(shape, *sdata); + if (flags & UpdateFlag::Path) { + if (!shapeGenOutline(shape, *sdata)) return sdata; + //TODO: From below sequence starts threading? + if (!shapeTransformOutline(shape, *sdata)) return sdata; + if (!shapeGenRle(shape, *sdata)) return sdata; + shapeDelOutline(shape, *sdata); + } return sdata; } diff --git a/src/lib/sw_engine/tvgSwRaster.h b/src/lib/sw_engine/tvgSwRaster.h index 07fc274e..c690be37 100644 --- a/src/lib/sw_engine/tvgSwRaster.h +++ b/src/lib/sw_engine/tvgSwRaster.h @@ -20,7 +20,7 @@ class SwRaster : public RasterMethod { public: - void* prepare(const ShapeNode& shape, void* data) override; + void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; static SwRaster* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp new file mode 100644 index 00000000..d208c534 --- /dev/null +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -0,0 +1,336 @@ +/* + * 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_SW_RLE_H_ +#define _TVG_SW_RLE_H_ + +#include +#include "tvgSwCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ +constexpr auto MAX_SPANS = 256; + +using SwPtrDist = ptrdiff_t; +using TPos = long; +using TCoord = long; +using TArea = int; + +struct TBand +{ + TPos min, max; +}; + +struct TCell +{ + TPos x; + TCoord cover; + TArea area; + TCell *next; +}; + +struct RleWorker +{ + TCoord ex, ey; + TPos exMin, exMax; + TPos eyMin, eyMax; + TPos exCnt, eyCnt; + + TArea area; + TCoord cover; + + TCell* cells; + SwPtrDist maxCells; + SwPtrDist numCells; + + TPos x, y; + + Point bezStack[32 * 3 + 1]; + int levStack[32]; + + SwOutline* outline; + //SwBBox clipBox; + + SwSpan spans[MAX_SPANS]; + int spansCnt; + + //render_span + //render_span_data; + int ySpan; + + int bandSize; + int bandShoot; + + jmp_buf jmpBuf; + + void* buffer; + long bufferSize; + + TCell** yCells; + TPos yCnt; + + bool invalid; +}; + +static bool rleSweep(RleWorker& rw) +{ + //TODO: + return true; +} + +static bool moveTo(SwPoint& pt) +{ + printf("moveTo = %f %f\n", pt.x, pt.y); + return true; +} + + +static bool lineTo(SwPoint& pt) +{ + printf("lineTo = %f %f\n", pt.x, pt.y); + return true; +} + + +static bool cubicTo(SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& pt) +{ + printf("cubicTo = ctrl1(%f %f) ctrl2(%f %f) pt(%f %f)\n", ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, pt.x, pt.y); + return true; +} + + +static bool decomposeOutline(RleWorker& rw) +{ + printf("decomposOutline\n"); + auto outline = rw.outline; + assert(outline); + + auto first = 0; //index of first point in contour + + for (size_t n = 0; n < outline->cntrsCnt; ++n) { + auto last = outline->cntrs[n]; + if (last < 0) goto invalid_outline; + + auto limit = outline->pts + last; + assert(limit); + + auto pt = outline->pts + first; + auto tags = outline->tags + first; + + /* A contour cannot start with a cubic control point! */ + if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline; + + if (!moveTo(outline->pts[first])) return false; + + while (pt < limit) { + assert(++pt); + assert(++tags); + + //emit a single line_to + if (tags[0] == SW_CURVE_TAG_ON) { + if (!lineTo(*pt)) return false; + continue; + //tag cubic + } else { + if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC) + goto invalid_outline; + + pt += 2; + tags += 2; + + if (pt <= limit) { + if (!cubicTo(pt[-2], pt[-1], pt[0])) return false; + continue; + } + if (!cubicTo(pt[-2], pt[-1], outline->pts[first])) return false; + goto close; + } + } + + //Close the contour with a line segment? + //if (!lineTo(outline->pts[first])); + close: + first = last + 1; + } + + return true; + +invalid_outline: + cout << "Invalid Outline!" << endl; + return false; +} + + +static TCell* findCell(RleWorker& rw) +{ + //TODO: + return nullptr; +} + + +static void recordCell(RleWorker& rw) +{ + if (rw.area | rw.cover) { + TCell* cell = findCell(rw); + assert(cell); + cell->area += rw.area; + cell->cover += rw.cover; + } +} + + +static bool genRle(RleWorker& rw) +{ + bool ret = false; + + if (setjmp(rw.jmpBuf) == 0) { + ret = decomposeOutline(rw); + if (!rw.invalid) recordCell(rw); + } else { + cout << "Memory Overflow" << endl; + } + return ret; +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool rleRender(SwShape& sdata) +{ + constexpr auto RENDER_POOL_SIZE = 16384L; + constexpr auto BAND_SIZE = 40; + + auto outline = sdata.outline; + assert(outline); + + if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; + + assert(outline->cntrs && outline->pts); + assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); + + //TODO: We can preserve several static workers in advance + RleWorker rw; + TCell buffer[RENDER_POOL_SIZE / sizeof(TCell)]; + + //Init Cells + rw.buffer = buffer; + rw.bufferSize = sizeof(buffer); + rw.yCells = reinterpret_cast(buffer); + rw.cells = nullptr; + rw.maxCells = 0; + rw.numCells = 0; + rw.area = 0; + rw.cover = 0; + rw.invalid = true; + rw.exMin = sdata.bbox.xMin; + rw.exMax = sdata.bbox.xMax; + rw.eyMin = sdata.bbox.yMin; + rw.eyMax = sdata.bbox.yMax; + rw.exCnt = rw.exMax - rw.exMin; + rw.eyCnt = rw.eyMax - rw.eyMin; + rw.outline = outline; + rw.bandSize = rw.bufferSize / (sizeof(TCell) * 8); //bandSize: 64 + rw.bandShoot = 0; + //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%d), eyCnt(%d), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize); + + //Generate RLE + TBand bands[BAND_SIZE]; + TBand* band; + + /* set up vertical bands */ + auto bandCnt = (rw.eyMax - rw.eyMin) / rw.bandSize; + if (bandCnt == 0) bandCnt = 1; + else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE - 1; + + auto min = rw.eyMin; + auto yMax = rw.eyMax; + TPos max; +//printf("bandCnt(%d)\n", bandCnt); + + for (int n = 0; n < bandCnt; ++n, min = max) { + max = min + rw.bandSize; + if (n == bandCnt -1 || max > yMax) max = yMax; + + bands[0].min = min; + bands[0].max = max; + band = bands; + + while (band >= bands) { + rw.yCells = static_cast(rw.buffer); + rw.yCnt = band->max - band->min; + + auto cellStart = sizeof(TCell*) * rw.yCnt; + auto cellMod = cellStart % sizeof(TCell); + + if (cellMod > 0) cellStart += sizeof(TCell) - cellMod; + + auto cellEnd = rw.bufferSize; + cellEnd -= cellEnd % sizeof(TCell); +//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod); + + auto cellsMax = reinterpret_cast((char*)rw.buffer + cellEnd); + rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); + + if (rw.cells >= cellsMax) goto reduce_bands; + + rw.maxCells = cellsMax - rw.cells; + if (rw.maxCells < 2) goto reduce_bands; + + for (auto y = 0; y < rw.yCnt; ++y) + rw.yCells[y] = nullptr; + + rw.numCells = 0; + rw.invalid = true; + rw.eyMin = band->min; + rw.eyMax = band->max; + rw.eyCnt = band->max - band->min; + + if (!genRle(rw)) return -1; + + rleSweep(rw); + --band; + continue; + + reduce_bands: + /* render pool overflow: we will reduce the render band by half */ + auto bottom = band->min; + auto top = band->max; + auto middle = bottom + ((top - bottom) >> 1); + + /* This is too complex for a single scanline; there must + be some problems */ + if (middle == bottom) return -1; + + if (bottom - top >= rw.bandSize) ++rw.bandShoot; + + band[1].min = bottom; + band[1].max = middle; + band[0].min = middle; + band[0].max = top; + ++band; + } + } + + if (rw.bandShoot > 8 && rw.bandSize > 16) + rw.bandSize = rw.bandSize / 2; + + return true; +} + +#endif /* _TVG_SW_RLE_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 364ac3e9..746fa891 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -69,7 +69,7 @@ static void outlineEnd(SwOutline& outline) growOutlineContour(outline, 1); if (outline.ptsCnt > 0) { outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1; - ++outline.cntrs; + ++outline.cntrsCnt; } } @@ -150,25 +150,77 @@ static bool outlineClose(SwOutline& outline) } -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +static void initBBox(SwShape& sdata) { - //TODO: rle + sdata.bbox.xMin = sdata.bbox.yMin = 0; + sdata.bbox.xMax = sdata.bbox.yMax = 0; +} + + +static bool updateBBox(SwShape& sdata) +{ + auto outline = sdata.outline; + assert(outline); + + auto pt = outline->pts; + assert(pt); + + if (outline->ptsCnt <= 0) { + initBBox(sdata); + return false; + } + + auto xMin = pt->x; + auto xMax = pt->y; + auto yMin = pt->y; + auto yMax = pt->y; + + ++pt; + + for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) { + assert(pt); + if (xMin > pt->x) xMin = pt->x; + if (xMax < pt->y) xMax = pt->x; + if (yMin > pt->y) yMin = pt->y; + if (yMax < pt->y) yMax = pt->y; + } + sdata.bbox.xMin = round(xMin - 0.49); + sdata.bbox.xMax = round(xMax + 0.49); + sdata.bbox.yMin = round(yMin - 0.49); + sdata.bbox.yMax = round(yMax + 0.49); + + if (xMax - xMin < 1 || yMax - yMin < 1) return false; return true; } -bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata) +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) { //TODO: return true; } +void shapeDelRle(const ShapeNode& shape, SwShape& sdata) +{ + if (sdata.rle.spans) free(sdata.rle.spans); + sdata.rle.spans = nullptr; +} + + +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +{ + shapeDelRle(shape, sdata); + if (!updateBBox(sdata)) return false; + return rleRender(sdata); +} + + void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) { if (!sdata.outline) return; @@ -185,6 +237,8 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) { + initBBox(sdata); + const PathCommand* cmds = nullptr; auto cmdCnt = shape.pathCommands(&cmds); @@ -233,6 +287,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) cout << "Outline was already allocated? How?" << endl; } + //TODO: Probabry we can copy pts from shape directly. growOutlinePoint(*outline, outlinePtsCnt); growOutlineContour(*outline, outlineCntrsCnt); @@ -264,6 +319,9 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) outlineEnd(*outline); + //FIXME: + //outline->flags = SwOutline::FillRule::Winding; + sdata.outline = outline; return true; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index dfd908f0..e9dc2490 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "tizenvg.h" using namespace std; @@ -31,8 +32,9 @@ namespace tvg class RasterMethod { public: + enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RasterMethod() {} - virtual void* prepare(const ShapeNode& shape, void* data) = 0; + virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; }; } diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 26735c08..81d97dd5 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -89,7 +89,7 @@ int ShapeNode :: update(RasterMethod* engine) noexcept auto impl = pImpl.get(); assert(impl); - impl->edata = engine->prepare(*this, impl->edata); + impl->edata = engine->prepare(*this, impl->edata, RasterMethod::UpdateFlag::All); if (impl->edata) return 0; return - 1; } @@ -180,9 +180,9 @@ int ShapeNode :: fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept assert(impl); if (r) *r = impl->color[0]; - if (g) *g = impl->color[0]; - if (b) *b = impl->color[0]; - if (a) *a = impl->color[0]; + if (g) *g = impl->color[1]; + if (b) *b = impl->color[2]; + if (a) *a = impl->color[3]; return 0; } From 2a396175274f3c7d0ae6648bf224c33efd5741ca Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 15 Apr 2020 02:11:18 +0900 Subject: [PATCH 009/244] implement rle path parts. Change-Id: I7200d80320404d6e7fb722042b8f330961bee76d --- src/lib/sw_engine/tvgSwCommon.h | 29 +- src/lib/sw_engine/tvgSwRle.cpp | 448 ++++++++++++++++++++++++------- src/lib/sw_engine/tvgSwShape.cpp | 46 ++-- test/testShape.cpp | 2 +- 4 files changed, 399 insertions(+), 126 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 2269cfb4..576a0b83 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -20,12 +20,33 @@ #include "tvgCommon.h" using namespace tvg; -using SwPoint = Point; -constexpr auto SW_CURVE_TAG_CONIC = 0; constexpr auto SW_CURVE_TAG_ON = 1; constexpr auto SW_CURVE_TAG_CUBIC = 2; +using SwCoord = signed long; + +struct SwPoint +{ + SwCoord x, y; + + SwPoint operator+(const SwPoint& rhs) const { + return {x + rhs.x, y + rhs.y}; + } + + SwPoint operator-(const SwPoint& rhs) const { + return {x - rhs.x, y - rhs.y}; + } + + bool operator==(const SwPoint& rhs ) const { + return (x == rhs.x && y == rhs.y); + } + + bool operator!=(const SwPoint& rhs) const { + return (x != rhs.x || y != rhs.y); + } +}; + struct SwOutline { size_t* cntrs; //the contour end points @@ -55,8 +76,8 @@ struct SwRleData struct SwBBox { - size_t xMin, yMin; - size_t xMax, yMax; + SwPoint min; + SwPoint max; }; struct SwShape diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index d208c534..f8292c61 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -18,58 +18,57 @@ #define _TVG_SW_RLE_H_ #include +#include #include "tvgSwCommon.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ + constexpr auto MAX_SPANS = 256; +constexpr auto PIXEL_BITS = 8; //must be at least 6 bits! +constexpr auto ONE_PIXEL = (1L << PIXEL_BITS); -using SwPtrDist = ptrdiff_t; -using TPos = long; -using TCoord = long; -using TArea = int; -struct TBand +using Area = long; + +struct Band { - TPos min, max; + SwCoord min, max; }; -struct TCell +struct Cell { - TPos x; - TCoord cover; - TArea area; - TCell *next; + SwCoord x; + SwCoord cover; + Area area; + Cell *next; }; struct RleWorker { - TCoord ex, ey; - TPos exMin, exMax; - TPos eyMin, eyMax; - TPos exCnt, eyCnt; + SwPoint cellPos; + SwPoint cellMin; + SwPoint cellMax; + SwCoord cellXCnt; + SwCoord cellYCnt; - TArea area; - TCoord cover; + Area area; + SwCoord cover; - TCell* cells; - SwPtrDist maxCells; - SwPtrDist numCells; + Cell* cells; + ptrdiff_t maxCells; + ptrdiff_t cellsCnt; - TPos x, y; + SwPoint pos; - Point bezStack[32 * 3 + 1]; - int levStack[32]; + SwPoint bezStack[32 * 3 + 1]; + int levStack[32]; SwOutline* outline; - //SwBBox clipBox; SwSpan spans[MAX_SPANS]; int spansCnt; - - //render_span - //render_span_data; int ySpan; int bandSize; @@ -80,42 +79,311 @@ struct RleWorker void* buffer; long bufferSize; - TCell** yCells; - TPos yCnt; + Cell** yCells; + SwCoord yCnt; bool invalid; }; -static bool rleSweep(RleWorker& rw) + +static inline SwPoint UPSCALE(const SwPoint& pt) +{ + return {pt.x << (PIXEL_BITS - 6), pt.y << (PIXEL_BITS - 6)}; +} + + +static inline SwPoint DOWNSCALE(const SwPoint& pt) +{ + return {pt.x >> (PIXEL_BITS - 6), pt.y >> (PIXEL_BITS - 6)}; +} + + +static inline SwPoint TRUNC(const SwPoint& pt) +{ + return { pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS }; +} + + +static inline SwPoint SUBPIXELS(const SwPoint& pt) +{ + return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS }; +} + + +static inline SwCoord SUBPIXELS(const SwCoord x) +{ + return (x << PIXEL_BITS); +} + + +static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) { //TODO: - return true; } -static bool moveTo(SwPoint& pt) + +static void genSpan(RleWorker& rw) +{ + //TODO: +} + + +static void sweep(RleWorker& rw) +{ + if (rw.cellsCnt == 0) return; + + rw.spansCnt = 0; + + for (int y = 0; y < rw.yCnt; ++y) { + + auto cover = 0; + auto x = 0; + auto cell = rw.yCells[y]; + + while (cell) { + + horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); + cover += cell->cover; + auto area = cover * (ONE_PIXEL * 2) - cell->area; + + if (area != 0 && cell->x >= 0) + horizLine(rw, cell->x, y, area, 1); + + x = cell->x + 1; + cell = cell->next; + } + + if (cover != 0) + horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); + } + + if (rw.spansCnt > 0) genSpan(rw); +} + + +static Cell* findCell(RleWorker& rw) +{ + auto x = rw.cellPos.x; + if (x > rw.cellXCnt) x = rw.cellXCnt; + + auto pcell = &rw.yCells[rw.cellPos.y]; + assert(pcell); + + while(true) { + Cell* cell = *pcell; + if (!cell || cell->x > x) break; + if (cell->x == x) return cell; + pcell = &cell->next; + } + + if (rw.cellsCnt >= rw.maxCells) longjmp(rw.jmpBuf, 1); + + auto cell = rw.cells + rw.cellsCnt++; + assert(cell); + cell->x = x; + cell->area = 0; + cell->cover = 0; + cell->next = *pcell; + *pcell = cell; + + return cell; +} + + +static void recordCell(RleWorker& rw) +{ + if (rw.area | rw.cover) { + auto cell = findCell(rw); + assert(cell); + cell->area += rw.area; + cell->cover += rw.cover; + } +} + +static void setCell(RleWorker& rw, SwPoint pos) +{ + /* Move the cell pointer to a new position. We set the `invalid' */ + /* flag to indicate that the cell isn't part of those we're interested */ + /* in during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ + + /* All cells that are on the left of the clipping region go to the + min_ex - 1 horizontal position. */ + pos.y -= rw.cellMin.y; + + if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; + pos.x -= rw.cellMin.x; + if (pos.x < 0) pos.x = -1; + + //Are we moving to a different cell? + if (pos != rw.cellPos) { + if (!rw.invalid) recordCell(rw); + } + + rw.area = 0; + rw.cover = 0; + rw.cellPos = pos; + rw.invalid = ((unsigned)pos.y >= (unsigned)rw.cellYCnt || pos.x >= rw.cellXCnt); +} + + +static void startCell(RleWorker& rw, SwPoint pos) +{ + if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; + if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x; + + rw.area = 0; + rw.cover = 0; + rw.cellPos = pos - rw.cellMin; + rw.invalid = false; + + setCell(rw, pos); +} + + +static void moveTo(RleWorker& rw, const SwPoint& to) +{ + //record current cell, if any */ + if (!rw.invalid) recordCell(rw); + + //start to a new position + startCell(rw, TRUNC(to)); + + rw.pos = to; +} + + +static void lineTo(RleWorker& rw, const SwPoint& to) +{ +#define SW_UDIV(a, b) \ + static_cast(((unsigned long)(a) * (unsigned long)(b)) >> \ + (sizeof(long) * CHAR_BIT - PIXEL_BITS)) + + auto e1 = TRUNC(rw.pos); + auto e2 = TRUNC(to); + + //vertical clipping + if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || + (e1.y < rw.cellMin.y && e2.y >= rw.cellMin.y)) { + rw.pos = to; + return; + } + + auto diff = to - rw.pos; + auto f1 = rw.pos - SUBPIXELS(e1); + SwPoint f2; + + //inside one cell + if (e1 == e2) { + ; + //any horizontal line + } else if (diff.y == 0) { + e1.x = e2.x; + setCell(rw, e1); + } else if (diff.x == 0) { + //vertical line up + if (diff.y > 0) { + do { + f2.y = ONE_PIXEL; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * f1.x * 2; + f1.y = 0; + ++e1.y; + setCell(rw, e1); + } while(e1.y != e2.y); + //vertical line down + } else { + do { + f2.y = 0; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * f1.x * 2; + f1.y = ONE_PIXEL; + --e1.y; + setCell(rw, e1); + } while(e1.y != e2.y); + } + //any other line + } else { + Area prod = diff.x * f1.y - diff.y * f1.x; + + /* These macros speed up repetitive divisions by replacing them + with multiplications and right shifts. */ + auto dx_r = (ULONG_MAX >> PIXEL_BITS) / (diff.x); + auto dy_r = (ULONG_MAX >> PIXEL_BITS) / (diff.y); + + /* The fundamental value `prod' determines which side and the */ + /* exact coordinate where the line exits current cell. It is */ + /* also easily updated when moving from one cell to the next. */ + do { + auto px = diff.x * ONE_PIXEL; + auto py = diff.y * ONE_PIXEL; + + //left + if (prod <= 0 && prod - px) { + f2 = {0, SW_UDIV(-prod, -dx_r)}; + prod -= py; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * (f1.x + f2.x); + f1 = {ONE_PIXEL, f2.y}; + --e1.x; + //up + } else if (prod - px <= 0 && prod - px + py > 0) { + prod -= px; + f2 = {SW_UDIV(-prod, dy_r), ONE_PIXEL}; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * (f1.x + f2.x); + f1 = {f2.x, 0}; + ++e1.y; + //right + } else if (prod - px + py <= 0 && prod + py >= 0) { + prod += py; + f2 = {ONE_PIXEL, SW_UDIV(prod, dx_r)}; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * (f1.x + f2.x); + f1 = {0, f2.y}; + ++e1.x; + //down + } else { + f2 = {SW_UDIV(prod, -dy_r), 0}; + prod += px; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * (f1.x + f2.x); + f1 = {f2.x, ONE_PIXEL}; + --e1.y; + } + + setCell(rw, e1); + + } while(e1 != e2); + } + + f2 = {to.x - SUBPIXELS(e2.x), to.y - SUBPIXELS(e2.y)}; + rw.cover += (f2.y - f1.y); + rw.area += (f2.y - f1.y) * (f1.x + f2.x); + rw.pos = to; +} + + +static bool renderCubic(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) { - printf("moveTo = %f %f\n", pt.x, pt.y); return true; } -static bool lineTo(SwPoint& pt) +static bool cubicTo(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) { - printf("lineTo = %f %f\n", pt.x, pt.y); - return true; -} - - -static bool cubicTo(SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& pt) -{ - printf("cubicTo = ctrl1(%f %f) ctrl2(%f %f) pt(%f %f)\n", ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, pt.x, pt.y); - return true; + return renderCubic(rw, ctrl1, ctrl2, to); } static bool decomposeOutline(RleWorker& rw) { - printf("decomposOutline\n"); + // printf("decomposOutline\n"); auto outline = rw.outline; assert(outline); @@ -134,7 +402,7 @@ static bool decomposeOutline(RleWorker& rw) /* A contour cannot start with a cubic control point! */ if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline; - if (!moveTo(outline->pts[first])) return false; + moveTo(rw, UPSCALE(outline->pts[first])); while (pt < limit) { assert(++pt); @@ -142,8 +410,7 @@ static bool decomposeOutline(RleWorker& rw) //emit a single line_to if (tags[0] == SW_CURVE_TAG_ON) { - if (!lineTo(*pt)) return false; - continue; + lineTo(rw, UPSCALE(*pt)); //tag cubic } else { if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC) @@ -153,16 +420,16 @@ static bool decomposeOutline(RleWorker& rw) tags += 2; if (pt <= limit) { - if (!cubicTo(pt[-2], pt[-1], pt[0])) return false; + if (!cubicTo(rw, pt[-2], pt[-1], pt[0])) return false; continue; } - if (!cubicTo(pt[-2], pt[-1], outline->pts[first])) return false; + if (!cubicTo(rw, pt[-2], pt[-1], outline->pts[first])) return false; goto close; } } //Close the contour with a line segment? - //if (!lineTo(outline->pts[first])); + //if (!lineTo(rw, outline->pts[first])); close: first = last + 1; } @@ -175,24 +442,6 @@ invalid_outline: } -static TCell* findCell(RleWorker& rw) -{ - //TODO: - return nullptr; -} - - -static void recordCell(RleWorker& rw) -{ - if (rw.area | rw.cover) { - TCell* cell = findCell(rw); - assert(cell); - cell->area += rw.area; - cell->cover += rw.cover; - } -} - - static bool genRle(RleWorker& rw) { bool ret = false; @@ -214,7 +463,7 @@ static bool genRle(RleWorker& rw) bool rleRender(SwShape& sdata) { constexpr auto RENDER_POOL_SIZE = 16384L; - constexpr auto BAND_SIZE = 40; + constexpr auto BAND_SIZE = 39; auto outline = sdata.outline; assert(outline); @@ -226,42 +475,39 @@ bool rleRender(SwShape& sdata) //TODO: We can preserve several static workers in advance RleWorker rw; - TCell buffer[RENDER_POOL_SIZE / sizeof(TCell)]; + Cell buffer[RENDER_POOL_SIZE / sizeof(Cell)]; //Init Cells rw.buffer = buffer; rw.bufferSize = sizeof(buffer); - rw.yCells = reinterpret_cast(buffer); + rw.yCells = reinterpret_cast(buffer); rw.cells = nullptr; rw.maxCells = 0; - rw.numCells = 0; + rw.cellsCnt = 0; rw.area = 0; rw.cover = 0; rw.invalid = true; - rw.exMin = sdata.bbox.xMin; - rw.exMax = sdata.bbox.xMax; - rw.eyMin = sdata.bbox.yMin; - rw.eyMax = sdata.bbox.yMax; - rw.exCnt = rw.exMax - rw.exMin; - rw.eyCnt = rw.eyMax - rw.eyMin; + rw.cellMin = sdata.bbox.min; + rw.cellMax = sdata.bbox.max; + rw.cellXCnt = rw.cellMax.x - rw.cellMin.x; + rw.cellYCnt = rw.cellMax.y - rw.cellMin.y; rw.outline = outline; - rw.bandSize = rw.bufferSize / (sizeof(TCell) * 8); //bandSize: 64 + rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; - //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%d), eyCnt(%d), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize); + //printf("bufferSize = %d, bbox(%f %f %f %f), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize); //Generate RLE - TBand bands[BAND_SIZE]; - TBand* band; + Band bands[BAND_SIZE]; + Band* band; /* set up vertical bands */ - auto bandCnt = (rw.eyMax - rw.eyMin) / rw.bandSize; + auto bandCnt = static_cast((rw.cellMax.y - rw.cellMin.y) / rw.bandSize); if (bandCnt == 0) bandCnt = 1; - else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE - 1; + else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE; - auto min = rw.eyMin; - auto yMax = rw.eyMax; - TPos max; -//printf("bandCnt(%d)\n", bandCnt); + auto min = rw.cellMin.y; + auto yMax = rw.cellMax.y; + SwCoord max; for (int n = 0; n < bandCnt; ++n, min = max) { max = min + rw.bandSize; @@ -272,20 +518,20 @@ bool rleRender(SwShape& sdata) band = bands; while (band >= bands) { - rw.yCells = static_cast(rw.buffer); + rw.yCells = static_cast(rw.buffer); rw.yCnt = band->max - band->min; - auto cellStart = sizeof(TCell*) * rw.yCnt; - auto cellMod = cellStart % sizeof(TCell); + auto cellStart = sizeof(Cell*) * (int)rw.yCnt; + auto cellMod = cellStart % sizeof(Cell); - if (cellMod > 0) cellStart += sizeof(TCell) - cellMod; + if (cellMod > 0) cellStart += sizeof(Cell) - cellMod; auto cellEnd = rw.bufferSize; - cellEnd -= cellEnd % sizeof(TCell); + cellEnd -= cellEnd % sizeof(Cell); //printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod); - auto cellsMax = reinterpret_cast((char*)rw.buffer + cellEnd); - rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); + auto cellsMax = reinterpret_cast((char*)rw.buffer + cellEnd); + rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); if (rw.cells >= cellsMax) goto reduce_bands; @@ -295,15 +541,15 @@ bool rleRender(SwShape& sdata) for (auto y = 0; y < rw.yCnt; ++y) rw.yCells[y] = nullptr; - rw.numCells = 0; + rw.cellsCnt = 0; rw.invalid = true; - rw.eyMin = band->min; - rw.eyMax = band->max; - rw.eyCnt = band->max - band->min; + rw.cellMin.y = band->min; + rw.cellMax.y = band->max; + rw.cellYCnt = band->max - band->min; if (!genRle(rw)) return -1; - rleSweep(rw); + sweep(rw); --band; continue; @@ -328,7 +574,7 @@ bool rleRender(SwShape& sdata) } if (rw.bandShoot > 8 && rw.bandSize > 16) - rw.bandSize = rw.bandSize / 2; + rw.bandSize = (rw.bandSize >> 1); return true; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 746fa891..0f2a6fa4 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -23,6 +23,12 @@ /* Internal Class Implementation */ /************************************************************************/ +static inline SwPoint TO_SWPOINT(const Point* pt) +{ + return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; +} + + static void growOutlineContour(SwOutline& outline, size_t n) { if (n == 0) { @@ -57,7 +63,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n) cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl; outline.reservedPtsCnt = n; - outline.pts = static_cast(realloc(outline.pts, n * sizeof(Point))); + outline.pts = static_cast(realloc(outline.pts, n * sizeof(SwPoint))); assert(outline.pts); outline.tags = static_cast(realloc(outline.tags, n * sizeof(char))); assert(outline.tags); @@ -74,13 +80,13 @@ static void outlineEnd(SwOutline& outline) } -static void outlineMoveTo(SwOutline& outline, const Point* pt) +static void outlineMoveTo(SwOutline& outline, const Point* to) { - assert(pt); + assert(to); growOutlinePoint(outline, 1); - outline.pts[outline.ptsCnt] = *pt; + outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; if (outline.ptsCnt > 0) { @@ -93,34 +99,34 @@ static void outlineMoveTo(SwOutline& outline, const Point* pt) } -static void outlineLineTo(SwOutline& outline, const Point* pt) +static void outlineLineTo(SwOutline& outline, const Point* to) { - assert(pt); + assert(to); growOutlinePoint(outline, 1); - outline.pts[outline.ptsCnt] = *pt; + outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; ++outline.ptsCnt; } -static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* pt) +static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to) { - assert(ctrl1 && ctrl2 && pt); + assert(ctrl1 && ctrl2 && to); growOutlinePoint(outline, 3); - outline.pts[outline.ptsCnt] = *ctrl1; + outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; ++outline.ptsCnt; - outline.pts[outline.ptsCnt] = *ctrl2; + outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; ++outline.ptsCnt; - outline.pts[outline.ptsCnt] = *ctrl1; + outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; ++outline.ptsCnt; } @@ -152,8 +158,8 @@ static bool outlineClose(SwOutline& outline) static void initBBox(SwShape& sdata) { - sdata.bbox.xMin = sdata.bbox.yMin = 0; - sdata.bbox.xMax = sdata.bbox.yMax = 0; + sdata.bbox.min.x = sdata.bbox.min.y = 0; + sdata.bbox.max.x = sdata.bbox.max.y = 0; } @@ -171,7 +177,7 @@ static bool updateBBox(SwShape& sdata) } auto xMin = pt->x; - auto xMax = pt->y; + auto xMax = pt->x; auto yMin = pt->y; auto yMax = pt->y; @@ -180,14 +186,14 @@ static bool updateBBox(SwShape& sdata) for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) { assert(pt); if (xMin > pt->x) xMin = pt->x; - if (xMax < pt->y) xMax = pt->x; + if (xMax < pt->x) xMax = pt->x; if (yMin > pt->y) yMin = pt->y; if (yMax < pt->y) yMax = pt->y; } - sdata.bbox.xMin = round(xMin - 0.49); - sdata.bbox.xMax = round(xMax + 0.49); - sdata.bbox.yMin = round(yMin - 0.49); - sdata.bbox.yMax = round(yMax + 0.49); + sdata.bbox.min.x = xMin >> 6; + sdata.bbox.max.x = (xMax + 63) >> 6; + sdata.bbox.min.y = yMin >> 6; + sdata.bbox.max.y = (yMax + 63) >> 6; if (xMax - xMin < 1 || yMax - yMin < 1) return false; diff --git a/test/testShape.cpp b/test/testShape.cpp index 64603aea..d1da21e7 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -18,7 +18,7 @@ int main(int argc, char **argv) //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius - shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->fill(0, 255, 0, 255); //r, g, b, a /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare From de242b018b4003bd90790b86ed780e5f82a062b2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 18 Apr 2020 12:43:30 +0900 Subject: [PATCH 010/244] replace backend class names. SwRaster to SwEngine GlRaster to GlEngine Change-Id: I3cf70e168b78c64754807a62c221e13c11b95c35 --- src/lib/gl_engine/meson.build | 4 ++-- .../{tvgGlRaster.cpp => tvgGlEngine.cpp} | 22 +++++++++---------- .../{tvgGlRaster.h => tvgGlEngine.h} | 14 ++++++------ src/lib/sw_engine/meson.build | 4 ++-- .../{tvgSwRaster.cpp => tvgSwEngine.cpp} | 22 +++++++++---------- .../{tvgSwRaster.h => tvgSwEngine.h} | 14 ++++++------ src/lib/tvgEngine.cpp | 12 +++++----- src/lib/tvgGlCanvas.cpp | 4 ++-- src/lib/tvgSwCanvas.cpp | 4 ++-- 9 files changed, 50 insertions(+), 50 deletions(-) rename src/lib/gl_engine/{tvgGlRaster.cpp => tvgGlEngine.cpp} (75%) rename src/lib/gl_engine/{tvgGlRaster.h => tvgGlEngine.h} (81%) rename src/lib/sw_engine/{tvgSwRaster.cpp => tvgSwEngine.cpp} (84%) rename src/lib/sw_engine/{tvgSwRaster.h => tvgSwEngine.h} (81%) diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 2c3fe062..117149a1 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -1,6 +1,6 @@ source_file = [ - 'tvgGlRaster.h', - 'tvgGlRaster.cpp', + 'tvgGlEngine.h', + 'tvgGlEngine.cpp', ] glraster_dep = declare_dependency( diff --git a/src/lib/gl_engine/tvgGlRaster.cpp b/src/lib/gl_engine/tvgGlEngine.cpp similarity index 75% rename from src/lib/gl_engine/tvgGlRaster.cpp rename to src/lib/gl_engine/tvgGlEngine.cpp index 50ed465f..9280e347 100644 --- a/src/lib/gl_engine/tvgGlRaster.cpp +++ b/src/lib/gl_engine/tvgGlEngine.cpp @@ -14,14 +14,14 @@ * limitations under the License. * */ -#ifndef _TVG_GL_RASTER_CPP_ -#define _TVG_GL_RASTER_CPP_ +#ifndef _TVG_GL_ENGINE_CPP_ +#define _TVG_GL_ENGINE_CPP_ #include "tvgCommon.h" -#include "tvgGlRaster.h" +#include "tvgGlEngine.h" -static GlRaster* pInst = nullptr; +static GlEngine* pInst = nullptr; struct GlShape { @@ -29,7 +29,7 @@ struct GlShape }; -void* GlRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); @@ -42,31 +42,31 @@ void* GlRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) } -int GlRaster::init() +int GlEngine::init() { if (pInst) return -1; - pInst = new GlRaster(); + pInst = new GlEngine(); assert(pInst); return 0; } -int GlRaster::term() +int GlEngine::term() { if (!pInst) return -1; - cout << "GlRaster(" << pInst << ") destroyed!" << endl; + cout << "GlEngine(" << pInst << ") destroyed!" << endl; delete(pInst); pInst = nullptr; return 0; } -GlRaster* GlRaster::inst() +GlEngine* GlEngine::inst() { assert(pInst); return pInst; } -#endif /* _TVG_GL_RASTER_CPP_ */ +#endif /* _TVG_GL_ENGINE_CPP_ */ diff --git a/src/lib/gl_engine/tvgGlRaster.h b/src/lib/gl_engine/tvgGlEngine.h similarity index 81% rename from src/lib/gl_engine/tvgGlRaster.h rename to src/lib/gl_engine/tvgGlEngine.h index 08f750c3..bad52149 100644 --- a/src/lib/gl_engine/tvgGlRaster.h +++ b/src/lib/gl_engine/tvgGlEngine.h @@ -14,25 +14,25 @@ * limitations under the License. * */ -#ifndef _TVG_GL_RASTER_H_ -#define _TVG_GL_RASTER_H_ +#ifndef _TVG_GL_ENGINE_H_ +#define _TVG_GL_ENGINE_H_ namespace tvg { -class GlRaster : public RasterMethod +class GlEngine : public RasterMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - static GlRaster* inst(); + static GlEngine* inst(); static int init(); static int term(); private: - GlRaster(){}; - ~GlRaster(){}; + GlEngine(){}; + ~GlEngine(){}; }; } -#endif /* _TVG_GL_RASTER_H_ */ +#endif /* _TVG_GL_ENGINE_H_ */ diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index 4937d595..a1bb0e0a 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,7 +1,7 @@ source_file = [ 'tvgSwCommon.h', - 'tvgSwRaster.h', - 'tvgSwRaster.cpp', + 'tvgSwEngine.h', + 'tvgSwEngine.cpp', 'tvgSwShape.cpp', 'tvgSwRle.cpp', ] diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwEngine.cpp similarity index 84% rename from src/lib/sw_engine/tvgSwRaster.cpp rename to src/lib/sw_engine/tvgSwEngine.cpp index a7d2928b..a6ae3e78 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwEngine.cpp @@ -14,24 +14,24 @@ * limitations under the License. * */ -#ifndef _TVG_SW_RASTER_CPP_ -#define _TVG_SW_RASTER_CPP_ +#ifndef _TVG_SW_ENGINE_CPP_ +#define _TVG_SW_ENGINE_CPP_ #include "tvgSwCommon.h" -#include "tvgSwRaster.h" +#include "tvgSwEngine.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static SwRaster* pInst = nullptr; +static SwEngine* pInst = nullptr; /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -void* SwRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -59,31 +59,31 @@ void* SwRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) } -int SwRaster::init() +int SwEngine::init() { if (pInst) return -1; - pInst = new SwRaster(); + pInst = new SwEngine(); assert(pInst); return 0; } -int SwRaster::term() +int SwEngine::term() { if (!pInst) return -1; - cout << "SwRaster(" << pInst << ") destroyed!" << endl; + cout << "SwEngine(" << pInst << ") destroyed!" << endl; delete(pInst); pInst = nullptr; return 0; } -SwRaster* SwRaster::inst() +SwEngine* SwEngine::inst() { assert(pInst); return pInst; } -#endif /* _TVG_SW_RASTER_CPP_ */ +#endif /* _TVG_SW_ENGINE_CPP_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.h b/src/lib/sw_engine/tvgSwEngine.h similarity index 81% rename from src/lib/sw_engine/tvgSwRaster.h rename to src/lib/sw_engine/tvgSwEngine.h index c690be37..41853525 100644 --- a/src/lib/sw_engine/tvgSwRaster.h +++ b/src/lib/sw_engine/tvgSwEngine.h @@ -14,20 +14,20 @@ * limitations under the License. * */ -#ifndef _TVG_SW_RASTER_H_ -#define _TVG_SW_RASTER_H_ +#ifndef _TVG_SW_ENGINE_H_ +#define _TVG_SW_ENGINE_H_ -class SwRaster : public RasterMethod +class SwEngine : public RasterMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - static SwRaster* inst(); + static SwEngine* inst(); static int init(); static int term(); private: - SwRaster(){}; - ~SwRaster(){}; + SwEngine(){}; + ~SwEngine(){}; }; -#endif /* _TVG_SW_RASTER_H_ */ +#endif /* _TVG_SW_ENGINE_H_ */ diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index 5f8f533a..d99ee2d2 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -18,8 +18,8 @@ #define _TVG_ENGINE_CPP_ #include "tvgCommon.h" -#include "tvgSwRaster.h" -#include "tvgGlRaster.h" +#include "tvgSwEngine.h" +#include "tvgGlEngine.h" /************************************************************************/ /* Internal Class Implementation */ @@ -35,8 +35,8 @@ int Engine::init() noexcept //TODO: Initialize Raster engines by configuration. int ret = 0; - ret |= SwRaster::init(); - ret |= GlRaster::init(); + ret |= SwEngine::init(); + ret |= GlEngine::init(); return ret; } @@ -45,8 +45,8 @@ int Engine::init() noexcept int Engine::term() noexcept { int ret = 0; - ret |= SwRaster::term(); - ret |= GlRaster::term(); + ret |= SwEngine::term(); + ret |= GlEngine::term(); return ret; } diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 66f54488..7fb9a283 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -19,7 +19,7 @@ #include "tvgCommon.h" #include "tvgCanvasBase.h" -#include "tvgGlRaster.h" +#include "tvgGlEngine.h" /************************************************************************/ /* Internal Class Implementation */ @@ -27,7 +27,7 @@ struct GlCanvas::Impl : CanvasBase { - Impl() : CanvasBase(GlRaster::inst()) {} + Impl() : CanvasBase(GlEngine::inst()) {} }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 82da4530..995dac67 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -19,7 +19,7 @@ #include "tvgCommon.h" #include "tvgCanvasBase.h" -#include "tvgSwRaster.h" +#include "tvgSwEngine.h" /************************************************************************/ @@ -32,7 +32,7 @@ struct SwCanvas::Impl : CanvasBase int stride = 0; int height = 0; - Impl() : CanvasBase(SwRaster::inst()) {} + Impl() : CanvasBase(SwEngine::inst()) {} }; From c8d800f6c632b36d82ebd8921a781e5f47a16dfa Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 18 Apr 2020 13:48:37 +0900 Subject: [PATCH 011/244] sw_engine: implement line and curve raster Change-Id: I22a77892544cd510cfe646aee60093cebb848806 --- inc/tizenvg.h | 3 + src/lib/gl_engine/tvgGlEngine.cpp | 45 +++-- src/lib/gl_engine/tvgGlEngine.h | 4 + src/lib/sw_engine/tvgSwCommon.h | 20 +-- src/lib/sw_engine/tvgSwEngine.cpp | 40 +++-- src/lib/sw_engine/tvgSwEngine.h | 4 + src/lib/sw_engine/tvgSwRle.cpp | 286 +++++++++++++++++++++++++----- src/lib/sw_engine/tvgSwShape.cpp | 112 ++++++------ src/lib/tvgCanvasBase.h | 4 +- src/lib/tvgCommon.h | 61 +++++++ src/lib/tvgSceneNode.cpp | 7 + src/lib/tvgShapeNode.cpp | 11 ++ src/lib/tvgSwCanvas.cpp | 2 +- 13 files changed, 461 insertions(+), 138 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 2c43a85c..e9f49d37 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -73,6 +73,7 @@ class TIZENVG_EXPORT PaintNode { public: virtual ~PaintNode() {} + virtual int dispose(RasterMethod* engine) = 0; virtual int update(RasterMethod* engine) = 0; }; @@ -90,6 +91,7 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode public: ~ShapeNode(); + int dispose(RasterMethod* engine) noexcept override; int update(RasterMethod* engine) noexcept override; int clear() noexcept; @@ -121,6 +123,7 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode public: ~SceneNode(); + int dispose(RasterMethod* engine) noexcept override; int update(RasterMethod* engine) noexcept override; int push(std::unique_ptr shape) noexcept; diff --git a/src/lib/gl_engine/tvgGlEngine.cpp b/src/lib/gl_engine/tvgGlEngine.cpp index 9280e347..65a5ce33 100644 --- a/src/lib/gl_engine/tvgGlEngine.cpp +++ b/src/lib/gl_engine/tvgGlEngine.cpp @@ -20,14 +20,29 @@ #include "tvgCommon.h" #include "tvgGlEngine.h" +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ -static GlEngine* pInst = nullptr; +static RasterMethodInit engineInit; struct GlShape { //TODO: }; +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +void* GlEngine::dispose(const ShapeNode& shape, void *data) +{ + GlShape* sdata = static_cast(data); + if (!sdata) return nullptr; + free(sdata); + return nullptr; +} + void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { @@ -37,35 +52,37 @@ void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) sdata = static_cast(calloc(1, sizeof(GlShape))); assert(sdata); } - return sdata; } int GlEngine::init() { - if (pInst) return -1; - pInst = new GlEngine(); - assert(pInst); - - return 0; + return RasterMethodInit::init(engineInit, new GlEngine); } int GlEngine::term() { - if (!pInst) return -1; - cout << "GlEngine(" << pInst << ") destroyed!" << endl; - delete(pInst); - pInst = nullptr; - return 0; + return RasterMethodInit::term(engineInit); +} + + +size_t GlEngine::unref() +{ + return RasterMethodInit::unref(engineInit); +} + + +size_t GlEngine::ref() +{ + return RasterMethodInit::ref(engineInit); } GlEngine* GlEngine::inst() { - assert(pInst); - return pInst; + return dynamic_cast(RasterMethodInit::inst(engineInit)); } diff --git a/src/lib/gl_engine/tvgGlEngine.h b/src/lib/gl_engine/tvgGlEngine.h index bad52149..ebd1fd54 100644 --- a/src/lib/gl_engine/tvgGlEngine.h +++ b/src/lib/gl_engine/tvgGlEngine.h @@ -24,6 +24,10 @@ class GlEngine : public RasterMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; + void* dispose(const ShapeNode& shape, void *data) override; + size_t ref() override; + size_t unref() override; + static GlEngine* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 576a0b83..4e75e3cd 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -23,6 +23,8 @@ using namespace tvg; constexpr auto SW_CURVE_TAG_ON = 1; constexpr auto SW_CURVE_TAG_CUBIC = 2; +constexpr auto SW_OUTLINE_FILL_WINDING = 0; +constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; using SwCoord = signed long; @@ -56,43 +58,41 @@ struct SwOutline size_t ptsCnt; //number of points in the glyph size_t reservedPtsCnt; char* tags; //the points flags - size_t flags; //outline masks + uint8_t fillMode; //outline fill mode }; struct SwSpan { - size_t x; - size_t y; - size_t len; + uint16_t x, y; + uint16_t len; uint8_t coverage; }; struct SwRleData { + SwSpan *spans; size_t alloc; size_t size; - SwSpan *spans; }; struct SwBBox { - SwPoint min; - SwPoint max; + SwPoint min, max; }; struct SwShape { SwOutline* outline; - SwRleData rle; + SwRleData* rle; SwBBox bbox; }; +void shapeReset(SwShape& sdata); bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata); void shapeDelOutline(const ShapeNode& shape, SwShape& sdata); bool shapeGenRle(const ShapeNode& shape, SwShape& sdata); -void shapeDelRle(const ShapeNode& shape, SwShape& sdata); bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); -bool rleRender(SwShape& sdata); +SwRleData* rleRender(const SwShape& sdata); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwEngine.cpp b/src/lib/sw_engine/tvgSwEngine.cpp index a6ae3e78..683bffad 100644 --- a/src/lib/sw_engine/tvgSwEngine.cpp +++ b/src/lib/sw_engine/tvgSwEngine.cpp @@ -24,13 +24,22 @@ /* Internal Class Implementation */ /************************************************************************/ -static SwEngine* pInst = nullptr; +static RasterMethodInit engineInit; /************************************************************************/ /* External Class Implementation */ /************************************************************************/ +void* SwEngine::dispose(const ShapeNode& shape, void *data) +{ + SwShape* sdata = static_cast(data); + if (!sdata) return nullptr; + shapeReset(*sdata); + free(sdata); + return nullptr; +} + void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data @@ -48,11 +57,11 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) if (alpha == 0) return sdata; if (flags & UpdateFlag::Path) { + shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; //TODO: From below sequence starts threading? if (!shapeTransformOutline(shape, *sdata)) return sdata; if (!shapeGenRle(shape, *sdata)) return sdata; - shapeDelOutline(shape, *sdata); } return sdata; @@ -61,28 +70,31 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) int SwEngine::init() { - if (pInst) return -1; - pInst = new SwEngine(); - assert(pInst); - - return 0; + return RasterMethodInit::init(engineInit, new SwEngine); } int SwEngine::term() { - if (!pInst) return -1; - cout << "SwEngine(" << pInst << ") destroyed!" << endl; - delete(pInst); - pInst = nullptr; - return 0; + return RasterMethodInit::term(engineInit); +} + + +size_t SwEngine::unref() +{ + return RasterMethodInit::unref(engineInit); +} + + +size_t SwEngine::ref() +{ + return RasterMethodInit::ref(engineInit); } SwEngine* SwEngine::inst() { - assert(pInst); - return pInst; + return dynamic_cast(RasterMethodInit::inst(engineInit)); } diff --git a/src/lib/sw_engine/tvgSwEngine.h b/src/lib/sw_engine/tvgSwEngine.h index 41853525..dd2d4015 100644 --- a/src/lib/sw_engine/tvgSwEngine.h +++ b/src/lib/sw_engine/tvgSwEngine.h @@ -21,6 +21,10 @@ class SwEngine : public RasterMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; + void* dispose(const ShapeNode& shape, void *data) override; + size_t ref() override; + size_t unref() override; + static SwEngine* inst(); static int init(); static int term(); diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f8292c61..25b9c03a 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "tvgSwCommon.h" /************************************************************************/ @@ -29,7 +30,6 @@ constexpr auto MAX_SPANS = 256; constexpr auto PIXEL_BITS = 8; //must be at least 6 bits! constexpr auto ONE_PIXEL = (1L << PIXEL_BITS); - using Area = long; struct Band @@ -47,6 +47,8 @@ struct Cell struct RleWorker { + SwRleData* rle; + SwPoint cellPos; SwPoint cellMin; SwPoint cellMax; @@ -100,13 +102,19 @@ static inline SwPoint DOWNSCALE(const SwPoint& pt) static inline SwPoint TRUNC(const SwPoint& pt) { - return { pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS }; + return {pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS}; +} + + +static inline SwCoord TRUNC(const SwCoord x) +{ + return x >> PIXEL_BITS; } static inline SwPoint SUBPIXELS(const SwPoint& pt) { - return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS }; + return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS}; } @@ -115,20 +123,105 @@ static inline SwCoord SUBPIXELS(const SwCoord x) return (x << PIXEL_BITS); } - -static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) +/* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' + * algorithm. We use alpha = 1, beta = 3/8, giving us results with a + * largest error less than 7% compared to the exact value. + */ +static inline SwCoord HYPOT(SwPoint pt) { - //TODO: + if (pt.x < 0) pt.x = -pt.x; + if (pt.y < 0) pt.y = -pt.y; + return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3))); +} + +static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count) +{ + assert(rle && spans); + + auto newSize = rle->size + count; + + /* allocate enough memory for new spans */ + /* alloc is required to prevent free and reallocation */ + /* when the rle needs to be regenerated because of attribute change. */ + if (rle->alloc < newSize) { + rle->spans = static_cast(realloc(rle->spans, newSize * sizeof(SwSpan))); + assert(rle->spans); + rle->alloc = newSize; + } + + //copy the new spans to the allocated memory + SwSpan* lastSpan = rle->spans + rle->size; + assert(lastSpan); + memcpy(lastSpan, spans, count * sizeof(SwSpan)); + + rle->size = newSize; } -static void genSpan(RleWorker& rw) +static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) { - //TODO: + /* compute the coverage line's coverage, depending on the outline fill rule */ + /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ + auto coverage = static_cast(area >> (PIXEL_BITS * 2 + 1 - 8)); //range 0 - 256 + + if (coverage < 0) coverage = -coverage; + + if (rw.outline->fillMode == SW_OUTLINE_FILL_EVEN_ODD) { + coverage &= 511; + if (coverage > 256) coverage = 512 - coverage; + else if (coverage == 256) coverage = 255; + } else { + //normal non-zero winding rule + if (coverage >= 256) coverage = 255; + } + + x += rw.cellMin.x; + y += rw.cellMin.y; + + //span has ushort coordinates. check limit overflow + if (x >= SHRT_MAX) { + cout << "x(" << x << ") coordinate overflow!" << endl; + x = SHRT_MAX; + } + if (y >= SHRT_MAX) { + cout << "y(" << y << ") coordinate overflow!" << endl; + y = SHRT_MAX; + } + + if (coverage) { + auto count = rw.spansCnt; + auto span = rw.spans + count - 1; + assert(span); + + //see whether we can add this span to the current list + if ((count > 0) && (rw.ySpan == y) && + (span->x + span->len == x) && (span->coverage == coverage)) { + span->len = span->len + acount; + return; + } + + if (count >= MAX_SPANS) { + _genSpan(rw.rle, rw.spans, count); + rw.spansCnt = 0; + span = rw.spans; + assert(span); + } else { + ++span; + assert(span); + } + + //add a span to the current list + span->x = x; + span->y = y; + span->len = acount; + span->coverage = coverage; + ++rw.spansCnt; + } } -static void sweep(RleWorker& rw) +static void _sweep(RleWorker& rw) { if (rw.cellsCnt == 0) return; @@ -142,26 +235,26 @@ static void sweep(RleWorker& rw) while (cell) { - horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); + _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); cover += cell->cover; auto area = cover * (ONE_PIXEL * 2) - cell->area; if (area != 0 && cell->x >= 0) - horizLine(rw, cell->x, y, area, 1); + _horizLine(rw, cell->x, y, area, 1); x = cell->x + 1; cell = cell->next; } if (cover != 0) - horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); + _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); } - if (rw.spansCnt > 0) genSpan(rw); + if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt); } -static Cell* findCell(RleWorker& rw) +static Cell* _findCell(RleWorker& rw) { auto x = rw.cellPos.x; if (x > rw.cellXCnt) x = rw.cellXCnt; @@ -190,17 +283,18 @@ static Cell* findCell(RleWorker& rw) } -static void recordCell(RleWorker& rw) +static void _recordCell(RleWorker& rw) { if (rw.area | rw.cover) { - auto cell = findCell(rw); + auto cell = _findCell(rw); assert(cell); cell->area += rw.area; cell->cover += rw.cover; } } -static void setCell(RleWorker& rw, SwPoint pos) + +static void _setCell(RleWorker& rw, SwPoint pos) { /* Move the cell pointer to a new position. We set the `invalid' */ /* flag to indicate that the cell isn't part of those we're interested */ @@ -222,7 +316,7 @@ static void setCell(RleWorker& rw, SwPoint pos) //Are we moving to a different cell? if (pos != rw.cellPos) { - if (!rw.invalid) recordCell(rw); + if (!rw.invalid) _recordCell(rw); } rw.area = 0; @@ -232,7 +326,7 @@ static void setCell(RleWorker& rw, SwPoint pos) } -static void startCell(RleWorker& rw, SwPoint pos) +static void _startCell(RleWorker& rw, SwPoint pos) { if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x; @@ -242,23 +336,23 @@ static void startCell(RleWorker& rw, SwPoint pos) rw.cellPos = pos - rw.cellMin; rw.invalid = false; - setCell(rw, pos); + _setCell(rw, pos); } -static void moveTo(RleWorker& rw, const SwPoint& to) +static void _moveTo(RleWorker& rw, const SwPoint& to) { //record current cell, if any */ - if (!rw.invalid) recordCell(rw); + if (!rw.invalid) _recordCell(rw); //start to a new position - startCell(rw, TRUNC(to)); + _startCell(rw, TRUNC(to)); rw.pos = to; } -static void lineTo(RleWorker& rw, const SwPoint& to) +static void _lineTo(RleWorker& rw, const SwPoint& to) { #define SW_UDIV(a, b) \ static_cast(((unsigned long)(a) * (unsigned long)(b)) >> \ @@ -284,7 +378,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to) //any horizontal line } else if (diff.y == 0) { e1.x = e2.x; - setCell(rw, e1); + _setCell(rw, e1); } else if (diff.x == 0) { //vertical line up if (diff.y > 0) { @@ -294,7 +388,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to) rw.area += (f2.y - f1.y) * f1.x * 2; f1.y = 0; ++e1.y; - setCell(rw, e1); + _setCell(rw, e1); } while(e1.y != e2.y); //vertical line down } else { @@ -304,7 +398,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to) rw.area += (f2.y - f1.y) * f1.x * 2; f1.y = ONE_PIXEL; --e1.y; - setCell(rw, e1); + _setCell(rw, e1); } while(e1.y != e2.y); } //any other line @@ -357,7 +451,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to) --e1.y; } - setCell(rw, e1); + _setCell(rw, e1); } while(e1 != e2); } @@ -369,21 +463,111 @@ static void lineTo(RleWorker& rw, const SwPoint& to) } -static bool renderCubic(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) +static void _splitCubic(SwPoint* base) { - return true; + assert(base); + + SwCoord a, b, c, d; + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = (base[0].x + c) / 2; + base[5].x = b = (base[3].x + d) / 2; + c = (c + d) / 2; + base[2].x = a = (a + c) / 2; + base[4].x = b = (b + c) / 2; + base[3].x = (a + b) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = (base[0].y + c) / 2; + base[5].y = b = (base[3].y + d) / 2; + c = (c + d) / 2; + base[2].y = a = (a + c) / 2; + base[4].y = b = (b + c) / 2; + base[3].y = (a + b) / 2; } -static bool cubicTo(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) +static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) { - return renderCubic(rw, ctrl1, ctrl2, to); + auto arc = rw.bezStack; + assert(arc); + + arc[0] = to; + arc[1] = ctrl2; + arc[2] = ctrl1; + arc[3] = rw.pos; + + //Short-cut the arc that crosses the current band + auto min = arc[0].y; + auto max = arc[0].y; + + SwCoord y; + for (auto i = 1; i < 4; ++i) { + y = arc[i].y; + if (y < min) min = y; + if (y > max) max = y; + } + + if (TRUNC(min) >= rw.cellMax.y || TRUNC(max) < rw.cellMin.y) goto draw; + + /* Decide whether to split or draw. See `Rapid Termination */ + /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */ + /* F. Hain, at */ + /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */ + while (true) { + { + //diff is the P0 - P3 chord vector + auto diff = arc[3] - arc[0]; + auto L = HYPOT(diff); + + //avoid possible arithmetic overflow below by splitting + if (L > SHRT_MAX) goto split; + + //max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1) + auto sLimit = L * (ONE_PIXEL / 6); + + auto diff1 = arc[1] - arc[0]; + auto s = diff.y * diff1.x - diff.x * diff1.y; + if (s < 0) s = -s; + if (s > sLimit) goto split; + + //s is L * the perpendicular distance from P2 to the line P0 - P3 + auto diff2 = arc[2] - arc[0]; + s = diff.y * diff2.x - diff.x * diff2.y; + if (s < 0) s = -s; + if (s > sLimit) goto split; + + /* Split super curvy segments where the off points are so far + from the chord that the angles P0-P1-P3 or P0-P2-P3 become + acute as detected by appropriate dot products */ + if (diff1.x * (diff1.x - diff.x) + diff1.y * (diff1.y - diff.y) > 0 || + diff2.x * (diff2.x - diff.x) + diff2.y * (diff2.y - diff.y) > 0) + goto split; + + //no reason to split + goto draw; + } + split: + _splitCubic(arc); + arc += 3; + continue; + + draw: + _lineTo(rw, arc[0]); + + if (arc == rw.bezStack) return; + + arc -= 3; + } } -static bool decomposeOutline(RleWorker& rw) +static bool _decomposeOutline(RleWorker& rw) { - // printf("decomposOutline\n"); auto outline = rw.outline; assert(outline); @@ -402,7 +586,7 @@ static bool decomposeOutline(RleWorker& rw) /* A contour cannot start with a cubic control point! */ if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline; - moveTo(rw, UPSCALE(outline->pts[first])); + _moveTo(rw, UPSCALE(outline->pts[first])); while (pt < limit) { assert(++pt); @@ -410,7 +594,7 @@ static bool decomposeOutline(RleWorker& rw) //emit a single line_to if (tags[0] == SW_CURVE_TAG_ON) { - lineTo(rw, UPSCALE(*pt)); + _lineTo(rw, UPSCALE(*pt)); //tag cubic } else { if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC) @@ -420,10 +604,10 @@ static bool decomposeOutline(RleWorker& rw) tags += 2; if (pt <= limit) { - if (!cubicTo(rw, pt[-2], pt[-1], pt[0])) return false; + _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0])); continue; } - if (!cubicTo(rw, pt[-2], pt[-1], outline->pts[first])) return false; + _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(outline->pts[first])); goto close; } } @@ -442,13 +626,13 @@ invalid_outline: } -static bool genRle(RleWorker& rw) +static bool _genRle(RleWorker& rw) { bool ret = false; if (setjmp(rw.jmpBuf) == 0) { - ret = decomposeOutline(rw); - if (!rw.invalid) recordCell(rw); + ret = _decomposeOutline(rw); + if (!rw.invalid) _recordCell(rw); } else { cout << "Memory Overflow" << endl; } @@ -460,7 +644,7 @@ static bool genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -bool rleRender(SwShape& sdata) +SwRleData* rleRender(const SwShape& sdata) { constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 39; @@ -468,7 +652,7 @@ bool rleRender(SwShape& sdata) auto outline = sdata.outline; assert(outline); - if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; + if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr; assert(outline->cntrs && outline->pts); assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); @@ -494,6 +678,9 @@ bool rleRender(SwShape& sdata) rw.outline = outline; rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; + rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); + assert(rw.rle); + //printf("bufferSize = %d, bbox(%f %f %f %f), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize); //Generate RLE @@ -547,9 +734,9 @@ bool rleRender(SwShape& sdata) rw.cellMax.y = band->max; rw.cellYCnt = band->max - band->min; - if (!genRle(rw)) return -1; + if (!_genRle(rw)) goto error; - sweep(rw); + _sweep(rw); --band; continue; @@ -561,7 +748,7 @@ bool rleRender(SwShape& sdata) /* This is too complex for a single scanline; there must be some problems */ - if (middle == bottom) return -1; + if (middle == bottom) goto error; if (bottom - top >= rw.bandSize) ++rw.bandShoot; @@ -576,7 +763,12 @@ bool rleRender(SwShape& sdata) if (rw.bandShoot > 8 && rw.bandSize > 16) rw.bandSize = (rw.bandSize >> 1); - return true; + return rw.rle; + +error: + free(rw.rle); + rw.rle = nullptr; + return nullptr; } #endif /* _TVG_SW_RLE_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 0f2a6fa4..e725e30c 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -29,7 +29,7 @@ static inline SwPoint TO_SWPOINT(const Point* pt) } -static void growOutlineContour(SwOutline& outline, size_t n) +static void _growOutlineContour(SwOutline& outline, size_t n) { if (n == 0) { free(outline.cntrs); @@ -40,14 +40,14 @@ static void growOutlineContour(SwOutline& outline, size_t n) } if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; - cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;; + //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;; outline.reservedCntrsCnt = n; outline.cntrs = static_cast(realloc(outline.cntrs, n * sizeof(size_t))); assert(outline.cntrs); } -static void growOutlinePoint(SwOutline& outline, size_t n) +static void _growOutlinePoint(SwOutline& outline, size_t n) { if (n == 0) { free(outline.pts); @@ -61,7 +61,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n) if (outline.reservedPtsCnt >= outline.ptsCnt + n) return; - cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl; + //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl; outline.reservedPtsCnt = n; outline.pts = static_cast(realloc(outline.pts, n * sizeof(SwPoint))); assert(outline.pts); @@ -70,9 +70,9 @@ static void growOutlinePoint(SwOutline& outline, size_t n) } -static void outlineEnd(SwOutline& outline) +static void _outlineEnd(SwOutline& outline) { - growOutlineContour(outline, 1); + _growOutlineContour(outline, 1); if (outline.ptsCnt > 0) { outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1; ++outline.cntrsCnt; @@ -80,17 +80,17 @@ static void outlineEnd(SwOutline& outline) } -static void outlineMoveTo(SwOutline& outline, const Point* to) +static void _outlineMoveTo(SwOutline& outline, const Point* to) { assert(to); - growOutlinePoint(outline, 1); + _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; if (outline.ptsCnt > 0) { - growOutlineContour(outline, 1); + _growOutlineContour(outline, 1); outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1; ++outline.cntrsCnt; } @@ -99,11 +99,11 @@ static void outlineMoveTo(SwOutline& outline, const Point* to) } -static void outlineLineTo(SwOutline& outline, const Point* to) +static void _outlineLineTo(SwOutline& outline, const Point* to) { assert(to); - growOutlinePoint(outline, 1); + _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; @@ -112,11 +112,11 @@ static void outlineLineTo(SwOutline& outline, const Point* to) } -static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to) +static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to) { assert(ctrl1 && ctrl2 && to); - growOutlinePoint(outline, 3); + _growOutlinePoint(outline, 3); outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1); outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; @@ -132,7 +132,7 @@ static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* } -static bool outlineClose(SwOutline& outline) +static bool _outlineClose(SwOutline& outline) { size_t i = 0; @@ -146,7 +146,7 @@ static bool outlineClose(SwOutline& outline) if (outline.ptsCnt == i) return false; //Close the path - growOutlinePoint(outline, 1); + _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = outline.pts[i]; outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; @@ -156,14 +156,14 @@ static bool outlineClose(SwOutline& outline) } -static void initBBox(SwShape& sdata) +static void _initBBox(SwShape& sdata) { sdata.bbox.min.x = sdata.bbox.min.y = 0; sdata.bbox.max.x = sdata.bbox.max.y = 0; } -static bool updateBBox(SwShape& sdata) +static bool _updateBBox(SwShape& sdata) { auto outline = sdata.outline; assert(outline); @@ -172,7 +172,7 @@ static bool updateBBox(SwShape& sdata) assert(pt); if (outline->ptsCnt <= 0) { - initBBox(sdata); + _initBBox(sdata); return false; } @@ -201,33 +201,17 @@ static bool updateBBox(SwShape& sdata) } -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) +void _deleteRle(SwShape& sdata) { - //TODO: - return true; + if (sdata.rle) { + if (sdata.rle->spans) free(sdata.rle->spans); + free(sdata.rle); + } + sdata.rle = nullptr; } -void shapeDelRle(const ShapeNode& shape, SwShape& sdata) -{ - if (sdata.rle.spans) free(sdata.rle.spans); - sdata.rle.spans = nullptr; -} - - -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) -{ - shapeDelRle(shape, sdata); - if (!updateBBox(sdata)) return false; - return rleRender(sdata); -} - - -void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) +void _deleteOutline(SwShape& sdata) { if (!sdata.outline) return; @@ -240,11 +224,38 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) sdata.outline = nullptr; } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) +{ + //TODO: + return true; +} + + +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +{ + if (!_updateBBox(sdata)) goto end; + sdata.rle = rleRender(sdata); + _deleteOutline(sdata); +end: + if (sdata.rle) return true; + return false; +} + + +void shapeReset(SwShape& sdata) +{ + _deleteOutline(sdata); + _deleteRle(sdata); + _initBBox(sdata); +} + bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) { - initBBox(sdata); - const PathCommand* cmds = nullptr; auto cmdCnt = shape.pathCommands(&cmds); @@ -257,7 +268,6 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) //smart reservation auto outlinePtsCnt = 0; auto outlineCntrsCnt = 0; -// auto closed = false; for (auto i = 0; i < cmdCnt; ++i) { switch(*(cmds + i)) { @@ -294,28 +304,28 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) } //TODO: Probabry we can copy pts from shape directly. - growOutlinePoint(*outline, outlinePtsCnt); - growOutlineContour(*outline, outlineCntrsCnt); + _growOutlinePoint(*outline, outlinePtsCnt); + _growOutlineContour(*outline, outlineCntrsCnt); //Generate Outlines while (cmdCnt-- > 0) { switch(*cmds) { case PathCommand::Close: { - outlineClose(*outline); + _outlineClose(*outline); break; } case PathCommand::MoveTo: { - outlineMoveTo(*outline, pts); + _outlineMoveTo(*outline, pts); ++pts; break; } case PathCommand::LineTo: { - outlineLineTo(*outline, pts); + _outlineLineTo(*outline, pts); ++pts; break; } case PathCommand::CubicTo: { - outlineCubicTo(*outline, pts, pts + 1, pts + 2); + _outlineCubicTo(*outline, pts, pts + 1, pts + 2); pts += 3; break; } @@ -323,7 +333,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) ++cmds; } - outlineEnd(*outline); + _outlineEnd(*outline); //FIXME: //outline->flags = SwOutline::FillRule::Winding; diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index f200d29d..3ec6c7ab 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -30,12 +30,13 @@ struct CanvasBase CanvasBase(RasterMethod *pRaster):raster(pRaster) { - + raster->ref(); } ~CanvasBase() { clear(); + raster->unref(); } int reserve(size_t n) @@ -48,6 +49,7 @@ struct CanvasBase int clear() { for (auto node : nodes) { + node->dispose(raster); delete(node); } nodes.clear(); diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index e9dc2490..fe2d8e21 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -35,6 +35,67 @@ public: enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RasterMethod() {} virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; + virtual void* dispose(const ShapeNode& shape, void *data) = 0; + virtual size_t ref() = 0; + virtual size_t unref() = 0; +}; + +struct RasterMethodInit +{ + RasterMethod* pInst = nullptr; + size_t refCnt = 0; + bool initted = false; + + static int init(RasterMethodInit& initter, RasterMethod* engine) + { + assert(engine); + if (initter.pInst || initter.refCnt > 0) return -1; + initter.pInst = engine; + initter.refCnt = 0; + initter.initted = true; + return 0; + } + + static int term(RasterMethodInit& initter) + { + if (!initter.pInst || !initter.initted) return -1; + + initter.initted = false; + + //Still it's refered.... + if (initter.refCnt > 0) return 0; + delete(initter.pInst); + initter.pInst = nullptr; + + return 0; + } + + static size_t unref(RasterMethodInit& initter) + { + assert(initter.refCnt > 0); + --initter.refCnt; + + //engine has been requested to termination + if (!initter.initted && initter.refCnt == 0) { + if (initter.pInst) { + delete(initter.pInst); + initter.pInst = nullptr; + } + } + return initter.refCnt; + } + + static RasterMethod* inst(RasterMethodInit& initter) + { + assert(initter.pInst); + return initter.pInst; + } + + static size_t ref(RasterMethodInit& initter) + { + return ++initter.refCnt; + } + }; } diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp index 7c4bb589..93a9b211 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgSceneNode.cpp @@ -58,6 +58,13 @@ int SceneNode :: push(unique_ptr shape) noexcept } +int SceneNode :: dispose(RasterMethod* engine) noexcept +{ + + return 0; +} + + int SceneNode :: update(RasterMethod* engine) noexcept { diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 81d97dd5..f17021a2 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -84,6 +84,17 @@ unique_ptr ShapeNode::gen() noexcept } +int ShapeNode :: dispose(RasterMethod* engine) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->edata = engine->dispose(*this, impl->edata); + if (impl->edata) return -1; + return 0; +} + + int ShapeNode :: update(RasterMethod* engine) noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 995dac67..e85275f4 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -89,7 +89,7 @@ SwCanvas::SwCanvas() : pImpl(make_unique()) SwCanvas::~SwCanvas() { - cout << "SwCanvas(" << this << ") destroyed!" << endl; + cout << "SwCanvas(" << this << ") destroyed!" << endl; } From 9b7337622d1770f7d4e692bb60f838ca7ba9c5ca Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 18 Apr 2020 22:59:27 +0900 Subject: [PATCH 012/244] rename class names. RasterMethod -> RenderMethod SwEngine -> SwRenderer GlEngine -> GlRenderer Change-Id: Ic2ded698e49c4373fe21fe31fa34baca01bf43a2 --- inc/tizenvg.h | 18 +++++----- src/lib/gl_engine/meson.build | 4 +-- .../{tvgGlEngine.cpp => tvgGlRenderer.cpp} | 34 +++++++++---------- .../{tvgGlEngine.h => tvgGlRenderer.h} | 14 ++++---- src/lib/sw_engine/meson.build | 4 +-- .../{tvgSwEngine.cpp => tvgSwRenderer.cpp} | 34 +++++++++---------- .../{tvgSwEngine.h => tvgSwRenderer.h} | 14 ++++---- src/lib/tvgCanvasBase.h | 14 ++++---- src/lib/tvgCommon.h | 18 +++++----- src/lib/tvgEngine.cpp | 12 +++---- src/lib/tvgGlCanvas.cpp | 8 ++--- src/lib/tvgSceneNode.cpp | 4 +-- src/lib/tvgShapeNode.cpp | 6 ++-- src/lib/tvgSwCanvas.cpp | 8 ++--- 14 files changed, 96 insertions(+), 96 deletions(-) rename src/lib/gl_engine/{tvgGlEngine.cpp => tvgGlRenderer.cpp} (68%) rename src/lib/gl_engine/{tvgGlEngine.h => tvgGlRenderer.h} (82%) rename src/lib/sw_engine/{tvgSwEngine.cpp => tvgSwRenderer.cpp} (73%) rename src/lib/sw_engine/{tvgSwEngine.h => tvgSwRenderer.h} (82%) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index e9f49d37..dd125b52 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -52,7 +52,7 @@ namespace tvg enum class TIZENVG_EXPORT PathCommand { Close, MoveTo, LineTo, CubicTo }; -class RasterMethod; +class RenderMethod; struct Point { @@ -73,8 +73,8 @@ class TIZENVG_EXPORT PaintNode { public: virtual ~PaintNode() {} - virtual int dispose(RasterMethod* engine) = 0; - virtual int update(RasterMethod* engine) = 0; + virtual int dispose(RenderMethod* engine) = 0; + virtual int update(RenderMethod* engine) = 0; }; @@ -91,8 +91,8 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode public: ~ShapeNode(); - int dispose(RasterMethod* engine) noexcept override; - int update(RasterMethod* engine) noexcept override; + int dispose(RenderMethod* engine) noexcept override; + int update(RenderMethod* engine) noexcept override; int clear() noexcept; int appendRect(float x, float y, float w, float h, float radius) noexcept; @@ -123,8 +123,8 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode public: ~SceneNode(); - int dispose(RasterMethod* engine) noexcept override; - int update(RasterMethod* engine) noexcept override; + int dispose(RenderMethod* engine) noexcept override; + int update(RenderMethod* engine) noexcept override; int push(std::unique_ptr shape) noexcept; @@ -153,7 +153,7 @@ public: int update() noexcept; int draw(bool async = true) noexcept; int sync() noexcept; - RasterMethod* engine() noexcept; + RenderMethod* engine() noexcept; int target(uint32_t* buffer, size_t stride, size_t height) noexcept; @@ -183,7 +183,7 @@ public: int update() noexcept; int draw(bool async = true) noexcept { return 0; } int sync() noexcept { return 0; } - RasterMethod* engine() noexcept; + RenderMethod* engine() noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 117149a1..13e7fefe 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -1,6 +1,6 @@ source_file = [ - 'tvgGlEngine.h', - 'tvgGlEngine.cpp', + 'tvgGlRenderer.h', + 'tvgGlRenderer.cpp', ] glraster_dep = declare_dependency( diff --git a/src/lib/gl_engine/tvgGlEngine.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp similarity index 68% rename from src/lib/gl_engine/tvgGlEngine.cpp rename to src/lib/gl_engine/tvgGlRenderer.cpp index 65a5ce33..92f00dd6 100644 --- a/src/lib/gl_engine/tvgGlEngine.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -14,17 +14,17 @@ * limitations under the License. * */ -#ifndef _TVG_GL_ENGINE_CPP_ -#define _TVG_GL_ENGINE_CPP_ +#ifndef _TVG_GL_RENDERER_CPP_ +#define _TVG_GL_RENDERER_CPP_ #include "tvgCommon.h" -#include "tvgGlEngine.h" +#include "tvgGlRenderer.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static RasterMethodInit engineInit; +static RenderMethodInit engineInit; struct GlShape { @@ -35,7 +35,7 @@ struct GlShape /* External Class Implementation */ /************************************************************************/ -void* GlEngine::dispose(const ShapeNode& shape, void *data) +void* GlRenderer::dispose(const ShapeNode& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return nullptr; @@ -44,7 +44,7 @@ void* GlEngine::dispose(const ShapeNode& shape, void *data) } -void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* GlRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); @@ -56,34 +56,34 @@ void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) } -int GlEngine::init() +int GlRenderer::init() { - return RasterMethodInit::init(engineInit, new GlEngine); + return RenderMethodInit::init(engineInit, new GlRenderer); } -int GlEngine::term() +int GlRenderer::term() { - return RasterMethodInit::term(engineInit); + return RenderMethodInit::term(engineInit); } -size_t GlEngine::unref() +size_t GlRenderer::unref() { - return RasterMethodInit::unref(engineInit); + return RenderMethodInit::unref(engineInit); } -size_t GlEngine::ref() +size_t GlRenderer::ref() { - return RasterMethodInit::ref(engineInit); + return RenderMethodInit::ref(engineInit); } -GlEngine* GlEngine::inst() +GlRenderer* GlRenderer::inst() { - return dynamic_cast(RasterMethodInit::inst(engineInit)); + return dynamic_cast(RenderMethodInit::inst(engineInit)); } -#endif /* _TVG_GL_ENGINE_CPP_ */ +#endif /* _TVG_GL_RENDERER_CPP_ */ diff --git a/src/lib/gl_engine/tvgGlEngine.h b/src/lib/gl_engine/tvgGlRenderer.h similarity index 82% rename from src/lib/gl_engine/tvgGlEngine.h rename to src/lib/gl_engine/tvgGlRenderer.h index ebd1fd54..534969a1 100644 --- a/src/lib/gl_engine/tvgGlEngine.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -14,13 +14,13 @@ * limitations under the License. * */ -#ifndef _TVG_GL_ENGINE_H_ -#define _TVG_GL_ENGINE_H_ +#ifndef _TVG_GL_RENDERER_H_ +#define _TVG_GL_RENDERER_H_ namespace tvg { -class GlEngine : public RasterMethod +class GlRenderer : public RenderMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; @@ -28,15 +28,15 @@ public: size_t ref() override; size_t unref() override; - static GlEngine* inst(); + static GlRenderer* inst(); static int init(); static int term(); private: - GlEngine(){}; - ~GlEngine(){}; + GlRenderer(){}; + ~GlRenderer(){}; }; } -#endif /* _TVG_GL_ENGINE_H_ */ +#endif /* _TVG_GL_RENDERER_H_ */ diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index a1bb0e0a..4edd4895 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,7 +1,7 @@ source_file = [ 'tvgSwCommon.h', - 'tvgSwEngine.h', - 'tvgSwEngine.cpp', + 'tvgSwRenderer.h', + 'tvgSwRenderer.cpp', 'tvgSwShape.cpp', 'tvgSwRle.cpp', ] diff --git a/src/lib/sw_engine/tvgSwEngine.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp similarity index 73% rename from src/lib/sw_engine/tvgSwEngine.cpp rename to src/lib/sw_engine/tvgSwRenderer.cpp index 683bffad..a4f126d9 100644 --- a/src/lib/sw_engine/tvgSwEngine.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -14,24 +14,24 @@ * limitations under the License. * */ -#ifndef _TVG_SW_ENGINE_CPP_ -#define _TVG_SW_ENGINE_CPP_ +#ifndef _TVG_SW_RENDERER_CPP_ +#define _TVG_SW_RENDERER_CPP_ #include "tvgSwCommon.h" -#include "tvgSwEngine.h" +#include "tvgSwRenderer.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static RasterMethodInit engineInit; +static RenderMethodInit engineInit; /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -void* SwEngine::dispose(const ShapeNode& shape, void *data) +void* SwRenderer::dispose(const ShapeNode& shape, void *data) { SwShape* sdata = static_cast(data); if (!sdata) return nullptr; @@ -40,7 +40,7 @@ void* SwEngine::dispose(const ShapeNode& shape, void *data) return nullptr; } -void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -68,34 +68,34 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) } -int SwEngine::init() +int SwRenderer::init() { - return RasterMethodInit::init(engineInit, new SwEngine); + return RenderMethodInit::init(engineInit, new SwRenderer); } -int SwEngine::term() +int SwRenderer::term() { - return RasterMethodInit::term(engineInit); + return RenderMethodInit::term(engineInit); } -size_t SwEngine::unref() +size_t SwRenderer::unref() { - return RasterMethodInit::unref(engineInit); + return RenderMethodInit::unref(engineInit); } -size_t SwEngine::ref() +size_t SwRenderer::ref() { - return RasterMethodInit::ref(engineInit); + return RenderMethodInit::ref(engineInit); } -SwEngine* SwEngine::inst() +SwRenderer* SwRenderer::inst() { - return dynamic_cast(RasterMethodInit::inst(engineInit)); + return dynamic_cast(RenderMethodInit::inst(engineInit)); } -#endif /* _TVG_SW_ENGINE_CPP_ */ +#endif /* _TVG_SW_RENDERER_CPP_ */ diff --git a/src/lib/sw_engine/tvgSwEngine.h b/src/lib/sw_engine/tvgSwRenderer.h similarity index 82% rename from src/lib/sw_engine/tvgSwEngine.h rename to src/lib/sw_engine/tvgSwRenderer.h index dd2d4015..13f4f278 100644 --- a/src/lib/sw_engine/tvgSwEngine.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -14,10 +14,10 @@ * limitations under the License. * */ -#ifndef _TVG_SW_ENGINE_H_ -#define _TVG_SW_ENGINE_H_ +#ifndef _TVG_SW_RENDERER_H_ +#define _TVG_SW_RENDERER_H_ -class SwEngine : public RasterMethod +class SwRenderer : public RenderMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; @@ -25,13 +25,13 @@ public: size_t ref() override; size_t unref() override; - static SwEngine* inst(); + static SwRenderer* inst(); static int init(); static int term(); private: - SwEngine(){}; - ~SwEngine(){}; + SwRenderer(){}; + ~SwRenderer(){}; }; -#endif /* _TVG_SW_ENGINE_H_ */ +#endif /* _TVG_SW_RENDERER_H_ */ diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index 3ec6c7ab..89476ad6 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -26,17 +26,17 @@ struct CanvasBase { vector nodes; - RasterMethod* raster; + RenderMethod* renderer; - CanvasBase(RasterMethod *pRaster):raster(pRaster) + CanvasBase(RenderMethod *pRenderer):renderer(pRenderer) { - raster->ref(); + renderer->ref(); } ~CanvasBase() { clear(); - raster->unref(); + renderer->unref(); } int reserve(size_t n) @@ -49,7 +49,7 @@ struct CanvasBase int clear() { for (auto node : nodes) { - node->dispose(raster); + node->dispose(renderer); delete(node); } nodes.clear(); @@ -67,11 +67,11 @@ struct CanvasBase if (SceneNode *scene = dynamic_cast(node)) { } else if (ShapeNode *shape = dynamic_cast(node)) { - return shape->update(raster); + return shape->update(renderer); } #else if (ShapeNode *shape = dynamic_cast(node)) { - return shape->update(raster); + return shape->update(renderer); } #endif cout << "What type of PaintNode? = " << node << endl; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index fe2d8e21..d7d1d4da 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -29,24 +29,24 @@ using namespace tvg; namespace tvg { -class RasterMethod +class RenderMethod { public: enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; - virtual ~RasterMethod() {} + virtual ~RenderMethod() {} virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; virtual void* dispose(const ShapeNode& shape, void *data) = 0; virtual size_t ref() = 0; virtual size_t unref() = 0; }; -struct RasterMethodInit +struct RenderMethodInit { - RasterMethod* pInst = nullptr; + RenderMethod* pInst = nullptr; size_t refCnt = 0; bool initted = false; - static int init(RasterMethodInit& initter, RasterMethod* engine) + static int init(RenderMethodInit& initter, RenderMethod* engine) { assert(engine); if (initter.pInst || initter.refCnt > 0) return -1; @@ -56,7 +56,7 @@ struct RasterMethodInit return 0; } - static int term(RasterMethodInit& initter) + static int term(RenderMethodInit& initter) { if (!initter.pInst || !initter.initted) return -1; @@ -70,7 +70,7 @@ struct RasterMethodInit return 0; } - static size_t unref(RasterMethodInit& initter) + static size_t unref(RenderMethodInit& initter) { assert(initter.refCnt > 0); --initter.refCnt; @@ -85,13 +85,13 @@ struct RasterMethodInit return initter.refCnt; } - static RasterMethod* inst(RasterMethodInit& initter) + static RenderMethod* inst(RenderMethodInit& initter) { assert(initter.pInst); return initter.pInst; } - static size_t ref(RasterMethodInit& initter) + static size_t ref(RenderMethodInit& initter) { return ++initter.refCnt; } diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index d99ee2d2..fa005dc0 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -18,8 +18,8 @@ #define _TVG_ENGINE_CPP_ #include "tvgCommon.h" -#include "tvgSwEngine.h" -#include "tvgGlEngine.h" +#include "tvgSwRenderer.h" +#include "tvgGlRenderer.h" /************************************************************************/ /* Internal Class Implementation */ @@ -35,8 +35,8 @@ int Engine::init() noexcept //TODO: Initialize Raster engines by configuration. int ret = 0; - ret |= SwEngine::init(); - ret |= GlEngine::init(); + ret |= SwRenderer::init(); + ret |= GlRenderer::init(); return ret; } @@ -45,8 +45,8 @@ int Engine::init() noexcept int Engine::term() noexcept { int ret = 0; - ret |= SwEngine::term(); - ret |= GlEngine::term(); + ret |= SwRenderer::term(); + ret |= GlRenderer::term(); return ret; } diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 7fb9a283..619ea4b0 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -19,7 +19,7 @@ #include "tvgCommon.h" #include "tvgCanvasBase.h" -#include "tvgGlEngine.h" +#include "tvgGlRenderer.h" /************************************************************************/ /* Internal Class Implementation */ @@ -27,7 +27,7 @@ struct GlCanvas::Impl : CanvasBase { - Impl() : CanvasBase(GlEngine::inst()) {} + Impl() : CanvasBase(GlRenderer::inst()) {} }; @@ -76,11 +76,11 @@ int GlCanvas::update() noexcept } -RasterMethod* GlCanvas::engine() noexcept +RenderMethod* GlCanvas::engine() noexcept { auto impl = pImpl.get(); assert(impl); - return impl->raster; + return impl->renderer; } #endif /* _TVG_GLCANVAS_CPP_ */ diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp index 93a9b211..9c7d11fe 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgSceneNode.cpp @@ -58,14 +58,14 @@ int SceneNode :: push(unique_ptr shape) noexcept } -int SceneNode :: dispose(RasterMethod* engine) noexcept +int SceneNode :: dispose(RenderMethod* engine) noexcept { return 0; } -int SceneNode :: update(RasterMethod* engine) noexcept +int SceneNode :: update(RenderMethod* engine) noexcept { return 0; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index f17021a2..74dae239 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -84,7 +84,7 @@ unique_ptr ShapeNode::gen() noexcept } -int ShapeNode :: dispose(RasterMethod* engine) noexcept +int ShapeNode :: dispose(RenderMethod* engine) noexcept { auto impl = pImpl.get(); assert(impl); @@ -95,12 +95,12 @@ int ShapeNode :: dispose(RasterMethod* engine) noexcept } -int ShapeNode :: update(RasterMethod* engine) noexcept +int ShapeNode :: update(RenderMethod* engine) noexcept { auto impl = pImpl.get(); assert(impl); - impl->edata = engine->prepare(*this, impl->edata, RasterMethod::UpdateFlag::All); + impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All); if (impl->edata) return 0; return - 1; } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index e85275f4..4d930a71 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -19,7 +19,7 @@ #include "tvgCommon.h" #include "tvgCanvasBase.h" -#include "tvgSwEngine.h" +#include "tvgSwRenderer.h" /************************************************************************/ @@ -32,7 +32,7 @@ struct SwCanvas::Impl : CanvasBase int stride = 0; int height = 0; - Impl() : CanvasBase(SwEngine::inst()) {} + Impl() : CanvasBase(SwRenderer::inst()) {} }; @@ -111,11 +111,11 @@ int SwCanvas::update() noexcept } -RasterMethod* SwCanvas::engine() noexcept +RenderMethod* SwCanvas::engine() noexcept { auto impl = pImpl.get(); assert(impl); - return impl->raster; + return impl->renderer; } #endif /* _TVG_SWCANVAS_CPP_ */ From 7097940c225170ec763cfdc567a820236657f1f9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 18 Apr 2020 23:07:15 +0900 Subject: [PATCH 013/244] code refactoring. revise internal class & variable names for better code readibility. Change-Id: I7f1b4474f3129c3be04444350496485f000afd15 --- src/lib/gl_engine/tvgGlRenderer.cpp | 12 +++---- src/lib/sw_engine/tvgSwRenderer.cpp | 12 +++---- src/lib/tvgCommon.h | 52 ++++++++++++++--------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 92f00dd6..23575397 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -24,7 +24,7 @@ /* Internal Class Implementation */ /************************************************************************/ -static RenderMethodInit engineInit; +static RenderInitializer renderInit; struct GlShape { @@ -58,31 +58,31 @@ void* GlRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) int GlRenderer::init() { - return RenderMethodInit::init(engineInit, new GlRenderer); + return RenderInitializer::init(renderInit, new GlRenderer); } int GlRenderer::term() { - return RenderMethodInit::term(engineInit); + return RenderInitializer::term(renderInit); } size_t GlRenderer::unref() { - return RenderMethodInit::unref(engineInit); + return RenderInitializer::unref(renderInit); } size_t GlRenderer::ref() { - return RenderMethodInit::ref(engineInit); + return RenderInitializer::ref(renderInit); } GlRenderer* GlRenderer::inst() { - return dynamic_cast(RenderMethodInit::inst(engineInit)); + return dynamic_cast(RenderInitializer::inst(renderInit)); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index a4f126d9..0e09da6b 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -24,7 +24,7 @@ /* Internal Class Implementation */ /************************************************************************/ -static RenderMethodInit engineInit; +static RenderInitializer renderInit; /************************************************************************/ @@ -70,31 +70,31 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) int SwRenderer::init() { - return RenderMethodInit::init(engineInit, new SwRenderer); + return RenderInitializer::init(renderInit, new SwRenderer); } int SwRenderer::term() { - return RenderMethodInit::term(engineInit); + return RenderInitializer::term(renderInit); } size_t SwRenderer::unref() { - return RenderMethodInit::unref(engineInit); + return RenderInitializer::unref(renderInit); } size_t SwRenderer::ref() { - return RenderMethodInit::ref(engineInit); + return RenderInitializer::ref(renderInit); } SwRenderer* SwRenderer::inst() { - return dynamic_cast(RenderMethodInit::inst(engineInit)); + return dynamic_cast(RenderInitializer::inst(renderInit)); } diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index d7d1d4da..90e1b9f5 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -40,60 +40,60 @@ public: virtual size_t unref() = 0; }; -struct RenderMethodInit +struct RenderInitializer { RenderMethod* pInst = nullptr; size_t refCnt = 0; - bool initted = false; + bool initialized = false; - static int init(RenderMethodInit& initter, RenderMethod* engine) + static int init(RenderInitializer& renderInit, RenderMethod* engine) { assert(engine); - if (initter.pInst || initter.refCnt > 0) return -1; - initter.pInst = engine; - initter.refCnt = 0; - initter.initted = true; + if (renderInit.pInst || renderInit.refCnt > 0) return -1; + renderInit.pInst = engine; + renderInit.refCnt = 0; + renderInit.initialized = true; return 0; } - static int term(RenderMethodInit& initter) + static int term(RenderInitializer& renderInit) { - if (!initter.pInst || !initter.initted) return -1; + if (!renderInit.pInst || !renderInit.initialized) return -1; - initter.initted = false; + renderInit.initialized = false; //Still it's refered.... - if (initter.refCnt > 0) return 0; - delete(initter.pInst); - initter.pInst = nullptr; + if (renderInit.refCnt > 0) return 0; + delete(renderInit.pInst); + renderInit.pInst = nullptr; return 0; } - static size_t unref(RenderMethodInit& initter) + static size_t unref(RenderInitializer& renderInit) { - assert(initter.refCnt > 0); - --initter.refCnt; + assert(renderInit.refCnt > 0); + --renderInit.refCnt; //engine has been requested to termination - if (!initter.initted && initter.refCnt == 0) { - if (initter.pInst) { - delete(initter.pInst); - initter.pInst = nullptr; + if (!renderInit.initialized && renderInit.refCnt == 0) { + if (renderInit.pInst) { + delete(renderInit.pInst); + renderInit.pInst = nullptr; } } - return initter.refCnt; + return renderInit.refCnt; } - static RenderMethod* inst(RenderMethodInit& initter) + static RenderMethod* inst(RenderInitializer& renderInit) { - assert(initter.pInst); - return initter.pInst; + assert(renderInit.pInst); + return renderInit.pInst; } - static size_t ref(RenderMethodInit& initter) + static size_t ref(RenderInitializer& renderInit) { - return ++initter.refCnt; + return ++renderInit.refCnt; } }; From b2de30ba48c83a4a97b8970f0dc8609f897c6463 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 18 Apr 2020 23:21:22 +0900 Subject: [PATCH 014/244] code refactoring. separate Renderer interfaces to RenderCommon. Change-Id: I682b20db6cc8a058efee7dd4f519277d86306153 --- src/lib/meson.build | 1 + src/lib/tvgCommon.h | 75 +------------------------------ src/lib/tvgRenderCommon.h | 94 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 74 deletions(-) create mode 100644 src/lib/tvgRenderCommon.h diff --git a/src/lib/meson.build b/src/lib/meson.build index b2243fe7..ffecb2a5 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -3,6 +3,7 @@ subdir('gl_engine') source_file = [ 'tvgCommon.h', + 'tvgRenderCommon.h', 'tvgEngine.cpp', 'tvgCanvasBase.h', 'tvgShapePath.h', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 90e1b9f5..1a4a0d0d 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -22,82 +22,9 @@ #include #include #include "tizenvg.h" +#include "tvgRenderCommon.h" using namespace std; using namespace tvg; -namespace tvg -{ - -class RenderMethod -{ -public: - enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; - virtual ~RenderMethod() {} - virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; - virtual void* dispose(const ShapeNode& shape, void *data) = 0; - virtual size_t ref() = 0; - virtual size_t unref() = 0; -}; - -struct RenderInitializer -{ - RenderMethod* pInst = nullptr; - size_t refCnt = 0; - bool initialized = false; - - static int init(RenderInitializer& renderInit, RenderMethod* engine) - { - assert(engine); - if (renderInit.pInst || renderInit.refCnt > 0) return -1; - renderInit.pInst = engine; - renderInit.refCnt = 0; - renderInit.initialized = true; - return 0; - } - - static int term(RenderInitializer& renderInit) - { - if (!renderInit.pInst || !renderInit.initialized) return -1; - - renderInit.initialized = false; - - //Still it's refered.... - if (renderInit.refCnt > 0) return 0; - delete(renderInit.pInst); - renderInit.pInst = nullptr; - - return 0; - } - - static size_t unref(RenderInitializer& renderInit) - { - assert(renderInit.refCnt > 0); - --renderInit.refCnt; - - //engine has been requested to termination - if (!renderInit.initialized && renderInit.refCnt == 0) { - if (renderInit.pInst) { - delete(renderInit.pInst); - renderInit.pInst = nullptr; - } - } - return renderInit.refCnt; - } - - static RenderMethod* inst(RenderInitializer& renderInit) - { - assert(renderInit.pInst); - return renderInit.pInst; - } - - static size_t ref(RenderInitializer& renderInit) - { - return ++renderInit.refCnt; - } - -}; - -} - #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h new file mode 100644 index 00000000..e06f1ace --- /dev/null +++ b/src/lib/tvgRenderCommon.h @@ -0,0 +1,94 @@ +/* + * 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_RENDER_COMMON_H_ +#define _TVG_RENDER_COMMON_H_ + +namespace tvg +{ + +class RenderMethod +{ +public: + enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; + virtual ~RenderMethod() {} + virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; + virtual void* dispose(const ShapeNode& shape, void *data) = 0; + virtual size_t ref() = 0; + virtual size_t unref() = 0; +}; + +struct RenderInitializer +{ + RenderMethod* pInst = nullptr; + size_t refCnt = 0; + bool initialized = false; + + static int init(RenderInitializer& renderInit, RenderMethod* engine) + { + assert(engine); + if (renderInit.pInst || renderInit.refCnt > 0) return -1; + renderInit.pInst = engine; + renderInit.refCnt = 0; + renderInit.initialized = true; + return 0; + } + + static int term(RenderInitializer& renderInit) + { + if (!renderInit.pInst || !renderInit.initialized) return -1; + + renderInit.initialized = false; + + //Still it's refered.... + if (renderInit.refCnt > 0) return 0; + delete(renderInit.pInst); + renderInit.pInst = nullptr; + + return 0; + } + + static size_t unref(RenderInitializer& renderInit) + { + assert(renderInit.refCnt > 0); + --renderInit.refCnt; + + //engine has been requested to termination + if (!renderInit.initialized && renderInit.refCnt == 0) { + if (renderInit.pInst) { + delete(renderInit.pInst); + renderInit.pInst = nullptr; + } + } + return renderInit.refCnt; + } + + static RenderMethod* inst(RenderInitializer& renderInit) + { + assert(renderInit.pInst); + return renderInit.pInst; + } + + static size_t ref(RenderInitializer& renderInit) + { + return ++renderInit.refCnt; + } + +}; + +} + +#endif //_TVG_RENDER_COMMON_H_ From 75f2bc5f38c8d6a62ae55b2d9a24ed1de3c6f292 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 19 Apr 2020 11:13:28 +0900 Subject: [PATCH 015/244] sw_engine: optimization++ Adjust rle span generation size to reduce memory allocation. This span growing is experimentally increased, undeterministic. Thus We need too increase them every requests, if we increase their size x 4, we can avoid a lot of memory copy in advance. Change-Id: Idd24024204a69fa3b6857728b95aa63a3ac26c5e --- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 25b9c03a..1d3d4987 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -145,9 +145,9 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count) /* alloc is required to prevent free and reallocation */ /* when the rle needs to be regenerated because of attribute change. */ if (rle->alloc < newSize) { - rle->spans = static_cast(realloc(rle->spans, newSize * sizeof(SwSpan))); + rle->spans = static_cast(realloc(rle->spans, (count + rle->size) << 2 * sizeof(SwSpan))); assert(rle->spans); - rle->alloc = newSize; + rle->alloc = rle->size + (count << 2); } //copy the new spans to the allocated memory From 2628a5a9358fe9b79acba133725ece7b632a255a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 19 Apr 2020 11:55:19 +0900 Subject: [PATCH 016/244] sw_engine: tag one optimization point for future work. Change-Id: Ib41b18c097d24636efbba633972e1c8b7f9a63ef --- src/lib/sw_engine/tvgSwRle.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 1d3d4987..49d6238a 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -228,17 +228,16 @@ static void _sweep(RleWorker& rw) rw.spansCnt = 0; for (int y = 0; y < rw.yCnt; ++y) { - auto cover = 0; auto x = 0; auto cell = rw.yCells[y]; while (cell) { - _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); cover += cell->cover; auto area = cover * (ONE_PIXEL * 2) - cell->area; + //OPTIMIZE ME: This occurs 1 length span data. if (area != 0 && cell->x >= 0) _horizLine(rw, cell->x, y, area, 1); From 69f2fb49654ffd19dc1ae7f708ca360aba959894 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 19 Apr 2020 12:17:48 +0900 Subject: [PATCH 017/244] test: update test code for the first showcase. To show the result, we use efl library. Most linux distribution supports efl library from their package repo, you can easily install efl from its package repo: Ubuntu: $ apt-get install libelementary-dev Or, please visit efl site to install EFL libarary manually: https://www.enlightenment.org/download Change-Id: I696ac72e4ec7ea3258161a15b58171d74c16830d --- test/makefile | 2 +- test/testShape.cpp | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/test/makefile b/test/makefile index 5fdc45c4..7b242a39 100644 --- a/test/makefile +++ b/test/makefile @@ -1,2 +1,2 @@ all: - gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs tizenvg` + gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testShape.cpp b/test/testShape.cpp index d1da21e7..4ee2ad7e 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -7,7 +8,7 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -int main(int argc, char **argv) +void tvgtest() { //Initialize TizenVG Engine tvg::Engine::init(); @@ -32,3 +33,27 @@ int main(int argc, char **argv) //Terminate TizenVG Engine tvg::Engine::term(); } + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + + 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 37d34eeb19c22f5944ad843e2179dee4b94f0abd Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 19 Apr 2020 13:13:27 +0900 Subject: [PATCH 018/244] sw_engine: concrete shape rendering sequence. Succeed first sw backend screen up! Change-Id: I882fb1726ed1f45e92e73fbc36170e93645dfbd2 --- inc/tizenvg.h | 11 +++--- src/lib/gl_engine/tvgGlRenderer.cpp | 23 +++++++++-- src/lib/gl_engine/tvgGlRenderer.h | 3 +- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwCommon.h | 2 + src/lib/sw_engine/tvgSwRaster.cpp | 42 ++++++++++++++++++++ src/lib/sw_engine/tvgSwRenderer.cpp | 39 ++++++++++++++++-- src/lib/sw_engine/tvgSwRenderer.h | 6 ++- src/lib/tvgCanvasBase.h | 61 ++++++++++++++++++----------- src/lib/tvgGlCanvas.cpp | 13 +++++- src/lib/tvgRenderCommon.h | 11 +++++- src/lib/tvgSceneNode.cpp | 15 ++----- src/lib/tvgShapeNode.cpp | 23 +++++------ src/lib/tvgSwCanvas.cpp | 17 ++++---- test/testShape.cpp | 2 +- 15 files changed, 193 insertions(+), 76 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwRaster.cpp diff --git a/inc/tizenvg.h b/inc/tizenvg.h index dd125b52..24f2d3f5 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -56,8 +56,7 @@ class RenderMethod; struct Point { - float x; - float y; + float x, y; }; @@ -73,7 +72,6 @@ class TIZENVG_EXPORT PaintNode { public: virtual ~PaintNode() {} - virtual int dispose(RenderMethod* engine) = 0; virtual int update(RenderMethod* engine) = 0; }; @@ -91,7 +89,6 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode public: ~ShapeNode(); - int dispose(RenderMethod* engine) noexcept override; int update(RenderMethod* engine) noexcept override; int clear() noexcept; @@ -106,6 +103,9 @@ public: static std::unique_ptr gen() noexcept; + //FIXME: Ugly... Better design? + void *engine() noexcept; + _TIZENVG_DECLARE_PRIVATE(ShapeNode); }; @@ -123,7 +123,6 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode public: ~SceneNode(); - int dispose(RenderMethod* engine) noexcept override; int update(RenderMethod* engine) noexcept override; int push(std::unique_ptr shape) noexcept; @@ -181,7 +180,7 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. int update() noexcept; - int draw(bool async = true) noexcept { return 0; } + int draw(bool async = true) noexcept; int sync() noexcept { return 0; } RenderMethod* engine() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 23575397..38fb4dee 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -35,12 +35,26 @@ struct GlShape /* External Class Implementation */ /************************************************************************/ -void* GlRenderer::dispose(const ShapeNode& shape, void *data) +bool GlRenderer::render(const ShapeNode& shape, void *data) { GlShape* sdata = static_cast(data); - if (!sdata) return nullptr; + if (!sdata) return false; + + //TODO: + + return true; +} + + +bool GlRenderer::dispose(const ShapeNode& shape, void *data) +{ + GlShape* sdata = static_cast(data); + if (!sdata) return false; + + //TODO: + free(sdata); - return nullptr; + return true; } @@ -52,6 +66,9 @@ void* GlRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) sdata = static_cast(calloc(1, sizeof(GlShape))); assert(sdata); } + + //TODO: + return sdata; } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 534969a1..881d1efa 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -24,7 +24,8 @@ class GlRenderer : public RenderMethod { public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - void* dispose(const ShapeNode& shape, void *data) override; + bool dispose(const ShapeNode& shape, void *data) override; + bool render(const ShapeNode& shape, void *data) override; size_t ref() override; size_t unref() override; diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index 4edd4895..a33059dc 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -4,6 +4,7 @@ source_file = [ 'tvgSwRenderer.cpp', 'tvgSwShape.cpp', 'tvgSwRle.cpp', + 'tvgSwRaster.cpp', ] swraster_dep = declare_dependency( diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4e75e3cd..4b6f8203 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -95,4 +95,6 @@ bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata); +bool rasterShape(Surface& surface, SwShape& sdata, size_t color); + #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp new file mode 100644 index 00000000..2e43a44b --- /dev/null +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -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_SW_RASTER_CPP_ +#define _TVG_SW_RASTER_CPP_ + +#include "tvgSwCommon.h" + + +bool rasterShape(Surface& surface, SwShape& sdata, size_t color) +{ + SwRleData* rle = sdata.rle; + assert(rle); + + auto stride = surface.stride; + auto span = rle->spans; + + for (size_t i = 0; i < rle->size; ++i) { + assert(span); + for (auto j = 0; j < span->len; ++j) { + surface.buffer[span->y * stride + span->x + j] = color; + } + ++span; + } + + return true; +} + +#endif /* _TVG_SW_RASTER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 0e09da6b..425afaba 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -26,18 +26,49 @@ static RenderInitializer renderInit; +static inline size_t COLOR(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (a << 24 | r << 16 | g << 8 | b); +} /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -void* SwRenderer::dispose(const ShapeNode& shape, void *data) +bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t height) +{ + assert(buffer && stride > 0 && height > 0); + + surface.buffer = buffer; + surface.stride = stride; + surface.height = height; + + return true; +} + + +bool SwRenderer::render(const ShapeNode& shape, void *data) { SwShape* sdata = static_cast(data); - if (!sdata) return nullptr; + if (!sdata) return false; + + //invisible? + size_t r, g, b, a; + shape.fill(&r, &g, &b, &a); + if (a == 0) return true; + + //TODO: Threading + return rasterShape(surface, *sdata, COLOR(r, g, b, a)); +} + + +bool SwRenderer::dispose(const ShapeNode& shape, void *data) +{ + SwShape* sdata = static_cast(data); + if (!sdata) return false; shapeReset(*sdata); free(sdata); - return nullptr; + return true; } void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) @@ -56,10 +87,10 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) shape.fill(nullptr, nullptr, nullptr, &alpha); if (alpha == 0) return sdata; + //TODO: Threading if (flags & UpdateFlag::Path) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; - //TODO: From below sequence starts threading? if (!shapeTransformOutline(shape, *sdata)) return sdata; if (!shapeGenRle(shape, *sdata)) return sdata; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 13f4f278..f8ce1d4b 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -20,8 +20,12 @@ class SwRenderer : public RenderMethod { public: + Surface surface; + void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - void* dispose(const ShapeNode& shape, void *data) override; + bool dispose(const ShapeNode& shape, void *data) override; + bool render(const ShapeNode& shape, void *data) override; + bool target(uint32_t* buffer, size_t stride, size_t height); size_t ref() override; size_t unref() override; diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index 89476ad6..a2ed34b9 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -19,9 +19,6 @@ #include "tvgCommon.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct CanvasBase { @@ -48,42 +45,60 @@ struct CanvasBase int clear() { + assert(renderer); + + auto ret = 0; + for (auto node : nodes) { - node->dispose(renderer); + if (SceneNode *scene = dynamic_cast(node)) { + cout << "TODO: " << scene << endl; + } else if (ShapeNode *shape = dynamic_cast(node)) { + ret |= renderer->dispose(*shape, shape->engine()); + } delete(node); } nodes.clear(); - return 0; + return ret; + } + + int update() + { + assert(renderer); + + auto ret = 0; + + for(auto node: nodes) { + ret |= node->update(renderer); + } + + return ret; } int push(unique_ptr paint) { PaintNode *node = paint.release(); assert(node); - nodes.push_back(node); -#if 0 - if (SceneNode *scene = dynamic_cast(node)) { + return node->update(renderer); + } - } else if (ShapeNode *shape = dynamic_cast(node)) { - return shape->update(renderer); - } -#else - if (ShapeNode *shape = dynamic_cast(node)) { - return shape->update(renderer); - } -#endif - cout << "What type of PaintNode? = " << node << endl; + int draw() + { + assert(renderer); - return -1; + auto ret = 0; + + for(auto node: nodes) { + if (SceneNode *scene = dynamic_cast(node)) { + cout << "TODO: " << scene << endl; + } else if (ShapeNode *shape = dynamic_cast(node)) { + ret |= renderer->render(*shape, shape->engine()); + } + } + return ret; } }; - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - #endif /* _TVG_CANVAS_BASE_CPP_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 619ea4b0..386778d7 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -42,7 +42,6 @@ GlCanvas::GlCanvas() : pImpl(make_unique()) GlCanvas::~GlCanvas() { - cout << "GlCanvas(" << this << ") destroyed!" << endl; } @@ -72,7 +71,9 @@ int GlCanvas::clear() noexcept int GlCanvas::update() noexcept { - return 0; + auto impl = pImpl.get(); + assert(impl); + return impl->update(); } @@ -83,4 +84,12 @@ RenderMethod* GlCanvas::engine() noexcept return impl->renderer; } + +int GlCanvas::draw(bool async) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->draw(); +} + #endif /* _TVG_GLCANVAS_CPP_ */ diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index e06f1ace..acdfc2fd 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -20,13 +20,22 @@ namespace tvg { +struct Surface +{ + //TODO: Union for multiple types + uint32_t* buffer; + size_t stride; + size_t height; +}; + class RenderMethod { public: enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RenderMethod() {} virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; - virtual void* dispose(const ShapeNode& shape, void *data) = 0; + virtual bool dispose(const ShapeNode& shape, void *data) = 0; + virtual bool render(const ShapeNode& shape, void *data) = 0; virtual size_t ref() = 0; virtual size_t unref() = 0; }; diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp index 9c7d11fe..db3ae1d8 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgSceneNode.cpp @@ -34,13 +34,13 @@ struct SceneNode::Impl /* External Class Implementation */ /************************************************************************/ -SceneNode :: SceneNode() : pImpl(make_unique()) +SceneNode::SceneNode() : pImpl(make_unique()) { } -SceneNode :: ~SceneNode() +SceneNode::~SceneNode() { cout << "SceneNode(" << this << ") destroyed!" << endl; } @@ -52,20 +52,13 @@ unique_ptr SceneNode::gen() noexcept } -int SceneNode :: push(unique_ptr shape) noexcept +int SceneNode::push(unique_ptr shape) noexcept { return 0; } -int SceneNode :: dispose(RenderMethod* engine) noexcept -{ - - return 0; -} - - -int SceneNode :: update(RenderMethod* engine) noexcept +int SceneNode::update(RenderMethod* engine) noexcept { return 0; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 74dae239..2c15b1bc 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -84,18 +84,15 @@ unique_ptr ShapeNode::gen() noexcept } -int ShapeNode :: dispose(RenderMethod* engine) noexcept +void* ShapeNode::engine() noexcept { auto impl = pImpl.get(); assert(impl); - - impl->edata = engine->dispose(*this, impl->edata); - if (impl->edata) return -1; - return 0; + return impl->edata; } -int ShapeNode :: update(RenderMethod* engine) noexcept +int ShapeNode::update(RenderMethod* engine) noexcept { auto impl = pImpl.get(); assert(impl); @@ -106,7 +103,7 @@ int ShapeNode :: update(RenderMethod* engine) noexcept } -int ShapeNode :: clear() noexcept +int ShapeNode::clear() noexcept { auto impl = pImpl.get(); assert(impl); @@ -115,7 +112,7 @@ int ShapeNode :: clear() noexcept } -int ShapeNode :: pathCommands(const PathCommand** cmds) const noexcept +int ShapeNode::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); assert(impl && cmds); @@ -126,7 +123,7 @@ int ShapeNode :: pathCommands(const PathCommand** cmds) const noexcept } -int ShapeNode :: pathCoords(const Point** pts) const noexcept +int ShapeNode::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); assert(impl && pts); @@ -137,13 +134,13 @@ int ShapeNode :: pathCoords(const Point** pts) const noexcept } -int ShapeNode :: appendCircle(float cx, float cy, float radius) noexcept +int ShapeNode::appendCircle(float cx, float cy, float radius) noexcept { return 0; } -int ShapeNode :: appendRect(float x, float y, float w, float h, float radius) noexcept +int ShapeNode::appendRect(float x, float y, float w, float h, float radius) noexcept { auto impl = pImpl.get(); assert(impl); @@ -171,7 +168,7 @@ int ShapeNode :: appendRect(float x, float y, float w, float h, float radius) no } -int ShapeNode :: fill(size_t r, size_t g, size_t b, size_t a) noexcept +int ShapeNode::fill(size_t r, size_t g, size_t b, size_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -185,7 +182,7 @@ int ShapeNode :: fill(size_t r, size_t g, size_t b, size_t a) noexcept } -int ShapeNode :: fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int ShapeNode::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 4d930a71..442b0d7c 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -28,10 +28,6 @@ struct SwCanvas::Impl : CanvasBase { - uint32_t* buffer = nullptr; - int stride = 0; - int height = 0; - Impl() : CanvasBase(SwRenderer::inst()) {} }; @@ -45,9 +41,7 @@ int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept auto impl = pImpl.get(); assert(impl); - impl->buffer = buffer; - impl->stride = stride; - impl->height = height; + dynamic_cast(impl->renderer)->target(buffer, stride, height); return 0; } @@ -55,7 +49,9 @@ int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept int SwCanvas::draw(bool async) noexcept { - return 0; + auto impl = pImpl.get(); + assert(impl); + return impl->draw(); } @@ -89,7 +85,6 @@ SwCanvas::SwCanvas() : pImpl(make_unique()) SwCanvas::~SwCanvas() { - cout << "SwCanvas(" << this << ") destroyed!" << endl; } @@ -107,7 +102,9 @@ unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t heigh int SwCanvas::update() noexcept { - return 0; + auto impl = pImpl.get(); + assert(impl); + return impl->update(); } diff --git a/test/testShape.cpp b/test/testShape.cpp index 4ee2ad7e..e42cba80 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -19,7 +19,7 @@ void tvgtest() //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius - shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->fill(255, 0, 0, 255); //r, g, b, a /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare From fe9c2c9162f6aa2eea4ddaf1b138aee699642374 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 25 Apr 2020 21:40:40 +0900 Subject: [PATCH 019/244] common shape: implement appendCircle body. Change-Id: Ib8507366f84532db3119f04c8d55e0d4e8206f9f --- inc/tizenvg.h | 2 +- meson.build | 2 +- src/lib/sw_engine/tvgSwRle.cpp | 8 +- src/lib/tvgCommon.h | 1 + src/lib/tvgShapeNode.cpp | 19 ++- src/lib/tvgShapePath.h | 246 ++++++++++++++++++++++++++++++++- test/makefile | 1 + test/testMultipleShapes.cpp | 36 ++++- 8 files changed, 293 insertions(+), 22 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 24f2d3f5..64c8ee47 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -92,7 +92,7 @@ public: int update(RenderMethod* engine) noexcept override; int clear() noexcept; - int appendRect(float x, float y, float w, float h, float radius) noexcept; + int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; int appendCircle(float cx, float cy, float radius) noexcept; int fill(size_t r, size_t g, size_t b, size_t a) noexcept; diff --git a/meson.build b/meson.build index 32dd23be..5692fbce 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('tizenvg', 'cpp', - default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14'], + default_options : ['buildtype=debug', 'werror=false', 'cpp_std=c++14'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 49d6238a..4542567a 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -417,7 +417,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) auto py = diff.y * ONE_PIXEL; //left - if (prod <= 0 && prod - px) { + if (prod <= 0 && prod - px > 0) { f2 = {0, SW_UDIV(-prod, -dx_r)}; prod -= py; rw.cover += (f2.y - f1.y); @@ -557,9 +557,7 @@ static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, draw: _lineTo(rw, arc[0]); - if (arc == rw.bezStack) return; - arc -= 3; } } @@ -612,7 +610,7 @@ static bool _decomposeOutline(RleWorker& rw) } //Close the contour with a line segment? - //if (!lineTo(rw, outline->pts[first])); + //_lineTo(rw, UPSCALE(outline->pts[first])); close: first = last + 1; } @@ -680,7 +678,7 @@ SwRleData* rleRender(const SwShape& sdata) rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); assert(rw.rle); - //printf("bufferSize = %d, bbox(%f %f %f %f), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize); + //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.cellMin.x, rw.cellMin.y, rw.cellMax.x, rw.cellMax.y, rw.cellXCnt, rw.cellYCnt, rw.bandSize); //Generate RLE Band bands[BAND_SIZE]; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 1a4a0d0d..2653d3a1 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "tizenvg.h" #include "tvgRenderCommon.h" diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 2c15b1bc..7c4ab2e5 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -136,21 +136,28 @@ int ShapeNode::pathCoords(const Point** pts) const noexcept int ShapeNode::appendCircle(float cx, float cy, float radius) noexcept { + auto impl = pImpl.get(); + assert(impl); + + impl->path->reserve(5, 13); //decide size experimentally (move + curve * 4) + impl->path->arcTo(cx - radius, cy - radius, 2 * radius, 2 * radius, 0, 360); + impl->path->close(); + return 0; } -int ShapeNode::appendRect(float x, float y, float w, float h, float radius) noexcept +int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); assert(impl); - //clamping radius by minimum size + //clamping cornerRadius by minimum size auto min = (w < h ? w : h) * 0.5f; - if (radius > min) radius = min; + if (cornerRadius > min) cornerRadius = min; //rectangle - if (radius == 0) { + if (cornerRadius == 0) { impl->path->reserve(5, 4); impl->path->moveTo(x, y); impl->path->lineTo(x + w, y); @@ -158,8 +165,8 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float radius) noex impl->path->lineTo(x, y + h); impl->path->close(); //circle - } else if (w == h && radius * 2 == w) { - appendCircle(x + (w * 0.5f), y + (h * 0.5f), radius); + } else if (w == h && cornerRadius * 2 == w) { + return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius); } else { //... } diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 0d11cdf4..8c35bbe9 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -23,6 +23,14 @@ /* Internal Class Implementation */ /************************************************************************/ +constexpr auto PATH_KAPPA = 0.552284f; + +struct ShapePath; + +static float _arcAngle(float angle); +static int _arcToCubic(ShapePath& path, const Point* pts, size_t ptsCnt); +static void _findEllipseCoords(float x, float y, float w, float h, float startAngle, float sweepAngle, Point& ptStart, Point& ptEnd); + struct ShapePath { PathCommand* cmds = nullptr; @@ -111,6 +119,145 @@ struct ShapePath return 0; } + + int arcTo(float x, float y, float w, float h, float startAngle, float sweepAngle) + { + if ((fabsf(w) < FLT_EPSILON) || (fabsf(h) < FLT_EPSILON)) return -1; + if (fabsf(sweepAngle) < FLT_EPSILON) return -1; + + if (sweepAngle > 360) sweepAngle = 360; + else if (sweepAngle < -360) sweepAngle = -360; + + auto half_w = w * 0.5f; + auto half_h = h * 0.5f; + auto half_w_kappa = half_w * PATH_KAPPA; + auto half_h_kappa = half_h * PATH_KAPPA; + + //Curves for arc + Point pts[13] { + //start point: 0 degree + {x + w, y + half_h}, + + //0 -> 90 degree + {x + w, y + half_h + half_h_kappa}, + {x + half_w + half_w_kappa, y + h}, + {x + half_w, y + h}, + + //90 -> 180 degree + {x + half_w - half_w_kappa, y + h}, + {x, y + half_h + half_h_kappa}, + {x, y + half_h}, + + //180 -> 270 degree + {x, y + half_h - half_h_kappa}, + {x + half_w - half_w_kappa, y}, + {x + half_w, y}, + + //270 -> 0 degree + {x + half_w + half_w_kappa, y}, + {x + w, y + half_h - half_h_kappa}, + {x + w, y + half_w} + }; + + auto ptsCnt = 1; //one is reserved for the start point + Point curves[13]; + + //perfect circle: special case fast paths + if (fabsf(startAngle) <= FLT_EPSILON) { + if (fabsf(sweepAngle - 360) <= FLT_EPSILON) { + for (int i = 11; i >= 0; --i) { + curves[ptsCnt++] = pts[i]; + } + curves[0] = pts[12]; + return _arcToCubic(*this, curves, ptsCnt); + } else if (fabsf(sweepAngle + 360) <= FLT_EPSILON) { + for (int i = 1; i <= 12; ++i) { + curves[ptsCnt++] = pts[i]; + } + curves[0] = pts[0]; + return _arcToCubic(*this, curves, ptsCnt); + } + } + + auto startSegment = static_cast(floor(startAngle / 90)); + auto endSegment = static_cast(floor((startAngle + sweepAngle) / 90)); + auto startDelta = (startAngle - (startSegment * 90)) / 90; + auto endDelta = ((startAngle + sweepAngle) - (endSegment * 90)) / 90; + auto delta = sweepAngle > 0 ? 1 : -1; + + if (delta < 0) { + startDelta = 1 - startDelta; + endDelta = 1 - endDelta; + } + + //avoid empty start segment + if (fabsf(startDelta - 1) < FLT_EPSILON) { + startDelta = 0; + startSegment += delta; + } + + //avoid empty end segment + if (fabsf(endDelta) < FLT_EPSILON) { + endDelta = 1; + endSegment -= delta; + } + + startDelta = _arcAngle(startDelta * 90); + endDelta = _arcAngle(endDelta * 90); + + auto splitAtStart = (fabsf(startDelta) >= FLT_EPSILON) ? true : false; + auto splitAtEnd = (fabsf(endDelta - 1.0f) >= FLT_EPSILON) ? true : false; + auto end = endSegment + delta; + + //empty arc? + if (startSegment == end) { + auto quadrant = 3 - ((startSegment % 4) + 4) % 4; + auto i = 3 * quadrant; + curves[0] = (delta > 0) ? pts[i + 3] : pts[i]; + return _arcToCubic(*this, curves, ptsCnt); + } + + Point ptStart, ptEnd; + _findEllipseCoords(x, y, w, h, startAngle, sweepAngle, ptStart, ptEnd); + + for (auto i = startSegment; i != end; i += delta) { + //auto quadrant = 3 - ((i % 4) + 4) % 4; + //auto j = 3 * quadrant; + + if (delta > 0) { + //TODO: bezier + } else { + //TODO: bezier + } + + //empty arc? + if (startSegment == endSegment && (fabsf(startDelta - endDelta) < FLT_EPSILON)) { + curves[0] = ptStart; + return _arcToCubic(*this, curves, ptsCnt); + } + + if (i == startSegment) { + if (i == endSegment && splitAtEnd) { + //TODO: bezier + } else if (splitAtStart) { + //TODO: bezier + } + } else if (i == endSegment && splitAtEnd) { + //TODO: bezier + } + + //push control points + //curves[ptsCnt++] = ctrlPt1; + //curves[ptsCnt++] = ctrlPt2; + //curves[ptsCnt++] = endPt; + cout << "ArcTo: Not Implemented!" << endl; + } + + curves[ptsCnt - 1] = ptEnd; + + return _arcToCubic(*this, curves, ptsCnt); + } + int close() { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); @@ -142,8 +289,101 @@ struct ShapePath } }; -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ +static float _arcAngle(float angle) + { + if (angle < FLT_EPSILON) return 0; + if (fabsf(angle - 90) < FLT_EPSILON) return 1; + + auto radian = (angle / 180) * M_PI; + auto cosAngle = cos(radian); + auto sinAngle = sin(radian); + + //initial guess + auto tc = angle / 90; + + /* do some iterations of newton's method to approximate cosAngle + finds the zero of the function b.pointAt(tc).x() - cosAngle */ + tc -= ((((2 - 3 * PATH_KAPPA) * tc + 3 * (PATH_KAPPA - 1)) * tc) * tc + 1 - cosAngle) // value + / (((6 - 9 * PATH_KAPPA) * tc + 6 * (PATH_KAPPA - 1)) * tc); // derivative + tc -= ((((2 - 3 * PATH_KAPPA) * tc + 3 * (PATH_KAPPA - 1)) * tc) * tc + 1 - cosAngle) // value + / (((6 - 9 * PATH_KAPPA) * tc + 6 * (PATH_KAPPA - 1)) * tc); // derivative + + // initial guess + auto ts = tc; + + /* do some iterations of newton's method to approximate sin_angle + finds the zero of the function b.pointAt(tc).y() - sinAngle */ + ts -= ((((3 * PATH_KAPPA - 2) * ts - 6 * PATH_KAPPA + 3) * ts + 3 * PATH_KAPPA) * ts - sinAngle) + / (((9 * PATH_KAPPA - 6) * ts + 12 * PATH_KAPPA - 6) * ts + 3 * PATH_KAPPA); + ts -= ((((3 * PATH_KAPPA - 2) * ts - 6 * PATH_KAPPA + 3) * ts + 3 * PATH_KAPPA) * ts - sinAngle) + / (((9 * PATH_KAPPA - 6) * ts + 12 * PATH_KAPPA - 6) * ts + 3 * PATH_KAPPA); + + //use the average of the t that best approximates cos_angle and the t that best approximates sin_angle + return (0.5 * (tc + ts)); +} + + +static int _arcToCubic(ShapePath& path, const Point* pts, size_t ptsCnt) +{ + assert(pts); + + if (path.cmdCnt > 0 && path.cmds[path.cmdCnt] != PathCommand::Close) { + if (path.lineTo(pts[0].x, pts[0].y)) return -1; + } else { + if (path.moveTo(pts[0].x, pts[0].y)) return -1; + } + + for (size_t i = 1; i < ptsCnt; i += 3) { + if (path.cubicTo(pts[i].x, pts[i].y, pts[i+1].x, pts[i+1].y, pts[i+2].x, pts[i+2].y)) { + return -1; + } + } + + return 0; +} + + +static void _findEllipseCoords(float x, float y, float w, float h, float startAngle, float sweepAngle, Point& ptStart, Point& ptEnd) +{ + float angles[2] = {startAngle, startAngle + sweepAngle}; + float half_w = w * 0.5f; + float half_h = h * 0.5f; + float cx = x + half_w; + float cy = y + half_h; + Point* pts[2] = {&ptStart, &ptEnd}; + + for (auto i = 0; i < 2; ++i) { + auto theta = angles[i] - 360 * floor(angles[i] / 360); + auto t = theta / 90; + auto quadrant = static_cast(t); //truncate + t -= quadrant; + t = _arcAngle(90 * t); + + //swap x and y? + if (quadrant & 1) t = (1 - t); + + //bezier coefficients + auto m = 1 - t; + auto b = m * m; + auto c = t * t; + auto d = c * t; + auto a = b * m; + b *= 3 * t; + c *= 3 * m; + + auto px = a + b + c * PATH_KAPPA; + auto py = d + c + b * PATH_KAPPA; + + //left quadrants + if (quadrant == 1 || quadrant == 2) px = -px; + + //top quadrants + if (quadrant == 0 || quadrant == 1) py = -py; + + pts[i]->x = cx + half_w * px; + pts[i]->y = cy + half_h * py; + } +} + #endif //_TVG_SHAPE_PATH_CPP_ diff --git a/test/makefile b/test/makefile index 7b242a39..00b7d7ff 100644 --- a/test/makefile +++ b/test/makefile @@ -1,2 +1,3 @@ all: gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testMultipleShapes testMultipleShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testMultipleShapes.cpp b/test/testMultipleShapes.cpp index feeb9644..3826f8f7 100644 --- a/test/testMultipleShapes.cpp +++ b/test/testMultipleShapes.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -7,25 +8,25 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -int main(int argc, char **argv) +void tvgtest() { //Initialize TizenVG Engine tvg::Engine::init(); //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - canvas->reserve(2); //reserve 2 shape nodes (optional) + //canvas->reserve(2); //reserve 2 shape nodes (optional) //Prepare Rectangle auto shape1 = tvg::ShapeNode::gen(); - shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius - shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius + shape1->fill(0, 255, 0, 255); //r, g, b, a canvas->push(move(shape1)); //Prepare Circle auto shape2 = tvg::ShapeNode::gen(); - shape2->circle(400, 400, 200); //cx, cy, radius - shape2->fill(255, 255, 0, 255); //r, g, b, a + shape2->appendCircle(400, 400, 200); //cx, cy, radius + shape2->fill(255, 255, 0, 255); //r, g, b, a canvas->push(move(shape2)); //Draw the Shapes onto the Canvas @@ -35,3 +36,26 @@ int main(int argc, char **argv) //Terminate TizenVG Engine tvg::Engine::term(); } + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + + 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From a15e2c9ca09d9765d14e441b4ca409ce07c54e23 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 26 Apr 2020 14:57:14 +0900 Subject: [PATCH 020/244] sw_engine: fix wrong comparison that brings broken shapes. These implementation is still at hot coding, we still need to improve a lot. Change-Id: I61398bff75395ff5e692ca48f4d62243f74bed85 --- src/lib/sw_engine/tvgSwRle.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 4542567a..f17c6845 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -233,7 +233,10 @@ static void _sweep(RleWorker& rw) auto cell = rw.yCells[y]; while (cell) { - _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); + + if (cell->x > x && cover != 0) + _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); + cover += cell->cover; auto area = cover * (ONE_PIXEL * 2) - cell->area; @@ -315,6 +318,7 @@ static void _setCell(RleWorker& rw, SwPoint pos) //Are we moving to a different cell? if (pos != rw.cellPos) { + //Record the current one if it is valid if (!rw.invalid) _recordCell(rw); } @@ -329,6 +333,7 @@ static void _startCell(RleWorker& rw, SwPoint pos) { if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x; + //if (pos.x < rw.cellMin.x) pos.x = (rw.cellMin.x - 1); rw.area = 0; rw.cover = 0; @@ -362,7 +367,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) //vertical clipping if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || - (e1.y < rw.cellMin.y && e2.y >= rw.cellMin.y)) { + (e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) { rw.pos = to; return; } @@ -644,7 +649,7 @@ static bool _genRle(RleWorker& rw) SwRleData* rleRender(const SwShape& sdata) { constexpr auto RENDER_POOL_SIZE = 16384L; - constexpr auto BAND_SIZE = 39; + constexpr auto BAND_SIZE = 40; auto outline = sdata.outline; assert(outline); @@ -687,7 +692,7 @@ SwRleData* rleRender(const SwShape& sdata) /* set up vertical bands */ auto bandCnt = static_cast((rw.cellMax.y - rw.cellMin.y) / rw.bandSize); if (bandCnt == 0) bandCnt = 1; - else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE; + else if (bandCnt >= BAND_SIZE) bandCnt = (BAND_SIZE - 1); auto min = rw.cellMin.y; auto yMax = rw.cellMax.y; From e655471e099702dd18b4bdbcfc07e314ee9a4229 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 26 Apr 2020 15:00:29 +0900 Subject: [PATCH 021/244] common shape: support rounded rectangle. Also remove arcTo implementation since curveTo could covers it. Change-Id: Icc63eca55e51622fc80b57672f308f25f2301f85 --- src/lib/tvgShapeNode.cpp | 24 +++- src/lib/tvgShapePath.h | 243 ------------------------------------ test/testMultipleShapes.cpp | 2 +- test/testShape.cpp | 2 +- test/testStroke.cpp | 2 +- 5 files changed, 24 insertions(+), 249 deletions(-) diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 7c4ab2e5..6ee0b7ae 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -23,6 +23,7 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +constexpr auto PATH_KAPPA = 0.552284f; struct ShapeFill { @@ -139,8 +140,14 @@ int ShapeNode::appendCircle(float cx, float cy, float radius) noexcept auto impl = pImpl.get(); assert(impl); - impl->path->reserve(5, 13); //decide size experimentally (move + curve * 4) - impl->path->arcTo(cx - radius, cy - radius, 2 * radius, 2 * radius, 0, 360); + auto halfKappa = radius * PATH_KAPPA; + + impl->path->reserve(6, 13); + impl->path->moveTo(cx, cy - radius); + impl->path->cubicTo(cx + halfKappa, cy - radius, cx + radius, cy - halfKappa, cx + radius, cy); + impl->path->cubicTo(cx + radius, cy + halfKappa, cx + halfKappa, cy + radius, cx, cy + radius); + impl->path->cubicTo(cx - halfKappa, cy + radius, cx - radius, cy + halfKappa, cx - radius, cy); + impl->path->cubicTo(cx - radius, cy - halfKappa, cx - halfKappa, cy - radius, cx, cy - radius); impl->path->close(); return 0; @@ -168,7 +175,18 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius } else if (w == h && cornerRadius * 2 == w) { return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius); } else { - //... + auto halfKappa = cornerRadius * 0.5; + impl->path->reserve(10, 17); + impl->path->moveTo(x + cornerRadius, y); + impl->path->lineTo(x + w - cornerRadius, y); + impl->path->cubicTo(x + w - cornerRadius + halfKappa, y, x + w, y + cornerRadius - halfKappa, x + w, y + cornerRadius); + impl->path->lineTo(x + w, y + h - cornerRadius); + impl->path->cubicTo(x + w, y + h - cornerRadius + halfKappa, x + w - cornerRadius + halfKappa, y + h, x + w - cornerRadius, y + h); + impl->path->lineTo(x + cornerRadius, y + h); + impl->path->cubicTo(x + cornerRadius - halfKappa, y + h, x, y + h - cornerRadius + halfKappa, x, y + h - cornerRadius); + impl->path->lineTo(x, y + cornerRadius); + impl->path->cubicTo(x, y + cornerRadius - halfKappa, x + cornerRadius - halfKappa, y, x + cornerRadius, y); + impl->path->close(); } return 0; diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 8c35bbe9..6fda0f0d 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -23,14 +23,6 @@ /* Internal Class Implementation */ /************************************************************************/ -constexpr auto PATH_KAPPA = 0.552284f; - -struct ShapePath; - -static float _arcAngle(float angle); -static int _arcToCubic(ShapePath& path, const Point* pts, size_t ptsCnt); -static void _findEllipseCoords(float x, float y, float w, float h, float startAngle, float sweepAngle, Point& ptStart, Point& ptEnd); - struct ShapePath { PathCommand* cmds = nullptr; @@ -120,144 +112,6 @@ struct ShapePath } - int arcTo(float x, float y, float w, float h, float startAngle, float sweepAngle) - { - if ((fabsf(w) < FLT_EPSILON) || (fabsf(h) < FLT_EPSILON)) return -1; - if (fabsf(sweepAngle) < FLT_EPSILON) return -1; - - if (sweepAngle > 360) sweepAngle = 360; - else if (sweepAngle < -360) sweepAngle = -360; - - auto half_w = w * 0.5f; - auto half_h = h * 0.5f; - auto half_w_kappa = half_w * PATH_KAPPA; - auto half_h_kappa = half_h * PATH_KAPPA; - - //Curves for arc - Point pts[13] { - //start point: 0 degree - {x + w, y + half_h}, - - //0 -> 90 degree - {x + w, y + half_h + half_h_kappa}, - {x + half_w + half_w_kappa, y + h}, - {x + half_w, y + h}, - - //90 -> 180 degree - {x + half_w - half_w_kappa, y + h}, - {x, y + half_h + half_h_kappa}, - {x, y + half_h}, - - //180 -> 270 degree - {x, y + half_h - half_h_kappa}, - {x + half_w - half_w_kappa, y}, - {x + half_w, y}, - - //270 -> 0 degree - {x + half_w + half_w_kappa, y}, - {x + w, y + half_h - half_h_kappa}, - {x + w, y + half_w} - }; - - auto ptsCnt = 1; //one is reserved for the start point - Point curves[13]; - - //perfect circle: special case fast paths - if (fabsf(startAngle) <= FLT_EPSILON) { - if (fabsf(sweepAngle - 360) <= FLT_EPSILON) { - for (int i = 11; i >= 0; --i) { - curves[ptsCnt++] = pts[i]; - } - curves[0] = pts[12]; - return _arcToCubic(*this, curves, ptsCnt); - } else if (fabsf(sweepAngle + 360) <= FLT_EPSILON) { - for (int i = 1; i <= 12; ++i) { - curves[ptsCnt++] = pts[i]; - } - curves[0] = pts[0]; - return _arcToCubic(*this, curves, ptsCnt); - } - } - - auto startSegment = static_cast(floor(startAngle / 90)); - auto endSegment = static_cast(floor((startAngle + sweepAngle) / 90)); - auto startDelta = (startAngle - (startSegment * 90)) / 90; - auto endDelta = ((startAngle + sweepAngle) - (endSegment * 90)) / 90; - auto delta = sweepAngle > 0 ? 1 : -1; - - if (delta < 0) { - startDelta = 1 - startDelta; - endDelta = 1 - endDelta; - } - - //avoid empty start segment - if (fabsf(startDelta - 1) < FLT_EPSILON) { - startDelta = 0; - startSegment += delta; - } - - //avoid empty end segment - if (fabsf(endDelta) < FLT_EPSILON) { - endDelta = 1; - endSegment -= delta; - } - - startDelta = _arcAngle(startDelta * 90); - endDelta = _arcAngle(endDelta * 90); - - auto splitAtStart = (fabsf(startDelta) >= FLT_EPSILON) ? true : false; - auto splitAtEnd = (fabsf(endDelta - 1.0f) >= FLT_EPSILON) ? true : false; - auto end = endSegment + delta; - - //empty arc? - if (startSegment == end) { - auto quadrant = 3 - ((startSegment % 4) + 4) % 4; - auto i = 3 * quadrant; - curves[0] = (delta > 0) ? pts[i + 3] : pts[i]; - return _arcToCubic(*this, curves, ptsCnt); - } - - Point ptStart, ptEnd; - _findEllipseCoords(x, y, w, h, startAngle, sweepAngle, ptStart, ptEnd); - - for (auto i = startSegment; i != end; i += delta) { - //auto quadrant = 3 - ((i % 4) + 4) % 4; - //auto j = 3 * quadrant; - - if (delta > 0) { - //TODO: bezier - } else { - //TODO: bezier - } - - //empty arc? - if (startSegment == endSegment && (fabsf(startDelta - endDelta) < FLT_EPSILON)) { - curves[0] = ptStart; - return _arcToCubic(*this, curves, ptsCnt); - } - - if (i == startSegment) { - if (i == endSegment && splitAtEnd) { - //TODO: bezier - } else if (splitAtStart) { - //TODO: bezier - } - } else if (i == endSegment && splitAtEnd) { - //TODO: bezier - } - - //push control points - //curves[ptsCnt++] = ctrlPt1; - //curves[ptsCnt++] = ctrlPt2; - //curves[ptsCnt++] = endPt; - cout << "ArcTo: Not Implemented!" << endl; - } - - curves[ptsCnt - 1] = ptEnd; - - return _arcToCubic(*this, curves, ptsCnt); - } - int close() { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); @@ -289,101 +143,4 @@ struct ShapePath } }; -static float _arcAngle(float angle) - { - if (angle < FLT_EPSILON) return 0; - if (fabsf(angle - 90) < FLT_EPSILON) return 1; - - auto radian = (angle / 180) * M_PI; - auto cosAngle = cos(radian); - auto sinAngle = sin(radian); - - //initial guess - auto tc = angle / 90; - - /* do some iterations of newton's method to approximate cosAngle - finds the zero of the function b.pointAt(tc).x() - cosAngle */ - tc -= ((((2 - 3 * PATH_KAPPA) * tc + 3 * (PATH_KAPPA - 1)) * tc) * tc + 1 - cosAngle) // value - / (((6 - 9 * PATH_KAPPA) * tc + 6 * (PATH_KAPPA - 1)) * tc); // derivative - tc -= ((((2 - 3 * PATH_KAPPA) * tc + 3 * (PATH_KAPPA - 1)) * tc) * tc + 1 - cosAngle) // value - / (((6 - 9 * PATH_KAPPA) * tc + 6 * (PATH_KAPPA - 1)) * tc); // derivative - - // initial guess - auto ts = tc; - - /* do some iterations of newton's method to approximate sin_angle - finds the zero of the function b.pointAt(tc).y() - sinAngle */ - ts -= ((((3 * PATH_KAPPA - 2) * ts - 6 * PATH_KAPPA + 3) * ts + 3 * PATH_KAPPA) * ts - sinAngle) - / (((9 * PATH_KAPPA - 6) * ts + 12 * PATH_KAPPA - 6) * ts + 3 * PATH_KAPPA); - ts -= ((((3 * PATH_KAPPA - 2) * ts - 6 * PATH_KAPPA + 3) * ts + 3 * PATH_KAPPA) * ts - sinAngle) - / (((9 * PATH_KAPPA - 6) * ts + 12 * PATH_KAPPA - 6) * ts + 3 * PATH_KAPPA); - - //use the average of the t that best approximates cos_angle and the t that best approximates sin_angle - return (0.5 * (tc + ts)); -} - - -static int _arcToCubic(ShapePath& path, const Point* pts, size_t ptsCnt) -{ - assert(pts); - - if (path.cmdCnt > 0 && path.cmds[path.cmdCnt] != PathCommand::Close) { - if (path.lineTo(pts[0].x, pts[0].y)) return -1; - } else { - if (path.moveTo(pts[0].x, pts[0].y)) return -1; - } - - for (size_t i = 1; i < ptsCnt; i += 3) { - if (path.cubicTo(pts[i].x, pts[i].y, pts[i+1].x, pts[i+1].y, pts[i+2].x, pts[i+2].y)) { - return -1; - } - } - - return 0; -} - - -static void _findEllipseCoords(float x, float y, float w, float h, float startAngle, float sweepAngle, Point& ptStart, Point& ptEnd) -{ - float angles[2] = {startAngle, startAngle + sweepAngle}; - float half_w = w * 0.5f; - float half_h = h * 0.5f; - float cx = x + half_w; - float cy = y + half_h; - Point* pts[2] = {&ptStart, &ptEnd}; - - for (auto i = 0; i < 2; ++i) { - auto theta = angles[i] - 360 * floor(angles[i] / 360); - auto t = theta / 90; - auto quadrant = static_cast(t); //truncate - t -= quadrant; - t = _arcAngle(90 * t); - - //swap x and y? - if (quadrant & 1) t = (1 - t); - - //bezier coefficients - auto m = 1 - t; - auto b = m * m; - auto c = t * t; - auto d = c * t; - auto a = b * m; - b *= 3 * t; - c *= 3 * m; - - auto px = a + b + c * PATH_KAPPA; - auto py = d + c + b * PATH_KAPPA; - - //left quadrants - if (quadrant == 1 || quadrant == 2) px = -px; - - //top quadrants - if (quadrant == 0 || quadrant == 1) py = -py; - - pts[i]->x = cx + half_w * px; - pts[i]->y = cy + half_h * py; - } -} - - #endif //_TVG_SHAPE_PATH_CPP_ diff --git a/test/testMultipleShapes.cpp b/test/testMultipleShapes.cpp index 3826f8f7..f1bdfe84 100644 --- a/test/testMultipleShapes.cpp +++ b/test/testMultipleShapes.cpp @@ -19,7 +19,7 @@ void tvgtest() //Prepare Rectangle auto shape1 = tvg::ShapeNode::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius + 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)); diff --git a/test/testShape.cpp b/test/testShape.cpp index e42cba80..7d0aa88d 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -18,7 +18,7 @@ void tvgtest() //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius shape1->fill(255, 0, 0, 255); //r, g, b, a /* Push the shape into the Canvas drawing list diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 6a514123..de84c32a 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -17,7 +17,7 @@ int main(int argc, char **argv) //Prepare a Shape auto shape1 = tvg::ShapeNode::gen(); - shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius + shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //Stroke Style From 1e96cc2b1061259555118f7baaab68b7b432fc7f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 26 Apr 2020 18:18:52 +0900 Subject: [PATCH 022/244] common shape: support ellipse Now, you can pass separate width radius and height radius in circle. Change-Id: Ie1e2b58fbb399d8ef74d55d83ec48d8f4323f21e --- inc/tizenvg.h | 2 +- src/lib/tvgShapeNode.cpp | 17 +++++++++-------- test/testMultipleShapes.cpp | 10 ++++++++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 64c8ee47..e8974396 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -93,7 +93,7 @@ public: int clear() noexcept; int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; - int appendCircle(float cx, float cy, float radius) noexcept; + int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; int fill(size_t r, size_t g, size_t b, size_t a) noexcept; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 6ee0b7ae..a6e45114 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -135,19 +135,20 @@ int ShapeNode::pathCoords(const Point** pts) const noexcept } -int ShapeNode::appendCircle(float cx, float cy, float radius) noexcept +int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); assert(impl); - auto halfKappa = radius * PATH_KAPPA; + auto halfKappaW = radiusW * PATH_KAPPA; + auto halfKappaH = radiusH * PATH_KAPPA; impl->path->reserve(6, 13); - impl->path->moveTo(cx, cy - radius); - impl->path->cubicTo(cx + halfKappa, cy - radius, cx + radius, cy - halfKappa, cx + radius, cy); - impl->path->cubicTo(cx + radius, cy + halfKappa, cx + halfKappa, cy + radius, cx, cy + radius); - impl->path->cubicTo(cx - halfKappa, cy + radius, cx - radius, cy + halfKappa, cx - radius, cy); - impl->path->cubicTo(cx - radius, cy - halfKappa, cx - halfKappa, cy - radius, cx, cy - radius); + impl->path->moveTo(cx, cy - radiusH); + impl->path->cubicTo(cx + halfKappaW, cy - radiusH, cx + radiusW, cy - halfKappaH, cx + radiusW, cy); + impl->path->cubicTo(cx + radiusW, cy + halfKappaH, cx + halfKappaW, cy + radiusH, cx, cy + radiusH); + impl->path->cubicTo(cx - halfKappaW, cy + radiusH, cx - radiusW, cy + halfKappaH, cx - radiusW, cy); + impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH); impl->path->close(); return 0; @@ -173,7 +174,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius impl->path->close(); //circle } else if (w == h && cornerRadius * 2 == w) { - return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius); + return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius, cornerRadius); } else { auto halfKappa = cornerRadius * 0.5; impl->path->reserve(10, 17); diff --git a/test/testMultipleShapes.cpp b/test/testMultipleShapes.cpp index f1bdfe84..a73d2b6d 100644 --- a/test/testMultipleShapes.cpp +++ b/test/testMultipleShapes.cpp @@ -17,7 +17,7 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //canvas->reserve(2); //reserve 2 shape nodes (optional) - //Prepare Rectangle + //Prepare Round Rectangle auto shape1 = tvg::ShapeNode::gen(); shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //r, g, b, a @@ -25,10 +25,16 @@ void tvgtest() //Prepare Circle auto shape2 = tvg::ShapeNode::gen(); - shape2->appendCircle(400, 400, 200); //cx, cy, radius + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(255, 255, 0, 255); //r, g, b, a canvas->push(move(shape2)); + //Prepare Ellipse + auto shape3 = tvg::ShapeNode::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)); + //Draw the Shapes onto the Canvas canvas->draw(); canvas->sync(); From dc87a59d5399422192054817547a461ec2ceba0e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 26 Apr 2020 18:41:27 +0900 Subject: [PATCH 023/244] test: add merge shapes Change-Id: I2dc91d3514aed1cbb1bd3490ea5d91debeab662a --- test/makefile | 3 +- test/testMergeShapes.cpp | 63 +++++++++++++++++++ ...MultipleShapes.cpp => testMultiShapes.cpp} | 0 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/testMergeShapes.cpp rename test/{testMultipleShapes.cpp => testMultiShapes.cpp} (100%) diff --git a/test/makefile b/test/makefile index 00b7d7ff..bb807298 100644 --- a/test/makefile +++ b/test/makefile @@ -1,3 +1,4 @@ all: gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testMultipleShapes testMultipleShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testMultiShapes testMultiShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp new file mode 100644 index 00000000..3242df7b --- /dev/null +++ b/test/testMergeShapes.cpp @@ -0,0 +1,63 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Prepare a Shape (Rectangle + Rectangle + Circle) + auto shape1 = tvg::ShapeNode::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(500, 500, 100, 100); //cx, cy, radiusW, radiusH + //FIXME: eeek! crash! + // shape1->appendCircle(400, 600, 170, 100); //cx, cy, radiusW, radiusH + shape1->fill(255, 0, 0, 255); //r, g, b, a + + /* 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->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + + 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} diff --git a/test/testMultipleShapes.cpp b/test/testMultiShapes.cpp similarity index 100% rename from test/testMultipleShapes.cpp rename to test/testMultiShapes.cpp From 6be53b07794d9dbaaf73fb2d5fc5d3014f868eb4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 26 Apr 2020 18:47:34 +0900 Subject: [PATCH 024/244] test: close the window at exit button Change-Id: Idf46d7132ae97356637816e54dc6c267be7122e6 --- test/testMergeShapes.cpp | 7 +++++++ test/testMultiShapes.cpp | 7 +++++++ test/testShape.cpp | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 3242df7b..549ea9ef 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -38,6 +38,12 @@ void tvgtest() tvg::Engine::term(); } +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + int main(int argc, char **argv) { @@ -47,6 +53,7 @@ int main(int argc, char **argv) elm_init(argc, argv); Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index a73d2b6d..94d3c31f 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -43,6 +43,12 @@ void tvgtest() tvg::Engine::term(); } +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + int main(int argc, char **argv) { tvgtest(); @@ -51,6 +57,7 @@ int main(int argc, char **argv) elm_init(argc, argv); Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); diff --git a/test/testShape.cpp b/test/testShape.cpp index 7d0aa88d..c806d990 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -34,6 +34,11 @@ void tvgtest() tvg::Engine::term(); } +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} int main(int argc, char **argv) { @@ -43,6 +48,7 @@ int main(int argc, char **argv) elm_init(argc, argv); Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); From 0e6faa927610d8b2a67249f248a1dd4252837f0c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 01:45:52 +0900 Subject: [PATCH 025/244] common: code refactoring. introduce Canvas class to replace the CanvasBase. now, SwCanvas, GlCanvas inherits this Canvas for polymorphism and remove duplicated interfaces. Change-Id: I65a87e3aa2289d04997930a54aeccd14f57dd73a --- inc/tizenvg.h | 50 +++++++----- src/lib/meson.build | 2 +- src/lib/{tvgCanvasBase.h => tvgCanvas.cpp} | 91 ++++++++++++++++++---- src/lib/tvgGlCanvas.cpp | 51 +++--------- src/lib/tvgSwCanvas.cpp | 82 +++++-------------- 5 files changed, 136 insertions(+), 140 deletions(-) rename src/lib/{tvgCanvasBase.h => tvgCanvas.cpp} (61%) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index e8974396..babca5d4 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -72,7 +72,33 @@ class TIZENVG_EXPORT PaintNode { public: virtual ~PaintNode() {} - virtual int update(RenderMethod* engine) = 0; + virtual int update(RenderMethod*) = 0; +}; + + +/** + * @class Canvas + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TIZENVG_EXPORT Canvas +{ +public: + Canvas(RenderMethod*); + virtual ~Canvas(); + + virtual int push(std::unique_ptr paint) noexcept; + virtual int clear() noexcept; + virtual int update() noexcept; + virtual int draw(bool async = true) noexcept; + virtual int sync() = 0; + + RenderMethod* engine() noexcept; + + _TIZENVG_DECLARE_PRIVATE(Canvas); }; @@ -141,21 +167,13 @@ public: @brief description... * */ -class TIZENVG_EXPORT SwCanvas final +class TIZENVG_EXPORT SwCanvas final : public Canvas { public: ~SwCanvas(); - int push(std::unique_ptr paint) noexcept; - int clear() noexcept; - - int update() noexcept; - int draw(bool async = true) noexcept; - int sync() noexcept; - RenderMethod* engine() noexcept; - int target(uint32_t* buffer, size_t stride, size_t height) noexcept; - + int sync() noexcept override; static std::unique_ptr gen(uint32_t* buffer = nullptr, size_t stride = 0, size_t height = 0) noexcept; _TIZENVG_DECLARE_PRIVATE(SwCanvas); @@ -170,20 +188,14 @@ public: * @brief description... * */ -class TIZENVG_EXPORT GlCanvas final +class TIZENVG_EXPORT GlCanvas final : public Canvas { public: ~GlCanvas(); - int push(std::unique_ptr paint) noexcept; - int clear() noexcept; - //TODO: Gl Specific methods. Need gl backend configuration methods as well. - int update() noexcept; - int draw(bool async = true) noexcept; - int sync() noexcept { return 0; } - RenderMethod* engine() noexcept; + int sync() noexcept override; static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(GlCanvas); diff --git a/src/lib/meson.build b/src/lib/meson.build index ffecb2a5..976aa5ee 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -5,8 +5,8 @@ source_file = [ 'tvgCommon.h', 'tvgRenderCommon.h', 'tvgEngine.cpp', - 'tvgCanvasBase.h', 'tvgShapePath.h', + 'tvgCanvas.cpp', 'tvgSwCanvas.cpp', 'tvgGlCanvas.cpp', 'tvgSceneNode.cpp', diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvas.cpp similarity index 61% rename from src/lib/tvgCanvasBase.h rename to src/lib/tvgCanvas.cpp index a2ed34b9..3bde24f6 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvas.cpp @@ -14,26 +14,30 @@ * limitations under the License. * */ -#ifndef _TVG_CANVAS_BASE_CPP_ -#define _TVG_CANVAS_BASE_CPP_ +#ifndef _TVG_CANVAS_CPP_ +#define _TVG_CANVAS_CPP_ #include "tvgCommon.h" -struct CanvasBase +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct Canvas::Impl { vector nodes; RenderMethod* renderer; - CanvasBase(RenderMethod *pRenderer):renderer(pRenderer) + Impl(RenderMethod *pRenderer):renderer(pRenderer) { renderer->ref(); } - ~CanvasBase() + ~Impl() { - clear(); - renderer->unref(); + clear(); + renderer->unref(); } int reserve(size_t n) @@ -43,6 +47,14 @@ struct CanvasBase return 0; } + int push(unique_ptr paint) + { + PaintNode *node = paint.release(); + assert(node); + nodes.push_back(node); + return node->update(renderer); + } + int clear() { assert(renderer); @@ -75,14 +87,6 @@ struct CanvasBase return ret; } - int push(unique_ptr paint) - { - PaintNode *node = paint.release(); - assert(node); - nodes.push_back(node); - return node->update(renderer); - } - int draw() { assert(renderer); @@ -101,4 +105,59 @@ struct CanvasBase }; -#endif /* _TVG_CANVAS_BASE_CPP_ */ + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +Canvas::Canvas(RenderMethod *pRenderer):pImpl(make_unique(pRenderer)) +{ +} + + +Canvas::~Canvas() +{ +} + + +int Canvas::push(unique_ptr paint) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->push(move(paint)); +} + + +int Canvas::clear() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->clear(); +} + + +int Canvas::draw(bool async) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->draw(); +} + + +int Canvas::update() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->update(); +} + + +RenderMethod* Canvas::engine() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + return impl->renderer; +} + +#endif /* _TVG_CANVAS_CPP_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 386778d7..a7719d30 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -18,16 +18,15 @@ #define _TVG_GLCANVAS_CPP_ #include "tvgCommon.h" -#include "tvgCanvasBase.h" #include "tvgGlRenderer.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -struct GlCanvas::Impl : CanvasBase +struct GlCanvas::Impl { - Impl() : CanvasBase(GlRenderer::inst()) {} + Impl() {} }; @@ -35,7 +34,7 @@ struct GlCanvas::Impl : CanvasBase /* External Class Implementation */ /************************************************************************/ -GlCanvas::GlCanvas() : pImpl(make_unique()) +GlCanvas::GlCanvas() : Canvas(GlRenderer::inst()), pImpl(make_unique()) { } @@ -45,6 +44,12 @@ GlCanvas::~GlCanvas() } +int GlCanvas::sync() noexcept +{ + return 0; +} + + unique_ptr GlCanvas::gen() noexcept { auto canvas = unique_ptr(new GlCanvas); @@ -54,42 +59,4 @@ unique_ptr GlCanvas::gen() noexcept } -int GlCanvas::push(unique_ptr paint) noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->push(move(paint)); -} - -int GlCanvas::clear() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->clear(); -} - - -int GlCanvas::update() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->update(); -} - - -RenderMethod* GlCanvas::engine() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->renderer; -} - - -int GlCanvas::draw(bool async) noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->draw(); -} - #endif /* _TVG_GLCANVAS_CPP_ */ diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 442b0d7c..04902fc6 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -18,7 +18,6 @@ #define _TVG_SWCANVAS_CPP_ #include "tvgCommon.h" -#include "tvgCanvasBase.h" #include "tvgSwRenderer.h" @@ -26,9 +25,9 @@ /* Internal Class Implementation */ /************************************************************************/ -struct SwCanvas::Impl : CanvasBase +struct SwCanvas::Impl { - Impl() : CanvasBase(SwRenderer::inst()) {} + Impl() {} }; @@ -36,49 +35,7 @@ struct SwCanvas::Impl : CanvasBase /* External Class Implementation */ /************************************************************************/ -int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept -{ - auto impl = pImpl.get(); - assert(impl); - - dynamic_cast(impl->renderer)->target(buffer, stride, height); - - return 0; -} - - -int SwCanvas::draw(bool async) noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->draw(); -} - - -int SwCanvas::sync() noexcept -{ - return 0; -} - - -int SwCanvas::push(unique_ptr paint) noexcept -{ - auto impl = pImpl.get(); - assert(impl); - - return impl->push(move(paint)); -} - - -int SwCanvas::clear() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->clear(); -} - - -SwCanvas::SwCanvas() : pImpl(make_unique()) +SwCanvas::SwCanvas() : Canvas(SwRenderer::inst()), pImpl(make_unique()) { } @@ -88,6 +45,23 @@ SwCanvas::~SwCanvas() } +int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept +{ + auto renderer = dynamic_cast(engine()); + assert(renderer); + + if (!renderer->target(buffer, stride, height)) return -1; + + return 0; +} + + +int SwCanvas::sync() noexcept +{ + return 0; +} + + unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t height) noexcept { auto canvas = unique_ptr(new SwCanvas); @@ -99,20 +73,4 @@ unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t heigh return canvas; } - -int SwCanvas::update() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->update(); -} - - -RenderMethod* SwCanvas::engine() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->renderer; -} - #endif /* _TVG_SWCANVAS_CPP_ */ From 809dfd8644c4b41a0958a212f24d2daa180bd51c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 01:52:44 +0900 Subject: [PATCH 026/244] canvas: add reserve() method. This allocates nodes slots in advance to avoid memory grow & copy. it will be benefit if you know how many shapes will be used in your canvas. Change-Id: I7d93d166c9c054078bd86593d3471a2ade3671ee --- inc/tizenvg.h | 1 + src/lib/tvgCanvas.cpp | 8 ++++++++ test/testMultiShapes.cpp | 2 +- test/testShape.cpp | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index babca5d4..1aee6bb8 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -90,6 +90,7 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); + int reserve(size_t n); virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 3bde24f6..96b58e0c 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -120,6 +120,14 @@ Canvas::~Canvas() } +int Canvas::reserve(size_t n) +{ + auto impl = pImpl.get(); + assert(impl); + return impl->reserve(n); +} + + int Canvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 94d3c31f..6fc0469f 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -15,7 +15,7 @@ void tvgtest() //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //canvas->reserve(2); //reserve 2 shape nodes (optional) + canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/testShape.cpp b/test/testShape.cpp index c806d990..b7fca2f9 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -18,7 +18,7 @@ void tvgtest() //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + shape1->appendRect(100, 100, 400, 400, 0); //x, y, w, h, cornerRadius shape1->fill(255, 0, 0, 255); //r, g, b, a /* Push the shape into the Canvas drawing list From c813de45caa5f9c9e342be1dfea82ec450d09eda Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 01:59:49 +0900 Subject: [PATCH 027/244] update gitignore file Change-Id: I0b245f1177e3df04ddc6f345213bbb1207d3e950 --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 45329ec6..a6a008ab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ build .vscode *.swp testShape +testMultiShapes +testMergeShapes From 5120a7ae125db724c7ea32a77b0ed4819b57886a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 02:00:38 +0900 Subject: [PATCH 028/244] canvas: correct convention add missing noexcept option. Change-Id: I14eacb0fdb2c9bd40e365bf81bb5cc0b73239ffe --- inc/tizenvg.h | 2 +- src/lib/tvgCanvas.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 1aee6bb8..c53a5dc3 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -90,7 +90,7 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); - int reserve(size_t n); + int reserve(size_t n) noexcept; virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 96b58e0c..37230838 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -120,7 +120,7 @@ Canvas::~Canvas() } -int Canvas::reserve(size_t n) +int Canvas::reserve(size_t n) noexcept { auto impl = pImpl.get(); assert(impl); From 46ba3352a8313b602c04da9ddcf8dea955c485b6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 00:54:41 +0900 Subject: [PATCH 029/244] sw_engine: case cover out of surface boundary. Also added surface boundary test code. Change-Id: Ib4c327d12ce52d506f1b8a566ffa48e5b5b8c03e --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 12 ++-- src/lib/sw_engine/tvgSwRaster.cpp | 3 +- src/lib/sw_engine/tvgSwRenderer.cpp | 5 +- src/lib/sw_engine/tvgSwRle.cpp | 42 ++++++++++---- src/lib/sw_engine/tvgSwShape.cpp | 12 +++- test/makefile | 1 + test/testBoundary.cpp | 86 +++++++++++++++++++++++++++++ 8 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 test/testBoundary.cpp diff --git a/.gitignore b/.gitignore index a6a008ab..bbd3f8ee 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build testShape testMultiShapes testMergeShapes +testBoundary diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4b6f8203..012f9681 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -49,6 +49,11 @@ struct SwPoint } }; +struct SwSize +{ + SwCoord w, h; +}; + struct SwOutline { size_t* cntrs; //the contour end points @@ -63,7 +68,7 @@ struct SwOutline struct SwSpan { - uint16_t x, y; + int16_t x, y; uint16_t len; uint8_t coverage; }; @@ -90,10 +95,9 @@ struct SwShape void shapeReset(SwShape& sdata); bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata); void shapeDelOutline(const ShapeNode& shape, SwShape& sdata); -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata); +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); - -SwRleData* rleRender(const SwShape& sdata); +SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, size_t color); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 2e43a44b..a71c4433 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -23,13 +23,14 @@ bool rasterShape(Surface& surface, SwShape& sdata, size_t color) { SwRleData* rle = sdata.rle; - assert(rle); + if (!rle) return false; auto stride = surface.stride; auto span = rle->spans; for (size_t i = 0; i < rle->size; ++i) { assert(span); +// printf("raster y(%d) x(%d) len(%d)\n", span->y, span->x, span->len); for (auto j = 0; j < span->len; ++j) { surface.buffer[span->y * stride + span->x + j] = color; } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 425afaba..ae43735d 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -55,7 +55,6 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) //invisible? size_t r, g, b, a; shape.fill(&r, &g, &b, &a); - if (a == 0) return true; //TODO: Threading return rasterShape(surface, *sdata, COLOR(r, g, b, a)); @@ -92,7 +91,9 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; - if (!shapeGenRle(shape, *sdata)) return sdata; + + SwSize clip = {static_cast(surface.stride), static_cast(surface.height)}; + if (!shapeGenRle(shape, *sdata, clip)) return sdata; } return sdata; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f17c6845..3991fff1 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -84,6 +84,8 @@ struct RleWorker Cell** yCells; SwCoord yCnt; + SwSize clip; + bool invalid; }; @@ -161,6 +163,13 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count) static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) { + x += rw.cellMin.x; + y += rw.cellMin.y; + + //Clip Y range + if (y < 0) return; + if (y >= rw.clip.h) return; + /* compute the coverage line's coverage, depending on the outline fill rule */ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ auto coverage = static_cast(area >> (PIXEL_BITS * 2 + 1 - 8)); //range 0 - 256 @@ -176,9 +185,6 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor if (coverage >= 256) coverage = 255; } - x += rw.cellMin.x; - y += rw.cellMin.y; - //span has ushort coordinates. check limit overflow if (x >= SHRT_MAX) { cout << "x(" << x << ") coordinate overflow!" << endl; @@ -197,7 +203,13 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor //see whether we can add this span to the current list if ((count > 0) && (rw.ySpan == y) && (span->x + span->len == x) && (span->coverage == coverage)) { - span->len = span->len + acount; + + //Clip x range + SwCoord xOver = 0; + if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); + if (x < 0) xOver += x; + + span->len += (acount + xOver) - 1; return; } @@ -211,10 +223,21 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor assert(span); } + //Clip x range + SwCoord xOver = 0; + if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); + if (x < 0) { + xOver += x; + x = 0; + } + + //Nothing to draw + if (acount + xOver <= 0) return; + //add a span to the current list span->x = x; span->y = y; - span->len = acount; + span->len = (acount + xOver); span->coverage = coverage; ++rw.spansCnt; } @@ -646,16 +669,13 @@ static bool _genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(const SwShape& sdata) +SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) { constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 40; auto outline = sdata.outline; assert(outline); - - if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr; - assert(outline->cntrs && outline->pts); assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); @@ -680,11 +700,10 @@ SwRleData* rleRender(const SwShape& sdata) rw.outline = outline; rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; + rw.clip = clip; rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); assert(rw.rle); - //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.cellMin.x, rw.cellMin.y, rw.cellMax.x, rw.cellMax.y, rw.cellXCnt, rw.cellYCnt, rw.bandSize); - //Generate RLE Band bands[BAND_SIZE]; Band* band; @@ -717,7 +736,6 @@ SwRleData* rleRender(const SwShape& sdata) auto cellEnd = rw.bufferSize; cellEnd -= cellEnd % sizeof(Cell); -//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod); auto cellsMax = reinterpret_cast((char*)rw.buffer + cellEnd); rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index e725e30c..1f24a631 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -235,11 +235,19 @@ bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) } -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip) { + if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) goto end; if (!_updateBBox(sdata)) goto end; - sdata.rle = rleRender(sdata); + + //Check boundary + if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) || + (sdata.bbox.min.x + sdata.bbox.max.x < 0) || + (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end; + + sdata.rle = rleRender(sdata, clip); _deleteOutline(sdata); + end: if (sdata.rle) return true; return false; diff --git a/test/makefile b/test/makefile index bb807298..1bab747e 100644 --- a/test/makefile +++ b/test/makefile @@ -2,3 +2,4 @@ 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 testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp new file mode 100644 index 00000000..473fd59c --- /dev/null +++ b/test/testBoundary.cpp @@ -0,0 +1,86 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + canvas->reserve(5); //reserve 5 shape nodes (optional) + + //Prepare Shape1 + auto shape1 = tvg::ShapeNode::gen(); + shape1->appendRect(-100, -100, 1000, 1000, 50); + shape1->fill(255, 255, 255, 255); + canvas->push(move(shape1)); + + //Prepare Shape2 + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendRect(-100, -100, 250, 250, 50); + shape2->fill(0, 0, 255, 255); + canvas->push(move(shape2)); + + //Prepare Shape3 + auto shape3 = tvg::ShapeNode::gen(); + shape3->appendRect(500, 500, 550, 550, 0); + shape3->fill(0, 255, 255, 255); + canvas->push(move(shape3)); + + //Prepare Shape4 + auto shape4 = tvg::ShapeNode::gen(); + shape4->appendCircle(800, 100, 200, 200); + shape4->fill(255, 255, 0, 255); + canvas->push(move(shape4)); + + //Prepare Shape5 + auto shape5 = tvg::ShapeNode::gen(); + 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(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From e0ecd680a02ccf9e3ef46c4c82b2336d9509426f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 15:41:16 +0900 Subject: [PATCH 030/244] sw_engine: fix crash at merge shape test increased spare cell memory for rasterizing. Change-Id: I391dfbfae0ef028d213c55fe1ceca023e272e676 --- src/lib/sw_engine/tvgSwRle.cpp | 3 ++- test/testMergeShapes.cpp | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 3991fff1..02870c3d 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -671,7 +671,8 @@ static bool _genRle(RleWorker& rw) SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) { - constexpr auto RENDER_POOL_SIZE = 16384L; + //Please adjust when you out of cell memory (default: 16384L) + constexpr auto RENDER_POOL_SIZE = 166641L; constexpr auto BAND_SIZE = 40; auto outline = sdata.outline; diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 549ea9ef..b37440b6 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -20,10 +20,9 @@ void tvgtest() auto shape1 = tvg::ShapeNode::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(500, 500, 100, 100); //cx, cy, radiusW, radiusH - //FIXME: eeek! crash! - // shape1->appendCircle(400, 600, 170, 100); //cx, cy, radiusW, radiusH - shape1->fill(255, 0, 0, 255); //r, g, b, a + 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 /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare From 9b8ab42e545cac7514caa7893312d2beb03f1e02 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 18:31:51 +0900 Subject: [PATCH 031/244] common shape: support path appending it's usage may require a little handy but The path data is very low manipulated, its usage may require a little handy, but appedingPath() is designed for performance. Also added testPath. Change-Id: Ifd929d48506926e3f529198c0b40ee8f922835d4 --- .gitignore | 1 + inc/tizenvg.h | 1 + src/lib/tvgCommon.h | 1 + src/lib/tvgShapeNode.cpp | 24 ++++++-- src/lib/tvgShapePath.h | 86 +++++++++++------------------ test/makefile | 1 + test/testPath.cpp | 116 ++++++++++++++++++++++++++++++++++----- 7 files changed, 158 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index bbd3f8ee..ddc65233 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ testShape testMultiShapes testMergeShapes testBoundary +testPath diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c53a5dc3..89db3f54 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -121,6 +121,7 @@ public: int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; + int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; int fill(size_t r, size_t g, size_t b, size_t a) noexcept; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2653d3a1..c3f0c568 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "tizenvg.h" #include "tvgRenderCommon.h" diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index a6e45114..0c01c0fb 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -109,7 +109,9 @@ int ShapeNode::clear() noexcept auto impl = pImpl.get(); assert(impl); - return impl->path->clear(); + impl->path->clear(); + + return 0; } @@ -135,6 +137,20 @@ int ShapeNode::pathCoords(const Point** pts) const noexcept } +int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +{ + if (cmdCnt < 0 || ptsCnt < 0) return -1; + assert(cmds && pts); + + auto impl = pImpl.get(); + assert(impl); + + impl->path->append(cmds, cmdCnt, pts, ptsCnt); + + return 0; +} + + int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); @@ -143,7 +159,7 @@ int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) no auto halfKappaW = radiusW * PATH_KAPPA; auto halfKappaH = radiusH * PATH_KAPPA; - impl->path->reserve(6, 13); + impl->path->grow(6, 13); impl->path->moveTo(cx, cy - radiusH); impl->path->cubicTo(cx + halfKappaW, cy - radiusH, cx + radiusW, cy - halfKappaH, cx + radiusW, cy); impl->path->cubicTo(cx + radiusW, cy + halfKappaH, cx + halfKappaW, cy + radiusH, cx, cy + radiusH); @@ -166,7 +182,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius //rectangle if (cornerRadius == 0) { - impl->path->reserve(5, 4); + impl->path->grow(5, 4); impl->path->moveTo(x, y); impl->path->lineTo(x + w, y); impl->path->lineTo(x + w, y + h); @@ -177,7 +193,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius, cornerRadius); } else { auto halfKappa = cornerRadius * 0.5; - impl->path->reserve(10, 17); + impl->path->grow(10, 17); impl->path->moveTo(x + cornerRadius, y); impl->path->lineTo(x + w - cornerRadius, y); impl->path->cubicTo(x + w - cornerRadius + halfKappa, y, x + w, y + cornerRadius - halfKappa, x + w, y + cornerRadius); diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 6fda0f0d..f4fee181 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -40,65 +40,68 @@ struct ShapePath if (pts) delete(pts); } - int reserveCmd(size_t cmdCnt) + void reserveCmd(size_t cmdCnt) { - if (cmdCnt > reservedCmdCnt) { - reservedCmdCnt = cmdCnt; - cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); - assert(cmds); - } - return 0; + if (cmdCnt <= reservedCmdCnt) return; + reservedCmdCnt = cmdCnt; + cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); + assert(cmds); } - int reservePts(size_t ptsCnt) + void reservePts(size_t ptsCnt) { - if (ptsCnt > reservedPtsCnt) { - reservedPtsCnt = ptsCnt; - pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); - assert(pts); - } - return 0; + if (ptsCnt <= reservedPtsCnt) return; + reservedPtsCnt = ptsCnt; + pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); + assert(pts); } - int reserve(size_t cmdCnt, size_t ptsCnt) + void reserve(size_t cmdCnt, size_t ptsCnt) { reserveCmd(cmdCnt); reservePts(ptsCnt); - - return 0; } - int clear() + void grow(size_t cmdCnt, size_t ptsCnt) + { + reserveCmd(this->cmdCnt + cmdCnt); + reservePts(this->ptsCnt + ptsCnt); + } + + void clear() { cmdCnt = 0; ptsCnt = 0; - - return 0; } - int moveTo(float x, float y) + void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) + { + grow(cmdCnt, ptsCnt); + memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); + memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); + this->cmdCnt += cmdCnt; + this->ptsCnt += ptsCnt; + } + + void moveTo(float x, float y) { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); cmds[cmdCnt++] = PathCommand::MoveTo; pts[ptsCnt++] = {x, y}; - - return 0; } - int lineTo(float x, float y) + void lineTo(float x, float y) { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); cmds[cmdCnt++] = PathCommand::LineTo; pts[ptsCnt++] = {x, y}; - - return 0; } - int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) + void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2); @@ -107,39 +110,12 @@ struct ShapePath pts[ptsCnt++] = {cx1, cy1}; pts[ptsCnt++] = {cx2, cy2}; pts[ptsCnt++] = {x, y}; - - return 0; } - - int close() + void close() { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); cmds[cmdCnt++] = PathCommand::Close; - - return 0; - } - - int bounds(float& x, float& y, float& w, float& h) - { - if (ptsCnt == 0) return -1; - - Point min = { pts[0].x, pts[0].y }; - Point max = { pts[0].x, pts[0].y }; - - for(size_t i = 1; i <= ptsCnt; ++i) { - if (pts[i].x < min.x) min.x = pts[i].x; - if (pts[i].y < min.y) min.y = pts[i].y; - if (pts[i].x > max.x) max.x = pts[i].x; - if (pts[i].y > max.y) max.y = pts[i].y; - } - - x = min.x; - y = min.y; - w = max.x - min.x; - h = max.y - min.y; - - return 0; } }; diff --git a/test/makefile b/test/makefile index 1bab747e..e213907d 100644 --- a/test/makefile +++ b/test/makefile @@ -3,3 +3,4 @@ all: gcc -o testMultiShapes testMultiShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testMergeShapes testMergeShapes.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` diff --git a/test/testPath.cpp b/test/testPath.cpp index e260682f..a75c7f71 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -7,7 +8,7 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -int main(int argc, char **argv) +void tvgtest() { //Initialize TizenVG Engine tvg::Engine::init(); @@ -15,25 +16,114 @@ int main(int argc, char **argv) //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //Prepare Path - auto path = tvg::Path::gen(); - path.reserve(cmdCnt, ptCnt); //command count, points count - path.moveTo(...); - path.lineTo(...); - path.cubicTo(...); - path.close(); + /* Star */ + + //Prepare Path Commands + tvg::PathCommand cmds[11]; + cmds[0] = tvg::PathCommand::MoveTo; + cmds[1] = tvg::PathCommand::LineTo; + cmds[2] = tvg::PathCommand::LineTo; + cmds[3] = tvg::PathCommand::LineTo; + cmds[4] = tvg::PathCommand::LineTo; + cmds[5] = tvg::PathCommand::LineTo; + cmds[6] = tvg::PathCommand::LineTo; + cmds[7] = tvg::PathCommand::LineTo; + cmds[8] = tvg::PathCommand::LineTo; + cmds[9] = tvg::PathCommand::LineTo; + cmds[10] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts[10]; + pts[0] = {199, 34}; //MoveTo + pts[1] = {253, 143}; //LineTo + pts[2] = {374, 160}; //LineTo + pts[3] = {287, 244}; //LineTo + pts[4] = {307, 365}; //LineTo + pts[5] = {199, 309}; //LineTo + pts[6] = {97, 365}; //LineTo + pts[7] = {112, 245}; //LineTo + pts[8] = {26, 161}; //LineTo + pts[9] = {146, 143}; //LineTo - //Prepare a Shape auto shape1 = tvg::ShapeNode::gen(); - shape1->path(move(path)); //migrate owner otherwise, - shape1->path(path.get()); //copy raw data directly for performance + shape1->appendPath(cmds, 11, pts, 10); //copy path data shape1->fill(0, 255, 0, 255); - - //Draw the Shape onto the Canvas canvas->push(move(shape1)); + + + /* Circle */ + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Prepare Path Commands + tvg::PathCommand cmds2[6]; + cmds2[0] = tvg::PathCommand::MoveTo; + cmds2[1] = tvg::PathCommand::CubicTo; + cmds2[2] = tvg::PathCommand::CubicTo; + cmds2[3] = tvg::PathCommand::CubicTo; + cmds2[4] = tvg::PathCommand::CubicTo; + cmds2[5] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts2[13]; + pts2[0] = {cx, cy - radius}; //MoveTo + //CubicTo 1 + pts2[1] = {cx + halfRadius, cy - radius}; //Ctrl1 + pts2[2] = {cx + radius, cy - halfRadius}; //Ctrl2 + pts2[3] = {cx + radius, cy}; //To + //CubicTo 2 + pts2[4] = {cx + radius, cy + halfRadius}; //Ctrl1 + pts2[5] = {cx + halfRadius, cy + radius}; //Ctrl2 + pts2[6] = {cx, cy+ radius}; //To + //CubicTo 3 + pts2[7] = {cx - halfRadius, cy + radius}; //Ctrl1 + pts2[8] = {cx - radius, cy + halfRadius}; //Ctrl2 + pts2[9] = {cx - radius, cy}; //To + //CubicTo 4 + pts2[10] = {cx - radius, cy - halfRadius}; //Ctrl1 + pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 + pts2[12] = {cx, cy - radius}; //To + + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendPath(cmds2, 6, pts2, 13); //copy path data + shape2->fill(255, 255, 0, 255); + canvas->push(move(shape2)); + canvas->draw(); canvas->sync(); //Terminate TizenVG Engine tvg::Engine::term(); } + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 308456ebade78905cd2ad6e9e3f8a5770475d523 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 18:38:34 +0900 Subject: [PATCH 032/244] common shape: remove unnecessary log Change-Id: Ie85153afdc01270ed282d9ff87607ee1a882be31 --- src/lib/tvgShapeNode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 0c01c0fb..12ce6de9 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -75,7 +75,6 @@ ShapeNode :: ShapeNode() : pImpl(make_unique()) ShapeNode :: ~ShapeNode() { - cout << "ShapeNode(" << this << ") destroyed!" << endl; } From 700a44c623f9ff663d7b6488dbe831fe672ca7be Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 19:11:04 +0900 Subject: [PATCH 033/244] common shape: added path commands interfaces for user convenient. +lineTo() +moveTo() +cubicTo() +close() These interfaces might not perfect optmizied, but you can build path commands easier than manual data set. Change-Id: Icb934ca256d3107ca0c938d28015d767fb93355e --- .gitignore | 1 + inc/tizenvg.h | 5 ++ src/lib/sw_engine/tvgSwRle.cpp | 2 +- src/lib/tvgShapeNode.cpp | 45 +++++++++++++++++ src/lib/tvgShapePath.h | 9 +--- test/makefile | 1 + test/testPath2.cpp | 89 ++++++++++++++++++++++++++++++++++ 7 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 test/testPath2.cpp diff --git a/.gitignore b/.gitignore index ddc65233..8e92d138 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ testMultiShapes testMergeShapes testBoundary testPath +testPath2 diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 89db3f54..83e5f1d0 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -119,6 +119,11 @@ public: int update(RenderMethod* engine) noexcept override; int clear() noexcept; + int moveTo(float x, float y) noexcept; + int lineTo(float x, float y) noexcept; + int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; + int close() noexcept; + int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 02870c3d..5166de8e 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -637,7 +637,7 @@ static bool _decomposeOutline(RleWorker& rw) } } - //Close the contour with a line segment? + //FIXME: Close the contour with a line segment? //_lineTo(rw, UPSCALE(outline->pts[first])); close: first = last + 1; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 12ce6de9..b8397df5 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -144,12 +144,57 @@ int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* p auto impl = pImpl.get(); assert(impl); + impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); return 0; } +int ShapeNode::moveTo(float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->moveTo(x, y); + + return 0; +} + + +int ShapeNode::lineTo(float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->lineTo(x, y); + + return 0; +} + + +int ShapeNode::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); + + return 0; +} + + +int ShapeNode::close() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->close(); + + return 0; +} + + int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index f4fee181..2849099f 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -56,12 +56,6 @@ struct ShapePath assert(pts); } - void reserve(size_t cmdCnt, size_t ptsCnt) - { - reserveCmd(cmdCnt); - reservePts(ptsCnt); - } - void grow(size_t cmdCnt, size_t ptsCnt) { reserveCmd(this->cmdCnt + cmdCnt); @@ -76,7 +70,6 @@ struct ShapePath void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) { - grow(cmdCnt, ptsCnt); memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); this->cmdCnt += cmdCnt; @@ -114,6 +107,8 @@ struct ShapePath void close() { + if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return; + if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); cmds[cmdCnt++] = PathCommand::Close; } diff --git a/test/makefile b/test/makefile index e213907d..1471ecde 100644 --- a/test/makefile +++ b/test/makefile @@ -4,3 +4,4 @@ all: gcc -o testMergeShapes testMergeShapes.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 testPath2 testPath2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testPath2.cpp b/test/testPath2.cpp new file mode 100644 index 00000000..3c6738a4 --- /dev/null +++ b/test/testPath2.cpp @@ -0,0 +1,89 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Star + auto shape1 = tvg::ShapeNode::gen(); + + //Appends Paths + shape1->moveTo(199, 34); + shape1->lineTo(253, 143); + shape1->lineTo(374, 160); + shape1->lineTo(287, 244); + shape1->lineTo(307, 365); + shape1->lineTo(199, 309); + shape1->lineTo(97, 365); + shape1->lineTo(112, 245); + shape1->lineTo(26, 161); + shape1->lineTo(146, 143); + shape1->close(); + shape1->fill(0, 0, 255, 255); + canvas->push(move(shape1)); + + //Circle + auto shape2 = tvg::ShapeNode::gen(); + + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Append Paths + shape2->moveTo(cx, cy - radius); + 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->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)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 14efeb4f0b84858a3a8c1f21c42868ed6bd7cee3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 23:40:35 +0900 Subject: [PATCH 034/244] test: updated comments Change-Id: I92fccb5a9de088f837a768a2f1d60ac94eac9410 --- test/testMergeShapes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index b37440b6..268e9586 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -16,7 +16,7 @@ void tvgtest() //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //Prepare a Shape (Rectangle + Rectangle + Circle) + //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::ShapeNode::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 From 2f174560ebe96ed6bbf779361d9301412cb920b7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 1 May 2020 12:46:54 +0900 Subject: [PATCH 035/244] test: rename testPath to testPathCopy Change-Id: I8cf2a26437a804d2cd061d61d3a99b3c6f3aa0e6 --- .gitignore | 2 +- test/makefile | 2 +- test/testPath.cpp | 88 ++++++++-------------------- test/testPath2.cpp | 89 ----------------------------- test/testPathCopy.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 155 deletions(-) delete mode 100644 test/testPath2.cpp create mode 100644 test/testPathCopy.cpp diff --git a/.gitignore b/.gitignore index 8e92d138..2c0e514f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ testMultiShapes testMergeShapes testBoundary testPath -testPath2 +testPathCopy diff --git a/test/makefile b/test/makefile index 1471ecde..e28d76ba 100644 --- a/test/makefile +++ b/test/makefile @@ -4,4 +4,4 @@ all: gcc -o testMergeShapes testMergeShapes.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 testPath2 testPath2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testPath.cpp b/test/testPath.cpp index a75c7f71..3c6738a4 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -16,79 +16,39 @@ void tvgtest() //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - /* Star */ - - //Prepare Path Commands - tvg::PathCommand cmds[11]; - cmds[0] = tvg::PathCommand::MoveTo; - cmds[1] = tvg::PathCommand::LineTo; - cmds[2] = tvg::PathCommand::LineTo; - cmds[3] = tvg::PathCommand::LineTo; - cmds[4] = tvg::PathCommand::LineTo; - cmds[5] = tvg::PathCommand::LineTo; - cmds[6] = tvg::PathCommand::LineTo; - cmds[7] = tvg::PathCommand::LineTo; - cmds[8] = tvg::PathCommand::LineTo; - cmds[9] = tvg::PathCommand::LineTo; - cmds[10] = tvg::PathCommand::Close; - - //Prepare Path Points - tvg::Point pts[10]; - pts[0] = {199, 34}; //MoveTo - pts[1] = {253, 143}; //LineTo - pts[2] = {374, 160}; //LineTo - pts[3] = {287, 244}; //LineTo - pts[4] = {307, 365}; //LineTo - pts[5] = {199, 309}; //LineTo - pts[6] = {97, 365}; //LineTo - pts[7] = {112, 245}; //LineTo - pts[8] = {26, 161}; //LineTo - pts[9] = {146, 143}; //LineTo - + //Star auto shape1 = tvg::ShapeNode::gen(); - shape1->appendPath(cmds, 11, pts, 10); //copy path data - shape1->fill(0, 255, 0, 255); + + //Appends Paths + shape1->moveTo(199, 34); + shape1->lineTo(253, 143); + shape1->lineTo(374, 160); + shape1->lineTo(287, 244); + shape1->lineTo(307, 365); + shape1->lineTo(199, 309); + shape1->lineTo(97, 365); + shape1->lineTo(112, 245); + shape1->lineTo(26, 161); + shape1->lineTo(146, 143); + shape1->close(); + shape1->fill(0, 0, 255, 255); canvas->push(move(shape1)); + //Circle + auto shape2 = tvg::ShapeNode::gen(); - /* Circle */ auto cx = 550.0f; auto cy = 550.0f; auto radius = 125.0f; auto halfRadius = radius * 0.552284f; - //Prepare Path Commands - tvg::PathCommand cmds2[6]; - cmds2[0] = tvg::PathCommand::MoveTo; - cmds2[1] = tvg::PathCommand::CubicTo; - cmds2[2] = tvg::PathCommand::CubicTo; - cmds2[3] = tvg::PathCommand::CubicTo; - cmds2[4] = tvg::PathCommand::CubicTo; - cmds2[5] = tvg::PathCommand::Close; - - //Prepare Path Points - tvg::Point pts2[13]; - pts2[0] = {cx, cy - radius}; //MoveTo - //CubicTo 1 - pts2[1] = {cx + halfRadius, cy - radius}; //Ctrl1 - pts2[2] = {cx + radius, cy - halfRadius}; //Ctrl2 - pts2[3] = {cx + radius, cy}; //To - //CubicTo 2 - pts2[4] = {cx + radius, cy + halfRadius}; //Ctrl1 - pts2[5] = {cx + halfRadius, cy + radius}; //Ctrl2 - pts2[6] = {cx, cy+ radius}; //To - //CubicTo 3 - pts2[7] = {cx - halfRadius, cy + radius}; //Ctrl1 - pts2[8] = {cx - radius, cy + halfRadius}; //Ctrl2 - pts2[9] = {cx - radius, cy}; //To - //CubicTo 4 - pts2[10] = {cx - radius, cy - halfRadius}; //Ctrl1 - pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 - pts2[12] = {cx, cy - radius}; //To - - auto shape2 = tvg::ShapeNode::gen(); - shape2->appendPath(cmds2, 6, pts2, 13); //copy path data - shape2->fill(255, 255, 0, 255); + //Append Paths + shape2->moveTo(cx, cy - radius); + 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->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)); canvas->draw(); diff --git a/test/testPath2.cpp b/test/testPath2.cpp deleted file mode 100644 index 3c6738a4..00000000 --- a/test/testPath2.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() -{ - //Initialize TizenVG Engine - tvg::Engine::init(); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - - //Star - auto shape1 = tvg::ShapeNode::gen(); - - //Appends Paths - shape1->moveTo(199, 34); - shape1->lineTo(253, 143); - shape1->lineTo(374, 160); - shape1->lineTo(287, 244); - shape1->lineTo(307, 365); - shape1->lineTo(199, 309); - shape1->lineTo(97, 365); - shape1->lineTo(112, 245); - shape1->lineTo(26, 161); - shape1->lineTo(146, 143); - shape1->close(); - shape1->fill(0, 0, 255, 255); - canvas->push(move(shape1)); - - //Circle - auto shape2 = tvg::ShapeNode::gen(); - - auto cx = 550.0f; - auto cy = 550.0f; - auto radius = 125.0f; - auto halfRadius = radius * 0.552284f; - - //Append Paths - shape2->moveTo(cx, cy - radius); - 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->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)); - - canvas->draw(); - canvas->sync(); - - //Terminate TizenVG Engine - tvg::Engine::term(); -} - -void -win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - -int main(int argc, char **argv) -{ - tvgtest(); - - //Show the result using EFL... - elm_init(argc, argv); - - Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); -} diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp new file mode 100644 index 00000000..a75c7f71 --- /dev/null +++ b/test/testPathCopy.cpp @@ -0,0 +1,129 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + /* Star */ + + //Prepare Path Commands + tvg::PathCommand cmds[11]; + cmds[0] = tvg::PathCommand::MoveTo; + cmds[1] = tvg::PathCommand::LineTo; + cmds[2] = tvg::PathCommand::LineTo; + cmds[3] = tvg::PathCommand::LineTo; + cmds[4] = tvg::PathCommand::LineTo; + cmds[5] = tvg::PathCommand::LineTo; + cmds[6] = tvg::PathCommand::LineTo; + cmds[7] = tvg::PathCommand::LineTo; + cmds[8] = tvg::PathCommand::LineTo; + cmds[9] = tvg::PathCommand::LineTo; + cmds[10] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts[10]; + pts[0] = {199, 34}; //MoveTo + pts[1] = {253, 143}; //LineTo + pts[2] = {374, 160}; //LineTo + pts[3] = {287, 244}; //LineTo + pts[4] = {307, 365}; //LineTo + pts[5] = {199, 309}; //LineTo + pts[6] = {97, 365}; //LineTo + pts[7] = {112, 245}; //LineTo + pts[8] = {26, 161}; //LineTo + pts[9] = {146, 143}; //LineTo + + auto shape1 = tvg::ShapeNode::gen(); + shape1->appendPath(cmds, 11, pts, 10); //copy path data + shape1->fill(0, 255, 0, 255); + canvas->push(move(shape1)); + + + /* Circle */ + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Prepare Path Commands + tvg::PathCommand cmds2[6]; + cmds2[0] = tvg::PathCommand::MoveTo; + cmds2[1] = tvg::PathCommand::CubicTo; + cmds2[2] = tvg::PathCommand::CubicTo; + cmds2[3] = tvg::PathCommand::CubicTo; + cmds2[4] = tvg::PathCommand::CubicTo; + cmds2[5] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts2[13]; + pts2[0] = {cx, cy - radius}; //MoveTo + //CubicTo 1 + pts2[1] = {cx + halfRadius, cy - radius}; //Ctrl1 + pts2[2] = {cx + radius, cy - halfRadius}; //Ctrl2 + pts2[3] = {cx + radius, cy}; //To + //CubicTo 2 + pts2[4] = {cx + radius, cy + halfRadius}; //Ctrl1 + pts2[5] = {cx + halfRadius, cy + radius}; //Ctrl2 + pts2[6] = {cx, cy+ radius}; //To + //CubicTo 3 + pts2[7] = {cx - halfRadius, cy + radius}; //Ctrl1 + pts2[8] = {cx - radius, cy + halfRadius}; //Ctrl2 + pts2[9] = {cx - radius, cy}; //To + //CubicTo 4 + pts2[10] = {cx - radius, cy - halfRadius}; //Ctrl1 + pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 + pts2[12] = {cx, cy - radius}; //To + + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendPath(cmds2, 6, pts2, 13); //copy path data + shape2->fill(255, 255, 0, 255); + canvas->push(move(shape2)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 74d2f275e74c4aa4bf3b9b68f297c2d0f95d8c80 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 1 May 2020 13:59:02 +0900 Subject: [PATCH 036/244] sw_engine: support color blending this contains testBlending as well Change-Id: Ia0aadea804a973cfe8ec981ed1b21c1b44512ef2 --- .gitignore | 1 + inc/tizenvg.h | 4 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRaster.cpp | 58 +++++++++++++++-- src/lib/sw_engine/tvgSwRenderer.cpp | 31 ++++++--- src/lib/sw_engine/tvgSwRenderer.h | 3 +- src/lib/tvgRenderCommon.h | 2 +- src/lib/tvgSwCanvas.cpp | 10 ++- test/makefile | 1 + test/testBlending.cpp | 97 +++++++++++++++++++++++++++++ test/testBoundary.cpp | 3 +- test/testMergeShapes.cpp | 3 +- test/testMultiShapes.cpp | 3 +- test/testPath.cpp | 3 +- test/testPathCopy.cpp | 3 +- test/testShape.cpp | 3 +- 16 files changed, 194 insertions(+), 33 deletions(-) create mode 100644 test/testBlending.cpp diff --git a/.gitignore b/.gitignore index 2c0e514f..c26c55d2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ testMergeShapes testBoundary testPath testPathCopy +testBlending diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 83e5f1d0..87086957 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -179,9 +179,9 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - int target(uint32_t* buffer, size_t stride, size_t height) noexcept; + int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; - static std::unique_ptr gen(uint32_t* buffer = nullptr, size_t stride = 0, size_t height = 0) noexcept; + static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(SwCanvas); }; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 012f9681..4b31bcd2 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -99,6 +99,6 @@ bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); -bool rasterShape(Surface& surface, SwShape& sdata, size_t color); +bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index a71c4433..29350db3 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -20,20 +20,66 @@ #include "tvgSwCommon.h" -bool rasterShape(Surface& surface, SwShape& sdata, size_t color) +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) +{ + return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + + ((((color & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); +} + + +static inline size_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (a << 24 | r << 16 | g << 8 | b); +} + + +static void +_drawTranslucentSpan(uint32_t* dst, size_t len, size_t color, size_t alpha) +{ + //OPTIMIZE ME: SIMD + auto ialpha = 255 - alpha; + for (size_t i = 0; i < len; ++i) { + dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); + } +} + + +static void +_drawSolidSpan(uint32_t* dst, size_t len, size_t color) +{ + //OPTIMIZE ME: SIMD + for (size_t i = 0; i < len; ++i) { + dst[i] = color; + } +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { SwRleData* rle = sdata.rle; if (!rle) return false; - auto stride = surface.stride; auto span = rle->spans; + auto stride = surface.stride; + auto color = COLOR_ARGB_JOIN(r, g, b, a); for (size_t i = 0; i < rle->size; ++i) { assert(span); -// printf("raster y(%d) x(%d) len(%d)\n", span->y, span->x, span->len); - for (auto j = 0; j < span->len; ++j) { - surface.buffer[span->y * stride + span->x + j] = color; - } + + auto dst = &surface.buffer[span->y * stride + span->x]; + assert(dst); + + if (a == 255) _drawSolidSpan(dst, span->len, color); + else _drawTranslucentSpan(dst, span->len, color, a); + ++span; } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index ae43735d..983a1cab 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -26,22 +26,33 @@ static RenderInitializer renderInit; -static inline size_t COLOR(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (a << 24 | r << 16 | g << 8 | b); -} - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t height) +bool SwRenderer::clear() { - assert(buffer && stride > 0 && height > 0); + if (!surface.buffer) return false; + + assert(surface.stride > 0 && surface.w > 0 && surface.h > 0); + + //OPTIMIZE ME: SIMD! + for (size_t i = 0; i < surface.h; i++) { + for (size_t j = 0; j < surface.w; j++) + surface.buffer[surface.stride * i + j] = 0xff000000; //Solid Black + } + + return true; +} + +bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) +{ + assert(buffer && stride > 0 && w > 0 && h > 0); surface.buffer = buffer; surface.stride = stride; - surface.height = height; + surface.w = w; + surface.h = h; return true; } @@ -57,7 +68,7 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) shape.fill(&r, &g, &b, &a); //TODO: Threading - return rasterShape(surface, *sdata, COLOR(r, g, b, a)); + return rasterShape(surface, *sdata, r, g, b, a); } @@ -92,7 +103,7 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; - SwSize clip = {static_cast(surface.stride), static_cast(surface.height)}; + SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index f8ce1d4b..5de6c128 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -25,7 +25,8 @@ public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; bool dispose(const ShapeNode& shape, void *data) override; bool render(const ShapeNode& shape, void *data) override; - bool target(uint32_t* buffer, size_t stride, size_t height); + bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); + bool clear(); size_t ref() override; size_t unref() override; diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index acdfc2fd..ccbc4151 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -25,7 +25,7 @@ struct Surface //TODO: Union for multiple types uint32_t* buffer; size_t stride; - size_t height; + size_t w, h; }; class RenderMethod diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 04902fc6..668c377a 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,12 +45,13 @@ SwCanvas::~SwCanvas() } -int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept +int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(engine()); assert(renderer); - if (!renderer->target(buffer, stride, height)) return -1; + if (!renderer->target(buffer, stride, w, h)) return -1; + if (!renderer->clear()) return -1; return 0; } @@ -62,14 +63,11 @@ int SwCanvas::sync() noexcept } -unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t height) noexcept +unique_ptr SwCanvas::gen() noexcept { auto canvas = unique_ptr(new SwCanvas); assert(canvas); - int ret = canvas.get()->target(buffer, stride, height); - if (ret > 0) return nullptr; - return canvas; } diff --git a/test/makefile b/test/makefile index e28d76ba..f455654a 100644 --- a/test/makefile +++ b/test/makefile @@ -5,3 +5,4 @@ all: 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` diff --git a/test/testBlending.cpp b/test/testBlending.cpp new file mode 100644 index 00000000..ef142aa7 --- /dev/null +++ b/test/testBlending.cpp @@ -0,0 +1,97 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + canvas->reserve(5); + + //Prepare Round Rectangle + auto shape1 = tvg::ShapeNode::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)); + + //Prepare Circle + auto shape2 = tvg::ShapeNode::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)); + + //Prepare Ellipse + auto shape3 = tvg::ShapeNode::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)); + + //Prepare Star + auto shape4 = tvg::ShapeNode::gen(); + shape4->moveTo(199, 234); + shape4->lineTo(253, 343); + shape4->lineTo(374, 360); + shape4->lineTo(287, 444); + shape4->lineTo(307, 565); + shape4->lineTo(199, 509); + shape4->lineTo(97, 565); + shape4->lineTo(112, 445); + shape4->lineTo(26, 361); + shape4->lineTo(146, 343); + shape4->close(); + shape4->fill(200, 0, 200, 200); + canvas->push(move(shape4)); + + //Prepare Opaque Ellipse + auto shape5 = tvg::ShapeNode::gen(); + 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 TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 473fd59c..7d305be9 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(5); //reserve 5 shape nodes (optional) //Prepare Shape1 diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 268e9586..27ef0c57 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 6fc0469f..d53e9fc4 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle diff --git a/test/testPath.cpp b/test/testPath.cpp index 3c6738a4..1ae897d6 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Star auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index a75c7f71..e555226f 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); /* Star */ diff --git a/test/testShape.cpp b/test/testShape.cpp index b7fca2f9..4386637a 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); From 11e070d1672d6ff88f47ee365d27b296c674cf09 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 1 May 2020 17:15:31 +0900 Subject: [PATCH 037/244] sw_engine: support anti-aliasing Change-Id: I9b79c8b4022ddf2ae4fe980f480ba3ec140750d3 --- src/lib/sw_engine/tvgSwRaster.cpp | 35 +++++++++++++++++++++++-------- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 29350db3..0b813fdf 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,6 +24,12 @@ /* Internal Class Implementation */ /************************************************************************/ +static inline size_t COLOR_ALPHA(size_t color) +{ + return (color >> 24) & 0xff; +} + + static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) { return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + @@ -33,15 +39,18 @@ static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) static inline size_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (a << 24 | r << 16 | g << 8 | b); + return (a << 24 | r << 16 | g << 8 | b); } static void -_drawTranslucentSpan(uint32_t* dst, size_t len, size_t color, size_t alpha) +_rasterTranslucent(uint32_t* dst, size_t len, size_t color, size_t cov) { //OPTIMIZE ME: SIMD - auto ialpha = 255 - alpha; + + if (cov < 255) color = COLOR_ALPHA_BLEND(color, cov); + auto ialpha = 255 - COLOR_ALPHA(color); + for (size_t i = 0; i < len; ++i) { dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); } @@ -49,11 +58,20 @@ _drawTranslucentSpan(uint32_t* dst, size_t len, size_t color, size_t alpha) static void -_drawSolidSpan(uint32_t* dst, size_t len, size_t color) +_rasterSolid(uint32_t* dst, size_t len, size_t color, size_t cov) { //OPTIMIZE ME: SIMD - for (size_t i = 0; i < len; ++i) { - dst[i] = color; + + //Fully Opaque + if (cov == 255) { + for (size_t i = 0; i < len; ++i) { + dst[i] = color; + } + } else { + auto ialpha = 255 - cov; + for (size_t i = 0; i < len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(color, cov) + COLOR_ALPHA_BLEND(dst[i], ialpha); + } } } @@ -75,10 +93,9 @@ bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t assert(span); auto dst = &surface.buffer[span->y * stride + span->x]; - assert(dst); - if (a == 255) _drawSolidSpan(dst, span->len, color); - else _drawTranslucentSpan(dst, span->len, color, a); + if (a == 255) _rasterSolid(dst, span->len, color, span->coverage); + else _rasterTranslucent(dst, span->len, color, span->coverage); ++span; } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5166de8e..f915a5db 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -434,8 +434,8 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) /* These macros speed up repetitive divisions by replacing them with multiplications and right shifts. */ - auto dx_r = (ULONG_MAX >> PIXEL_BITS) / (diff.x); - auto dy_r = (ULONG_MAX >> PIXEL_BITS) / (diff.y); + auto dx_r = static_cast(ULONG_MAX >> PIXEL_BITS) / (diff.x); + auto dy_r = static_cast(ULONG_MAX >> PIXEL_BITS) / (diff.y); /* The fundamental value `prod' determines which side and the */ /* exact coordinate where the line exits current cell. It is */ From c923d881aa8ecdb04d5f296bc3e6ea5d4dcff289 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 10:55:33 +0900 Subject: [PATCH 038/244] test: added testUpdate this shows a moving shape: how to update canvas every frames. Change-Id: I373e39757f4511d4e676f36d76e468d03b185a0c --- .gitignore | 1 + inc/tizenvg.h | 1 + src/lib/tvgSwCanvas.cpp | 11 +++++ test/makefile | 1 + test/testUpdate.cpp | 107 ++++++++++++++++++++++++++-------------- 5 files changed, 85 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index c26c55d2..06f90992 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ testBoundary testPath testPathCopy testBlending +testUpdate diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 87086957..f3252765 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -179,6 +179,7 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); + int clear() noexcept override; int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 668c377a..cc26cbd8 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,6 +45,17 @@ SwCanvas::~SwCanvas() } +int SwCanvas::clear() noexcept +{ + auto renderer = dynamic_cast(engine()); + assert(renderer); + + if (!renderer->clear()) return -1; + + return Canvas::clear(); +} + + int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(engine()); diff --git a/test/makefile b/test/makefile index f455654a..e12fb317 100644 --- a/test/makefile +++ b/test/makefile @@ -6,3 +6,4 @@ all: 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` diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 3a812897..c4250fbf 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -6,50 +7,84 @@ using namespace std; #define HEIGHT 800 static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape + auto shape = tvg::ShapeNode::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) +{ + //Explicitly clear all retained paint nodes. + canvas->clear(); + + //Shape + auto shape = tvg::ShapeNode::gen(); + shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + shape->fill(rand()%255, rand()%255, rand()%255, 255); + canvas->push(move(shape)); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} int main(int argc, char **argv) { - //Initialize TizenVG Engine - tvg::Engine::init(); + //Initialize TizenVG Engine + tvg::Engine::init(); - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + tvgtest(); - //Create a Scene - auto scene = tvg::SceneNode::gen(); + //Show the result using EFL... + elm_init(argc, argv); - //Shape1 - auto shape1 = tvg::ShapeNode::gen(); + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); - /* Acquire shape1 pointer to access directly later. - instead, you should consider not to interrupt this pointer life-cycle. */ - auto pshape1 = shape1->get(); + 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); - shape1->rect(0, 0, 400, 400, 0.1); - shape1->fill(255, 0, 0, 255); - shape1->rotate(0, 0, 45); //axis x, y, z + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); - scene->push(move(shape1)); - canvas->push(move(scene)); + 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); - //Draw first frame - canvas->draw(); - canvas->sync(); + elm_run(); + elm_shutdown(); - /* Clear the previous shape path and Prepare a new shape path. - You can call clear() to explicitly clear path data. */ - pshape1->rect(0, 0, 300, 300, 0.1); - - //Prepapre for drawing (this may work asynchronously) - pshape1->update(); - - //Draw second frame - canvas->draw(); - canvas->sync(); - - //Explicitly clear all retained paint nodes. - canvas->clear(); - - //Terminate TizenVG Engine - tvg::Engine::term(); -} + //Terminate TizenVG Engine + tvg::Engine::term(); +} \ No newline at end of file From a8864390e289d6ea156748c4c4017506f9687a43 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 11:14:14 +0900 Subject: [PATCH 039/244] canvas: code refactoring accept an extra argument in the clear() to clear paints node and clear buffer selectively. Change-Id: I83721e74358f546f325bb03fd1f36c7565174dd7 --- inc/tizenvg.h | 3 +-- src/lib/gl_engine/tvgGlRenderer.cpp | 5 +++++ src/lib/gl_engine/tvgGlRenderer.h | 1 + src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/tvgCanvas.cpp | 27 ++++++++++++++++----------- src/lib/tvgRenderCommon.h | 1 + src/lib/tvgSwCanvas.cpp | 12 ------------ 7 files changed, 25 insertions(+), 26 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index f3252765..40f38acb 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -92,7 +92,7 @@ public: int reserve(size_t n) noexcept; virtual int push(std::unique_ptr paint) noexcept; - virtual int clear() noexcept; + virtual int clear(bool clearPaints = true) noexcept; virtual int update() noexcept; virtual int draw(bool async = true) noexcept; virtual int sync() = 0; @@ -179,7 +179,6 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - int clear() noexcept override; int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 38fb4dee..8cf84da3 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -35,6 +35,11 @@ struct GlShape /* External Class Implementation */ /************************************************************************/ +bool GlRenderer::clear() +{ + return true; +} + bool GlRenderer::render(const ShapeNode& shape, void *data) { GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 881d1efa..b6b95631 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -26,6 +26,7 @@ public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; bool dispose(const ShapeNode& shape, void *data) override; bool render(const ShapeNode& shape, void *data) override; + bool clear() override; size_t ref() override; size_t unref() override; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 5de6c128..95c5a0a1 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -26,7 +26,7 @@ public: bool dispose(const ShapeNode& shape, void *data) override; bool render(const ShapeNode& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); - bool clear(); + bool clear() override; size_t ref() override; size_t unref() override; diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 37230838..e1f41b74 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -36,7 +36,7 @@ struct Canvas::Impl ~Impl() { - clear(); + clearPaints(); renderer->unref(); } @@ -55,23 +55,27 @@ struct Canvas::Impl return node->update(renderer); } - int clear() + bool clearRender() { assert(renderer); + return renderer->clear()); + } - auto ret = 0; + int clearPaints() + { + assert(renderer); for (auto node : nodes) { if (SceneNode *scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; } else if (ShapeNode *shape = dynamic_cast(node)) { - ret |= renderer->dispose(*shape, shape->engine()); + if (!renderer->dispose(*shape, shape->engine())) return -1; } delete(node); } nodes.clear(); - return ret; + return 0; } int update() @@ -91,16 +95,14 @@ struct Canvas::Impl { assert(renderer); - auto ret = 0; - for(auto node: nodes) { if (SceneNode *scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; } else if (ShapeNode *shape = dynamic_cast(node)) { - ret |= renderer->render(*shape, shape->engine()); + if (!renderer->render(*shape, shape->engine())) return -1; } } - return ret; + return 0; } }; @@ -137,11 +139,14 @@ int Canvas::push(unique_ptr paint) noexcept } -int Canvas::clear() noexcept +int Canvas::clear(bool clearPaints) noexcept { auto impl = pImpl.get(); assert(impl); - return impl->clear(); + auto ret = 0; + if (clearPaints) ret |= impl->clearPaints(); + ret |= impl->clearRender(); + return ret; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index ccbc4151..07b33cd8 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -36,6 +36,7 @@ public: virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; virtual bool dispose(const ShapeNode& shape, void *data) = 0; virtual bool render(const ShapeNode& shape, void *data) = 0; + virtual bool clear() = 0; virtual size_t ref() = 0; virtual size_t unref() = 0; }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index cc26cbd8..f75d79c1 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -44,18 +44,6 @@ SwCanvas::~SwCanvas() { } - -int SwCanvas::clear() noexcept -{ - auto renderer = dynamic_cast(engine()); - assert(renderer); - - if (!renderer->clear()) return -1; - - return Canvas::clear(); -} - - int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(engine()); From 0be7e0cf539dccc962153c7ba106d9858a2e72a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 17:28:18 +0900 Subject: [PATCH 040/244] canvas: migrate render target clear call into draw(); Obivously, we need to clear target before drawing. Thus canvas request to renderers to clear buffer. the implementation is upto backend engines. Change-Id: Ib80da7f2260b021bcfed9fa13fb91c20218f9da0 --- inc/tizenvg.h | 2 +- src/lib/gl_engine/tvgGlRenderer.cpp | 2 ++ src/lib/tvgCanvas.cpp | 26 +++++++++----------------- src/lib/tvgSwCanvas.cpp | 1 - 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 40f38acb..87086957 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -92,7 +92,7 @@ public: int reserve(size_t n) noexcept; virtual int push(std::unique_ptr paint) noexcept; - virtual int clear(bool clearPaints = true) noexcept; + virtual int clear() noexcept; virtual int update() noexcept; virtual int draw(bool async = true) noexcept; virtual int sync() = 0; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 8cf84da3..ca319ed7 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -37,6 +37,8 @@ struct GlShape bool GlRenderer::clear() { + //TODO: (Request) to clear target + return true; } diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index e1f41b74..d9bf1764 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -36,7 +36,7 @@ struct Canvas::Impl ~Impl() { - clearPaints(); + clear(); renderer->unref(); } @@ -55,13 +55,7 @@ struct Canvas::Impl return node->update(renderer); } - bool clearRender() - { - assert(renderer); - return renderer->clear()); - } - - int clearPaints() + int clear() { assert(renderer); @@ -82,19 +76,20 @@ struct Canvas::Impl { assert(renderer); - auto ret = 0; - for(auto node: nodes) { - ret |= node->update(renderer); + if (!node->update(renderer)) return -1; } - return ret; + return 0; } int draw() { assert(renderer); + //Clear render target before drawing + if (!renderer->clear()) return -1; + for(auto node: nodes) { if (SceneNode *scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; @@ -139,14 +134,11 @@ int Canvas::push(unique_ptr paint) noexcept } -int Canvas::clear(bool clearPaints) noexcept +int Canvas::clear() noexcept { auto impl = pImpl.get(); assert(impl); - auto ret = 0; - if (clearPaints) ret |= impl->clearPaints(); - ret |= impl->clearRender(); - return ret; + return impl->clear(); } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index f75d79c1..a4e49ddb 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -50,7 +50,6 @@ int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexce assert(renderer); if (!renderer->target(buffer, stride, w, h)) return -1; - if (!renderer->clear()) return -1; return 0; } From 60d104a40a96ae0ac6439e16c0b878a55e9571eb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 17:44:49 +0900 Subject: [PATCH 041/244] sw_engine: code refactoring. renamed internal variables for better readibility. Change-Id: I1ba7938401e8b7249c8bcc396be1ba3c109716cd --- src/lib/sw_engine/tvgSwCommon.h | 6 +++--- src/lib/sw_engine/tvgSwRle.cpp | 14 +++++++------- src/lib/sw_engine/tvgSwShape.cpp | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4b31bcd2..2900577d 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -21,8 +21,8 @@ using namespace tvg; -constexpr auto SW_CURVE_TAG_ON = 1; -constexpr auto SW_CURVE_TAG_CUBIC = 2; +constexpr auto SW_CURVE_TYPE_POINT = 0; +constexpr auto SW_CURVE_TYPE_CUBIC = 1; constexpr auto SW_OUTLINE_FILL_WINDING = 0; constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; @@ -62,7 +62,7 @@ struct SwOutline SwPoint* pts; //the outline's points size_t ptsCnt; //number of points in the glyph size_t reservedPtsCnt; - char* tags; //the points flags + uint8_t* types; //curve type uint8_t fillMode; //outline fill mode }; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f915a5db..ea2e4511 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -606,27 +606,27 @@ static bool _decomposeOutline(RleWorker& rw) assert(limit); auto pt = outline->pts + first; - auto tags = outline->tags + first; + auto types = outline->types + first; /* A contour cannot start with a cubic control point! */ - if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline; + if (types[0] == SW_CURVE_TYPE_CUBIC) goto invalid_outline; _moveTo(rw, UPSCALE(outline->pts[first])); while (pt < limit) { assert(++pt); - assert(++tags); + assert(++types); //emit a single line_to - if (tags[0] == SW_CURVE_TAG_ON) { + if (types[0] == SW_CURVE_TYPE_POINT) { _lineTo(rw, UPSCALE(*pt)); - //tag cubic + //types cubic } else { - if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC) + if (pt + 1 > limit || types[1] != SW_CURVE_TYPE_CUBIC) goto invalid_outline; pt += 2; - tags += 2; + types += 2; if (pt <= limit) { _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0])); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 1f24a631..82235456 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -52,8 +52,8 @@ static void _growOutlinePoint(SwOutline& outline, size_t n) if (n == 0) { free(outline.pts); outline.pts = nullptr; - free(outline.tags); - outline.tags = nullptr; + free(outline.types); + outline.types = nullptr; outline.reservedPtsCnt = 0; outline.ptsCnt = 0; return; @@ -65,8 +65,8 @@ static void _growOutlinePoint(SwOutline& outline, size_t n) outline.reservedPtsCnt = n; outline.pts = static_cast(realloc(outline.pts, n * sizeof(SwPoint))); assert(outline.pts); - outline.tags = static_cast(realloc(outline.tags, n * sizeof(char))); - assert(outline.tags); + outline.types = static_cast(realloc(outline.types, n * sizeof(uint8_t))); + assert(outline.types); } @@ -87,7 +87,7 @@ static void _outlineMoveTo(SwOutline& outline, const Point* to) _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = TO_SWPOINT(to); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; if (outline.ptsCnt > 0) { _growOutlineContour(outline, 1); @@ -106,7 +106,7 @@ static void _outlineLineTo(SwOutline& outline, const Point* to) _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = TO_SWPOINT(to); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } @@ -119,15 +119,15 @@ static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* _growOutlinePoint(outline, 3); outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; outline.pts[outline.ptsCnt] = TO_SWPOINT(to); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } @@ -149,7 +149,7 @@ static bool _outlineClose(SwOutline& outline) _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = outline.pts[i]; - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; return true; @@ -218,7 +218,7 @@ void _deleteOutline(SwShape& sdata) SwOutline* outline = sdata.outline; if (outline->cntrs) free(outline->cntrs); if (outline->pts) free(outline->pts); - if (outline->tags) free(outline->tags); + if (outline->types) free(outline->types); free(outline); sdata.outline = nullptr; From 1b3661a0b0bceb790f6352a9c89d0f9d081ade16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 18:06:06 +0900 Subject: [PATCH 042/244] common shape: renamed the method clear() to reset() Also, added one more showcase how to update only necessary properties of a shape while retaining other properties... Change-Id: If165bc7f8147cad0437e3ca2f7c007614c256248 --- .gitignore | 1 + inc/tizenvg.h | 2 +- src/lib/tvgShapeNode.cpp | 4 +- src/lib/tvgShapePath.h | 2 +- test/makefile | 1 + test/testDirectUpdate.cpp | 98 ++++++++++++++++++++++++++++++++++++ test/testUpdate.cpp | 102 +++++++++++++++++++------------------- 7 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 test/testDirectUpdate.cpp diff --git a/.gitignore b/.gitignore index 06f90992..a5643f45 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ testPath testPathCopy testBlending testUpdate +testDirectUpdate diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 87086957..4a947daf 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -117,7 +117,7 @@ public: ~ShapeNode(); int update(RenderMethod* engine) noexcept override; - int clear() noexcept; + int reset() noexcept; int moveTo(float x, float y) noexcept; int lineTo(float x, float y) noexcept; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index b8397df5..0a872115 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -103,12 +103,12 @@ int ShapeNode::update(RenderMethod* engine) noexcept } -int ShapeNode::clear() noexcept +int ShapeNode::reset() noexcept { auto impl = pImpl.get(); assert(impl); - impl->path->clear(); + impl->path->reset(); return 0; } diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 2849099f..6b016f1f 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -62,7 +62,7 @@ struct ShapePath reservePts(this->ptsCnt + ptsCnt); } - void clear() + void reset() { cmdCnt = 0; ptsCnt = 0; diff --git a/test/makefile b/test/makefile index e12fb317..23fd51a0 100644 --- a/test/makefile +++ b/test/makefile @@ -7,3 +7,4 @@ all: 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` diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp new file mode 100644 index 00000000..ac6bdc37 --- /dev/null +++ b/test/testDirectUpdate.cpp @@ -0,0 +1,98 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::ShapeNode* pShape = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape + auto shape = tvg::ShapeNode::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->appendRect(-100, -100, 200, 200, 0); + shape->fill(127, 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) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + pShape->reset(); //reset path + + pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + + //Update shape for drawing (this may work asynchronously) + pShape->update(canvas->engine()); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + 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 TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index c4250fbf..97e81ec0 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -11,80 +11,80 @@ unique_ptr canvas = nullptr; void tvgtest() { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape - auto shape = tvg::ShapeNode::gen(); - shape->appendRect(-100, -100, 200, 200, 0); - shape->fill(255, 255, 255, 255); - canvas->push(move(shape)); + //Shape + auto shape = tvg::ShapeNode::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(); + //Draw first frame + canvas->draw(); + canvas->sync(); } void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - //Explicitly clear all retained paint nodes. - canvas->clear(); + //Explicitly clear all retained paint nodes. + canvas->clear(); - //Shape - auto shape = tvg::ShapeNode::gen(); - shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); - shape->fill(rand()%255, rand()%255, rand()%255, 255); - canvas->push(move(shape)); + //Shape + auto shape = tvg::ShapeNode::gen(); + shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + shape->fill(rand()%255, rand()%255, rand()%255, 255); + canvas->push(move(shape)); - //Draw Next frames - canvas->draw(); - canvas->sync(); + //Draw Next frames + canvas->draw(); + canvas->sync(); - //Update Efl Canvas - Eo* img = (Eo*) effect; - evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } void win_del(void *data, Evas_Object *o, void *ev) { - elm_exit(); + elm_exit(); } int main(int argc, char **argv) { - //Initialize TizenVG Engine - tvg::Engine::init(); + //Initialize TizenVG Engine + tvg::Engine::init(); - tvgtest(); + tvgtest(); - //Show the result using EFL... - elm_init(argc, argv); + //Show the result using EFL... + elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); - 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_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(); + elm_run(); + elm_shutdown(); - //Terminate TizenVG Engine - tvg::Engine::term(); -} \ No newline at end of file + //Terminate TizenVG Engine + tvg::Engine::term(); +} From 42c56757df211b2f44f5fb25e1f35c980a0eb9aa Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 18:16:45 +0900 Subject: [PATCH 043/244] common: redesigned interfaces PaintNode -> Paint ShapeNode -> Shape SceneNode -> Scene We can keep clean and neat shorter names. Change-Id: Ic8521d456d947985e5fbe1ba2bde06faa1f52469 --- inc/tizenvg.h | 30 +++++++-------- src/lib/gl_engine/tvgGlRenderer.cpp | 6 +-- src/lib/gl_engine/tvgGlRenderer.h | 6 +-- src/lib/meson.build | 4 +- src/lib/sw_engine/tvgSwCommon.h | 8 ++-- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +-- src/lib/sw_engine/tvgSwRenderer.h | 6 +-- src/lib/sw_engine/tvgSwShape.cpp | 6 +-- src/lib/tvgCanvas.cpp | 18 ++++----- src/lib/tvgRenderCommon.h | 6 +-- src/lib/{tvgSceneNode.cpp => tvgScene.cpp} | 22 +++++------ src/lib/{tvgShapeNode.cpp => tvgShape.cpp} | 44 +++++++++++----------- test/testBlending.cpp | 10 ++--- test/testBoundary.cpp | 10 ++--- test/testComposition.cpp | 2 +- test/testDirectUpdate.cpp | 4 +- test/testGradient.cpp | 4 +- test/testMergeShapes.cpp | 2 +- test/testMultiShapes.cpp | 6 +-- test/testPath.cpp | 4 +- test/testPathCopy.cpp | 4 +- test/testScene.cpp | 8 ++-- test/testShape.cpp | 2 +- test/testStroke.cpp | 2 +- test/testUpdate.cpp | 4 +- 25 files changed, 112 insertions(+), 112 deletions(-) rename src/lib/{tvgSceneNode.cpp => tvgScene.cpp} (72%) rename src/lib/{tvgShapeNode.cpp => tvgShape.cpp} (82%) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 4a947daf..b443d503 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -61,17 +61,17 @@ struct Point /** - * @class PaintNode + * @class Paint * * @ingroup TizenVG * * @brief description... * */ -class TIZENVG_EXPORT PaintNode +class TIZENVG_EXPORT Paint { public: - virtual ~PaintNode() {} + virtual ~Paint() {} virtual int update(RenderMethod*) = 0; }; @@ -91,7 +91,7 @@ public: virtual ~Canvas(); int reserve(size_t n) noexcept; - virtual int push(std::unique_ptr paint) noexcept; + virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; virtual int draw(bool async = true) noexcept; @@ -104,17 +104,17 @@ public: /** - * @class ShapeNode + * @class Shape * * @ingroup TizenVG * * @brief description... * */ -class TIZENVG_EXPORT ShapeNode final : public PaintNode +class TIZENVG_EXPORT Shape final : public Paint { public: - ~ShapeNode(); + ~Shape(); int update(RenderMethod* engine) noexcept override; int reset() noexcept; @@ -134,35 +134,35 @@ public: int pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; - static std::unique_ptr gen() noexcept; + static std::unique_ptr gen() noexcept; //FIXME: Ugly... Better design? void *engine() noexcept; - _TIZENVG_DECLARE_PRIVATE(ShapeNode); + _TIZENVG_DECLARE_PRIVATE(Shape); }; /** - * @class SceneNode + * @class Scene * * @ingroup TizenVG * * @brief description... * */ -class TIZENVG_EXPORT SceneNode final : public PaintNode +class TIZENVG_EXPORT Scene final : public Paint { public: - ~SceneNode(); + ~Scene(); int update(RenderMethod* engine) noexcept override; - int push(std::unique_ptr shape) noexcept; + int push(std::unique_ptr shape) noexcept; - static std::unique_ptr gen() noexcept; + static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(SceneNode); + _TIZENVG_DECLARE_PRIVATE(Scene); }; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index ca319ed7..4e0aa518 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -42,7 +42,7 @@ bool GlRenderer::clear() return true; } -bool GlRenderer::render(const ShapeNode& shape, void *data) +bool GlRenderer::render(const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; @@ -53,7 +53,7 @@ bool GlRenderer::render(const ShapeNode& shape, void *data) } -bool GlRenderer::dispose(const ShapeNode& shape, void *data) +bool GlRenderer::dispose(const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const ShapeNode& shape, void *data) } -void* GlRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index b6b95631..a508eed6 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,9 +23,9 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - bool dispose(const ShapeNode& shape, void *data) override; - bool render(const ShapeNode& shape, void *data) override; + void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + bool dispose(const Shape& shape, void *data) override; + bool render(const Shape& shape, void *data) override; bool clear() override; size_t ref() override; size_t unref() override; diff --git a/src/lib/meson.build b/src/lib/meson.build index 976aa5ee..5b47bcf9 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -9,8 +9,8 @@ source_file = [ 'tvgCanvas.cpp', 'tvgSwCanvas.cpp', 'tvgGlCanvas.cpp', - 'tvgSceneNode.cpp', - 'tvgShapeNode.cpp' + 'tvgScene.cpp', + 'tvgShape.cpp' ] src_dep = declare_dependency( diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 2900577d..4d654c93 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -93,10 +93,10 @@ struct SwShape }; void shapeReset(SwShape& sdata); -bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata); -void shapeDelOutline(const ShapeNode& shape, SwShape& sdata); -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); -bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); +bool shapeGenOutline(const Shape& shape, SwShape& sdata); +void shapeDelOutline(const Shape& shape, SwShape& sdata); +bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); +bool shapeTransformOutline(const Shape& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 983a1cab..eda12cc1 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -58,7 +58,7 @@ bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) } -bool SwRenderer::render(const ShapeNode& shape, void *data) +bool SwRenderer::render(const Shape& shape, void *data) { SwShape* sdata = static_cast(data); if (!sdata) return false; @@ -72,7 +72,7 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) } -bool SwRenderer::dispose(const ShapeNode& shape, void *data) +bool SwRenderer::dispose(const Shape& shape, void *data) { SwShape* sdata = static_cast(data); if (!sdata) return false; @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const ShapeNode& shape, void *data) return true; } -void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 95c5a0a1..ce87fa9c 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,9 +22,9 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - bool dispose(const ShapeNode& shape, void *data) override; - bool render(const ShapeNode& shape, void *data) override; + void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + bool dispose(const Shape& shape, void *data) override; + bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); bool clear() override; size_t ref() override; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 82235456..5a1c6c3d 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -228,14 +228,14 @@ void _deleteOutline(SwShape& sdata) /* External Class Implementation */ /************************************************************************/ -bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) +bool shapeTransformOutline(const Shape& shape, SwShape& sdata) { //TODO: return true; } -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip) +bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) { if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) goto end; if (!_updateBBox(sdata)) goto end; @@ -262,7 +262,7 @@ void shapeReset(SwShape& sdata) } -bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) +bool shapeGenOutline(const Shape& shape, SwShape& sdata) { const PathCommand* cmds = nullptr; auto cmdCnt = shape.pathCommands(&cmds); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index d9bf1764..84a13275 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -26,10 +26,10 @@ struct Canvas::Impl { - vector nodes; + vector nodes; RenderMethod* renderer; - Impl(RenderMethod *pRenderer):renderer(pRenderer) + Impl(RenderMethod* pRenderer):renderer(pRenderer) { renderer->ref(); } @@ -47,9 +47,9 @@ struct Canvas::Impl return 0; } - int push(unique_ptr paint) + int push(unique_ptr paint) { - PaintNode *node = paint.release(); + Paint* node = paint.release(); assert(node); nodes.push_back(node); return node->update(renderer); @@ -60,9 +60,9 @@ struct Canvas::Impl assert(renderer); for (auto node : nodes) { - if (SceneNode *scene = dynamic_cast(node)) { + if (Scene* scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; - } else if (ShapeNode *shape = dynamic_cast(node)) { + } else if (Shape *shape = dynamic_cast(node)) { if (!renderer->dispose(*shape, shape->engine())) return -1; } delete(node); @@ -91,9 +91,9 @@ struct Canvas::Impl if (!renderer->clear()) return -1; for(auto node: nodes) { - if (SceneNode *scene = dynamic_cast(node)) { + if (Scene* scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; - } else if (ShapeNode *shape = dynamic_cast(node)) { + } else if (Shape *shape = dynamic_cast(node)) { if (!renderer->render(*shape, shape->engine())) return -1; } } @@ -125,7 +125,7 @@ int Canvas::reserve(size_t n) noexcept } -int Canvas::push(unique_ptr paint) noexcept +int Canvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 07b33cd8..5d619913 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -33,9 +33,9 @@ class RenderMethod public: enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RenderMethod() {} - virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; - virtual bool dispose(const ShapeNode& shape, void *data) = 0; - virtual bool render(const ShapeNode& shape, void *data) = 0; + virtual void* prepare(const Shape& shape, void* data, UpdateFlag flags) = 0; + virtual bool dispose(const Shape& shape, void *data) = 0; + virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; virtual size_t ref() = 0; virtual size_t unref() = 0; diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgScene.cpp similarity index 72% rename from src/lib/tvgSceneNode.cpp rename to src/lib/tvgScene.cpp index db3ae1d8..75725617 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgScene.cpp @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_SCENE_NODE_CPP_ -#define _TVG_SCENE_NODE_CPP_ +#ifndef _TVG_SCENE_CPP_ +#define _TVG_SCENE_CPP_ #include "tvgCommon.h" @@ -23,7 +23,7 @@ /* Internal Class Implementation */ /************************************************************************/ -struct SceneNode::Impl +struct Scene::Impl { }; @@ -34,34 +34,34 @@ struct SceneNode::Impl /* External Class Implementation */ /************************************************************************/ -SceneNode::SceneNode() : pImpl(make_unique()) +Scene::Scene() : pImpl(make_unique()) { } -SceneNode::~SceneNode() +Scene::~Scene() { - cout << "SceneNode(" << this << ") destroyed!" << endl; + cout << "Scene(" << this << ") destroyed!" << endl; } -unique_ptr SceneNode::gen() noexcept +unique_ptr Scene::gen() noexcept { - return unique_ptr(new SceneNode); + return unique_ptr(new Scene); } -int SceneNode::push(unique_ptr shape) noexcept +int Scene::push(unique_ptr shape) noexcept { return 0; } -int SceneNode::update(RenderMethod* engine) noexcept +int Scene::update(RenderMethod* engine) noexcept { return 0; } -#endif /* _TVG_SCENE_NODE_CPP_ */ +#endif /* _TVG_SCENE_CPP_ */ diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShape.cpp similarity index 82% rename from src/lib/tvgShapeNode.cpp rename to src/lib/tvgShape.cpp index 0a872115..5fbfce84 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShape.cpp @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_SHAPE_NODE_CPP_ -#define _TVG_SHAPE_NODE_CPP_ +#ifndef _TVG_SHAPE_CPP_ +#define _TVG_SHAPE_CPP_ #include "tvgCommon.h" #include "tvgShapePath.h" @@ -41,7 +41,7 @@ struct ShapeTransform }; -struct ShapeNode::Impl +struct Shape::Impl { ShapeTransform *transform = nullptr; ShapeFill *fill = nullptr; @@ -68,23 +68,23 @@ struct ShapeNode::Impl /* External Class Implementation */ /************************************************************************/ -ShapeNode :: ShapeNode() : pImpl(make_unique()) +Shape :: Shape() : pImpl(make_unique()) { } -ShapeNode :: ~ShapeNode() +Shape :: ~Shape() { } -unique_ptr ShapeNode::gen() noexcept +unique_ptr Shape::gen() noexcept { - return unique_ptr(new ShapeNode); + return unique_ptr(new Shape); } -void* ShapeNode::engine() noexcept +void* Shape::engine() noexcept { auto impl = pImpl.get(); assert(impl); @@ -92,7 +92,7 @@ void* ShapeNode::engine() noexcept } -int ShapeNode::update(RenderMethod* engine) noexcept +int Shape::update(RenderMethod* engine) noexcept { auto impl = pImpl.get(); assert(impl); @@ -103,7 +103,7 @@ int ShapeNode::update(RenderMethod* engine) noexcept } -int ShapeNode::reset() noexcept +int Shape::reset() noexcept { auto impl = pImpl.get(); assert(impl); @@ -114,7 +114,7 @@ int ShapeNode::reset() noexcept } -int ShapeNode::pathCommands(const PathCommand** cmds) const noexcept +int Shape::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); assert(impl && cmds); @@ -125,7 +125,7 @@ int ShapeNode::pathCommands(const PathCommand** cmds) const noexcept } -int ShapeNode::pathCoords(const Point** pts) const noexcept +int Shape::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); assert(impl && pts); @@ -136,7 +136,7 @@ int ShapeNode::pathCoords(const Point** pts) const noexcept } -int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept { if (cmdCnt < 0 || ptsCnt < 0) return -1; assert(cmds && pts); @@ -151,7 +151,7 @@ int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* p } -int ShapeNode::moveTo(float x, float y) noexcept +int Shape::moveTo(float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); @@ -162,7 +162,7 @@ int ShapeNode::moveTo(float x, float y) noexcept } -int ShapeNode::lineTo(float x, float y) noexcept +int Shape::lineTo(float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); @@ -173,7 +173,7 @@ int ShapeNode::lineTo(float x, float y) noexcept } -int ShapeNode::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept +int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); @@ -184,7 +184,7 @@ int ShapeNode::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, floa } -int ShapeNode::close() noexcept +int Shape::close() noexcept { auto impl = pImpl.get(); assert(impl); @@ -195,7 +195,7 @@ int ShapeNode::close() noexcept } -int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept +int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); assert(impl); @@ -215,7 +215,7 @@ int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) no } -int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept +int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); assert(impl); @@ -254,7 +254,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius } -int ShapeNode::fill(size_t r, size_t g, size_t b, size_t a) noexcept +int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -268,7 +268,7 @@ int ShapeNode::fill(size_t r, size_t g, size_t b, size_t a) noexcept } -int ShapeNode::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); @@ -281,4 +281,4 @@ int ShapeNode::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept return 0; } -#endif //_TVG_SHAPE_NODE_CPP_ +#endif //_TVG_SHAPE_CPP_ diff --git a/test/testBlending.cpp b/test/testBlending.cpp index ef142aa7..58ae0251 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -19,25 +19,25 @@ void tvgtest() canvas->reserve(5); //Prepare Round Rectangle - auto shape1 = tvg::ShapeNode::gen(); + 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)); //Prepare Circle - auto shape2 = tvg::ShapeNode::gen(); + 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)); //Prepare Ellipse - auto shape3 = tvg::ShapeNode::gen(); + 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)); //Prepare Star - auto shape4 = tvg::ShapeNode::gen(); + auto shape4 = tvg::Shape::gen(); shape4->moveTo(199, 234); shape4->lineTo(253, 343); shape4->lineTo(374, 360); @@ -53,7 +53,7 @@ void tvgtest() canvas->push(move(shape4)); //Prepare Opaque Ellipse - auto shape5 = tvg::ShapeNode::gen(); + auto shape5 = tvg::Shape::gen(); shape5->appendCircle(600, 650, 200, 150); shape5->fill(0, 0, 255, 255); canvas->push(move(shape5)); diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 7d305be9..c5d39f62 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -19,31 +19,31 @@ void tvgtest() canvas->reserve(5); //reserve 5 shape nodes (optional) //Prepare Shape1 - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(-100, -100, 1000, 1000, 50); shape1->fill(255, 255, 255, 255); canvas->push(move(shape1)); //Prepare Shape2 - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->appendRect(-100, -100, 250, 250, 50); shape2->fill(0, 0, 255, 255); canvas->push(move(shape2)); //Prepare Shape3 - auto shape3 = tvg::ShapeNode::gen(); + auto shape3 = tvg::Shape::gen(); shape3->appendRect(500, 500, 550, 550, 0); shape3->fill(0, 255, 255, 255); canvas->push(move(shape3)); //Prepare Shape4 - auto shape4 = tvg::ShapeNode::gen(); + auto shape4 = tvg::Shape::gen(); shape4->appendCircle(800, 100, 200, 200); shape4->fill(255, 255, 0, 255); canvas->push(move(shape4)); //Prepare Shape5 - auto shape5 = tvg::ShapeNode::gen(); + auto shape5 = tvg::Shape::gen(); shape5->appendCircle(200, 650, 250, 200); shape5->fill(0, 0, 0, 255); canvas->push(move(shape5)); diff --git a/test/testComposition.cpp b/test/testComposition.cpp index cf5ed264..57a8e435 100644 --- a/test/testComposition.cpp +++ b/test/testComposition.cpp @@ -22,7 +22,7 @@ int main(int argc, char **argv) auto canvas2 = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Create a Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); shape->composite(canvas, tvg::CompMaskAdd); //Draw the Scene onto the Canvas diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index ac6bdc37..df5384df 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -8,7 +8,7 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; unique_ptr canvas = nullptr; -tvg::ShapeNode* pShape = nullptr; +tvg::Shape* pShape = nullptr; void tvgtest() { @@ -17,7 +17,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); /* Acquire shape pointer to access it again. instead, you should consider not to interrupt this pointer life-cycle. */ diff --git a/test/testGradient.cpp b/test/testGradient.cpp index a696839b..6a7b6ba7 100644 --- a/test/testGradient.cpp +++ b/test/testGradient.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Prepare a Shape - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius //Linear Gradient Fill @@ -30,7 +30,7 @@ int main(int argc, char **argv) canvas->push(move(shape1)); //Prepare Circle - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->circle(400, 400, 200); //cx, cy, radius //Radial Gradient Fill diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 27ef0c57..8cff17d2 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -18,7 +18,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) - auto shape1 = tvg::ShapeNode::gen(); + 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 diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index d53e9fc4..25393822 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -19,19 +19,19 @@ void tvgtest() canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle - auto shape1 = tvg::ShapeNode::gen(); + 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)); //Prepare Circle - auto shape2 = tvg::ShapeNode::gen(); + 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)); //Prepare Ellipse - auto shape3 = tvg::ShapeNode::gen(); + 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)); diff --git a/test/testPath.cpp b/test/testPath.cpp index 1ae897d6..c2ca8754 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -18,7 +18,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Star - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); //Appends Paths shape1->moveTo(199, 34); @@ -36,7 +36,7 @@ void tvgtest() canvas->push(move(shape1)); //Circle - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); auto cx = 550.0f; auto cy = 550.0f; diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index e555226f..28d19eb9 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -46,7 +46,7 @@ void tvgtest() pts[8] = {26, 161}; //LineTo pts[9] = {146, 143}; //LineTo - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendPath(cmds, 11, pts, 10); //copy path data shape1->fill(0, 255, 0, 255); canvas->push(move(shape1)); @@ -87,7 +87,7 @@ void tvgtest() pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 pts2[12] = {cx, cy - radius}; //To - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->appendPath(cmds2, 6, pts2, 13); //copy path data shape2->fill(255, 255, 0, 255); canvas->push(move(shape2)); diff --git a/test/testScene.cpp b/test/testScene.cpp index f3010dca..3232b659 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -16,25 +16,25 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Create a Scene - auto scene = tvg::SceneNode::gen(); + auto scene = tvg::Scene::gen(); scene->reserve(3); //reserve 3 shape nodes (optional) //Shape1 - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->rect(0, 0, 400, 400, 0.1); shape1->fill(255, 0, 0, 255); shape1->rotate(0, 0, 45); //axis x, y, z scene->push(move(shape1)); //Shape2 - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->rect(0, 0, 400, 400, 0.1); shape2->fill(0, 255, 0, 255); shape2->transform(matrix); //by matrix (var matrix[4 * 4];) scene->push(move(shape2)); //Shape3 - auto shape3 = tvg::ShapeNode::gen(); + auto shape3 = tvg::Shape::gen(); shape3->rect(0, 0, 400, 400, 0.1); shape3->fill(0, 0, 255, 255); shape3->origin(100, 100); //offset diff --git a/test/testShape.cpp b/test/testShape.cpp index 4386637a..8f60263a 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -18,7 +18,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle) - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(100, 100, 400, 400, 0); //x, y, w, h, cornerRadius shape1->fill(255, 0, 0, 255); //r, g, b, a diff --git a/test/testStroke.cpp b/test/testStroke.cpp index de84c32a..e2ae1bc2 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Prepare a Shape - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 97e81ec0..f2256245 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -16,7 +16,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); shape->appendRect(-100, -100, 200, 200, 0); shape->fill(255, 255, 255, 255); canvas->push(move(shape)); @@ -32,7 +32,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres canvas->clear(); //Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); canvas->push(move(shape)); From 30ac2da1a39578401eaf6dac3183f681b5385b1f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 22:30:48 +0900 Subject: [PATCH 044/244] common shape: support scale/rotate transform rotate(), scale() won't be retained. When you call reset() for the shape, these values will be reset as well. These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames. Thus user needs to keep the last values to understand the final accumulated values. Change-Id: I41f260271cdefc977eea01a778d49632440c777f --- inc/tizenvg.h | 16 ++++++++- src/lib/tvgScene.cpp | 20 ++++++++++- src/lib/tvgShape.cpp | 76 +++++++++++++++++++++++++++++---------- src/lib/tvgShapePath.h | 65 +++++++++++++++++++++++++++++++++ test/testDirectUpdate.cpp | 7 ++++ test/testUpdate.cpp | 3 ++ 6 files changed, 167 insertions(+), 20 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index b443d503..83254406 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -72,7 +72,13 @@ class TIZENVG_EXPORT Paint { public: virtual ~Paint() {} + virtual int update(RenderMethod*) = 0; + + virtual int rotate(float degree) = 0; + virtual int scale(float factor) = 0; + + virtual int bounds(float&x, float& y, float& w, float& h) const = 0; }; @@ -130,9 +136,13 @@ public: int fill(size_t r, size_t g, size_t b, size_t a) noexcept; + int rotate(float degree) noexcept override; + int scale(float factor) noexcept override; + int pathCommands(const PathCommand** cmds) const noexcept; int pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + int bounds(float&x, float& y, float& w, float& h) const noexcept override; static std::unique_ptr gen() noexcept; @@ -157,9 +167,13 @@ public: ~Scene(); int update(RenderMethod* engine) noexcept override; - int push(std::unique_ptr shape) noexcept; + int rotate(float degree) noexcept override; + int scale(float factor) noexcept override; + + int bounds(float&x, float& y, float& w, float& h) const noexcept override; + static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(Scene); diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 75725617..bf937a24 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -64,4 +64,22 @@ int Scene::update(RenderMethod* engine) noexcept return 0; } -#endif /* _TVG_SCENE_CPP_ */ + +int Scene::scale(float scaleFacator) noexcept +{ + return 0; +} + + +int Scene::rotate(float degree) noexcept +{ + return 0; +} + + +int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept +{ + return 0; +} + +#endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 5fbfce84..9c41c082 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -35,19 +35,14 @@ struct ShapeStroke }; -struct ShapeTransform -{ - float e[4*4]; -}; - - struct Shape::Impl { - ShapeTransform *transform = nullptr; ShapeFill *fill = nullptr; ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a + float scale = 1; + float rotate = 0; void *edata = nullptr; //engine data Impl() : path(new ShapePath) @@ -59,7 +54,14 @@ struct Shape::Impl if (path) delete(path); if (stroke) delete(stroke); if (fill) delete(fill); - if (transform) delete(transform); + } + + bool update() + { + if (path->scale(scale)) scale = 1; + if (path->rotate(rotate)) rotate = 0; + + return true; } }; @@ -97,6 +99,7 @@ int Shape::update(RenderMethod* engine) noexcept auto impl = pImpl.get(); assert(impl); + if (!impl->update()) return -1; impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All); if (impl->edata) return 0; return - 1; @@ -106,7 +109,7 @@ int Shape::update(RenderMethod* engine) noexcept int Shape::reset() noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->reset(); @@ -117,7 +120,7 @@ int Shape::reset() noexcept int Shape::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); - assert(impl && cmds); + assert(impl && impl->path && cmds); *cmds = impl->path->cmds; @@ -128,7 +131,7 @@ int Shape::pathCommands(const PathCommand** cmds) const noexcept int Shape::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); - assert(impl && pts); + assert(impl && impl->path && pts); *pts = impl->path->pts; @@ -142,7 +145,7 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, assert(cmds && pts); auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); @@ -154,7 +157,7 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, int Shape::moveTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->moveTo(x, y); @@ -165,7 +168,7 @@ int Shape::moveTo(float x, float y) noexcept int Shape::lineTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->lineTo(x, y); @@ -176,7 +179,7 @@ int Shape::lineTo(float x, float y) noexcept int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); @@ -187,7 +190,7 @@ int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) int Shape::close() noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->close(); @@ -198,7 +201,7 @@ int Shape::close() noexcept int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); auto halfKappaW = radiusW * PATH_KAPPA; auto halfKappaH = radiusH * PATH_KAPPA; @@ -218,7 +221,7 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); //clamping cornerRadius by minimum size auto min = (w < h ? w : h) * 0.5f; @@ -281,4 +284,41 @@ int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept return 0; } + +int Shape::scale(float factor) noexcept +{ + if (factor < FLT_EPSILON || fabsf(factor - 1) <= FLT_EPSILON) return -1; + + auto impl = pImpl.get(); + assert(impl); + + impl->scale *= factor; + + return 0; +} + + +int Shape::rotate(float degree) noexcept +{ + if (fabsf(degree) <= FLT_EPSILON) return -1; + + auto impl = pImpl.get(); + assert(impl); + + impl->rotate += degree; + + return 0; +} + + +int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept +{ + auto impl = pImpl.get(); + assert(impl && impl->path); + + if (!impl->path->bounds(x, y, w, h)) return -1; + + return 0; +} + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 6b016f1f..9c42829c 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -112,6 +112,71 @@ struct ShapePath if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); cmds[cmdCnt++] = PathCommand::Close; } + + bool bounds(float& x, float& y, float& w, float& h) + { + if (ptsCnt == 0) return false; + + Point min = { pts[0].x, pts[0].y }; + Point max = { pts[0].x, pts[0].y }; + + for(size_t i = 1; i < ptsCnt; ++i) { + if (pts[i].x < min.x) min.x = pts[i].x; + if (pts[i].y < min.y) min.y = pts[i].y; + if (pts[i].x > max.x) max.x = pts[i].x; + if (pts[i].y > max.y) max.y = pts[i].y; + } + + x = min.x; + y = min.y; + w = max.x - min.x; + h = max.y - min.y; + + return true; + } + + bool rotate(float degree) + { + constexpr auto PI = 3.141592f; + + if (fabsf(degree) <= FLT_EPSILON) return false; + + float x, y, w, h; + if (!bounds(x, y, w, h)) return false; + + auto radian = degree / 180.0f * PI; + auto cx = x + w * 0.5f; + auto cy = y + h * 0.5f; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + for(size_t i = 0; i < ptsCnt; ++i) { + auto dx = pts[i].x - cx; + auto dy = pts[i].y - cy; + pts[i].x = (cosVal * dx - sinVal * dy) + cx; + pts[i].y = (sinVal * dx + cosVal * dy) + cy; + } + + return true; + } + + bool scale(float factor) + { + if (fabsf(factor - 1) <= FLT_EPSILON) return false; + + float x, y, w, h; + if (!bounds(x, y, w, h)) return false; + + auto cx = x + w * 0.5f; + auto cy = y + h * 0.5f; + + for(size_t i = 0; i < ptsCnt; ++i) { + pts[i].x = (pts[i].x - cx) * factor + cx; + pts[i].y = (pts[i].y - cy) * factor + cy; + } + + return true; + } }; #endif //_TVG_SHAPE_PATH_CPP_ diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index df5384df..1888de44 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -25,6 +25,7 @@ void tvgtest() shape->appendRect(-100, -100, 200, 200, 0); shape->fill(127, 255, 255, 255); + shape->rotate(45); canvas->push(move(shape)); //Draw first frame @@ -42,6 +43,12 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + /* rotate, scale won't be retained, when you call reset() for the shape, these values will be reset as well. + These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames. + Thus user needs to keep the last values to understand the final accumulated values. */ + pShape->rotate(45); + pShape->scale(1 - 0.75 * progress); + //Update shape for drawing (this may work asynchronously) pShape->update(canvas->engine()); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index f2256245..d941e26d 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -35,6 +35,9 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres auto shape = tvg::Shape::gen(); shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); + shape->scale(1 - 0.75 * progress); + shape->rotate(360 * progress); + canvas->push(move(shape)); //Draw Next frames From 682bc252987ac42059c089f3a6ec0b3da26f86a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 3 May 2020 02:02:43 +0900 Subject: [PATCH 045/244] common shape: revise scale/rotate approach. Come to think of it, this optimized method is not so useful, it could just bring the user misunderstanding and not to efficient as I expected in the most cases. So, changed policy for transformation behaviors. it keeps the properties as others but leaves it to the backend implementation. Plus, this change contains the correct RenderUpdateFlag. You can refer the flag in the backend to figure out which kinds of properites has been updated Change-Id: Ibe0494712598a8161950b9ae2e22ac45bed1c47b --- inc/tizenvg.h | 10 +++- src/lib/gl_engine/tvgGlRenderer.cpp | 2 +- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 7 +-- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 79 ++++++++++++++++++++++------- src/lib/tvgRenderCommon.h | 5 +- src/lib/tvgScene.cpp | 12 +++++ src/lib/tvgShape.cpp | 68 ++++++++++++++++++------- src/lib/tvgShapePath.h | 43 ---------------- test/testDirectUpdate.cpp | 7 +-- 12 files changed, 143 insertions(+), 96 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 83254406..93e13fc2 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -79,6 +79,8 @@ public: virtual int scale(float factor) = 0; virtual int bounds(float&x, float& y, float& w, float& h) const = 0; + virtual float scale() const = 0; + virtual float rotate() const = 0; }; @@ -139,10 +141,12 @@ public: int rotate(float degree) noexcept override; int scale(float factor) noexcept override; - int pathCommands(const PathCommand** cmds) const noexcept; - int pathCoords(const Point** pts) const noexcept; + size_t pathCommands(const PathCommand** cmds) const noexcept; + size_t pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; int bounds(float&x, float& y, float& w, float& h) const noexcept override; + float scale() const noexcept override; + float rotate() const noexcept override; static std::unique_ptr gen() noexcept; @@ -173,6 +177,8 @@ public: int scale(float factor) noexcept override; int bounds(float&x, float& y, float& w, float& h) const noexcept override; + float scale() const noexcept override; + float rotate() const noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 4e0aa518..0b1a9c73 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index a508eed6..e9e5abe8 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,7 +23,7 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4d654c93..00ff3156 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -94,7 +94,7 @@ struct SwShape void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); -void shapeDelOutline(const Shape& shape, SwShape& sdata); +void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const Shape& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index eda12cc1..c9df96f7 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -90,7 +90,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) assert(sdata); } - if (flags == UpdateFlag::None) return nullptr; + if (flags == RenderUpdateFlag::None) return sdata; //invisible? size_t alpha; @@ -98,13 +98,14 @@ void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) if (alpha == 0) return sdata; //TODO: Threading - if (flags & UpdateFlag::Path) { + if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; + shapeDelOutline(*sdata); } return sdata; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index ce87fa9c..b299d70a 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 5a1c6c3d..03be175d 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -211,26 +211,57 @@ void _deleteRle(SwShape& sdata) } -void _deleteOutline(SwShape& sdata) -{ - if (!sdata.outline) return; - - SwOutline* outline = sdata.outline; - if (outline->cntrs) free(outline->cntrs); - if (outline->pts) free(outline->pts); - if (outline->types) free(outline->types); - free(outline); - - sdata.outline = nullptr; -} - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ bool shapeTransformOutline(const Shape& shape, SwShape& sdata) { - //TODO: + constexpr auto PI = 3.141592f; + + auto degree = shape.rotate(); + auto scale = shape.scale(); + bool rotateOn = false; + bool scaleOn = false; + + if (fabsf(degree) > FLT_EPSILON) rotateOn = true; + if (fabsf(scale - 1) > FLT_EPSILON) scaleOn = true; + + if (!rotateOn && !scaleOn) return true; + + auto outline = sdata.outline; + assert(outline); + + float x, y, w, h; + shape.bounds(x, y, w, h); + + auto cx = x + w * 0.5f; + auto cy = y + h * 0.5f; + + float radian, cosVal, sinVal; + if (rotateOn) { + radian = degree / 180.0f * PI; + cosVal = cosf(radian); + sinVal = sinf(radian); + } + + for(size_t i = 0; i < outline->ptsCnt; ++i) { + auto dx = static_cast(outline->pts[i].x >> 6) - cx; + auto dy = static_cast(outline->pts[i].y >> 6) - cy; + if (rotateOn) { + auto tx = (cosVal * dx - sinVal * dy); + auto ty = (sinVal * dx + cosVal * dy); + dx = tx; + dy = ty; + } + if (scaleOn) { + dx *= scale; + dy *= scale; + } + auto pt = Point{dx + cx, dy + cy}; + outline->pts[i] = TO_SWPOINT(&pt); + } + return true; } @@ -246,7 +277,6 @@ bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end; sdata.rle = rleRender(sdata, clip); - _deleteOutline(sdata); end: if (sdata.rle) return true; @@ -254,9 +284,23 @@ end: } +void shapeDelOutline(SwShape& sdata) +{ + if (!sdata.outline) return; + + SwOutline* outline = sdata.outline; + if (outline->cntrs) free(outline->cntrs); + if (outline->pts) free(outline->pts); + if (outline->types) free(outline->types); + free(outline); + + sdata.outline = nullptr; +} + + void shapeReset(SwShape& sdata) { - _deleteOutline(sdata); + shapeDelOutline(sdata); _deleteRle(sdata); _initBBox(sdata); } @@ -277,7 +321,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) auto outlinePtsCnt = 0; auto outlineCntrsCnt = 0; - for (auto i = 0; i < cmdCnt; ++i) { + for (size_t i = 0; i < cmdCnt; ++i) { switch(*(cmds + i)) { case PathCommand::Close: { ++outlinePtsCnt; @@ -311,7 +355,6 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) cout << "Outline was already allocated? How?" << endl; } - //TODO: Probabry we can copy pts from shape directly. _growOutlinePoint(*outline, outlinePtsCnt); _growOutlineContour(*outline, outlineCntrsCnt); diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 5d619913..9e8662bf 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -28,12 +28,13 @@ struct Surface size_t w, h; }; +enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; + class RenderMethod { public: - enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, UpdateFlag flags) = 0; + virtual void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index bf937a24..0be6f4d7 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -82,4 +82,16 @@ int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept return 0; } + +float Scene::scale() const noexcept +{ + return 0; +} + + +float Scene::rotate() const noexcept +{ + return 0; +} + #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 9c41c082..17e3a274 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -44,6 +44,7 @@ struct Shape::Impl float scale = 1; float rotate = 0; void *edata = nullptr; //engine data + size_t flag = RenderUpdateFlag::None; Impl() : path(new ShapePath) { @@ -55,14 +56,6 @@ struct Shape::Impl if (stroke) delete(stroke); if (fill) delete(fill); } - - bool update() - { - if (path->scale(scale)) scale = 1; - if (path->rotate(rotate)) rotate = 0; - - return true; - } }; @@ -99,10 +92,10 @@ int Shape::update(RenderMethod* engine) noexcept auto impl = pImpl.get(); assert(impl); - if (!impl->update()) return -1; - impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All); + impl->edata = engine->prepare(*this, impl->edata, static_cast(impl->flag)); + impl->flag = RenderUpdateFlag::None; if (impl->edata) return 0; - return - 1; + return -1; } @@ -113,11 +106,13 @@ int Shape::reset() noexcept impl->path->reset(); + impl->flag |= RenderUpdateFlag::Path; + return 0; } -int Shape::pathCommands(const PathCommand** cmds) const noexcept +size_t Shape::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); assert(impl && impl->path && cmds); @@ -128,7 +123,7 @@ int Shape::pathCommands(const PathCommand** cmds) const noexcept } -int Shape::pathCoords(const Point** pts) const noexcept +size_t Shape::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); assert(impl && impl->path && pts); @@ -150,6 +145,8 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -161,6 +158,8 @@ int Shape::moveTo(float x, float y) noexcept impl->path->moveTo(x, y); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -172,6 +171,8 @@ int Shape::lineTo(float x, float y) noexcept impl->path->lineTo(x, y); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -183,6 +184,8 @@ int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -194,6 +197,8 @@ int Shape::close() noexcept impl->path->close(); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -214,6 +219,8 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH); impl->path->close(); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -253,6 +260,8 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no impl->path->close(); } + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -266,6 +275,7 @@ int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept impl->color[1] = g; impl->color[2] = b; impl->color[3] = a; + impl->flag |= RenderUpdateFlag::Fill; return 0; } @@ -287,12 +297,13 @@ int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept int Shape::scale(float factor) noexcept { - if (factor < FLT_EPSILON || fabsf(factor - 1) <= FLT_EPSILON) return -1; - auto impl = pImpl.get(); assert(impl); - impl->scale *= factor; + if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; + + impl->scale = factor; + impl->flag |= RenderUpdateFlag::Transform; return 0; } @@ -300,12 +311,13 @@ int Shape::scale(float factor) noexcept int Shape::rotate(float degree) noexcept { - if (fabsf(degree) <= FLT_EPSILON) return -1; - auto impl = pImpl.get(); assert(impl); - impl->rotate += degree; + if (fabsf(degree - impl->rotate) <= FLT_EPSILON) return -1; + + impl->rotate = degree; + impl->flag |= RenderUpdateFlag::Transform; return 0; } @@ -321,4 +333,22 @@ int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept return 0; } + +float Shape::scale() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->scale; +} + + +float Shape::rotate() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->rotate; +} + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 9c42829c..9dafdf92 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -134,49 +134,6 @@ struct ShapePath return true; } - - bool rotate(float degree) - { - constexpr auto PI = 3.141592f; - - if (fabsf(degree) <= FLT_EPSILON) return false; - - float x, y, w, h; - if (!bounds(x, y, w, h)) return false; - - auto radian = degree / 180.0f * PI; - auto cx = x + w * 0.5f; - auto cy = y + h * 0.5f; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - for(size_t i = 0; i < ptsCnt; ++i) { - auto dx = pts[i].x - cx; - auto dy = pts[i].y - cy; - pts[i].x = (cosVal * dx - sinVal * dy) + cx; - pts[i].y = (sinVal * dx + cosVal * dy) + cy; - } - - return true; - } - - bool scale(float factor) - { - if (fabsf(factor - 1) <= FLT_EPSILON) return false; - - float x, y, w, h; - if (!bounds(x, y, w, h)) return false; - - auto cx = x + w * 0.5f; - auto cy = y + h * 0.5f; - - for(size_t i = 0; i < ptsCnt; ++i) { - pts[i].x = (pts[i].x - cx) * factor + cx; - pts[i].y = (pts[i].y - cy) * factor + cy; - } - - return true; - } }; #endif //_TVG_SHAPE_PATH_CPP_ diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 1888de44..9a6152c6 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -24,6 +24,8 @@ void tvgtest() pShape = shape.get(); shape->appendRect(-100, -100, 200, 200, 0); + + //fill and rotate properties will be retained shape->fill(127, 255, 255, 255); shape->rotate(45); canvas->push(move(shape)); @@ -42,11 +44,6 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->reset(); //reset path pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); - - /* rotate, scale won't be retained, when you call reset() for the shape, these values will be reset as well. - These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames. - Thus user needs to keep the last values to understand the final accumulated values. */ - pShape->rotate(45); pShape->scale(1 - 0.75 * progress); //Update shape for drawing (this may work asynchronously) From f4de03b01a228a293a58a9f3137c64142dc671e0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 3 May 2020 15:14:01 +0900 Subject: [PATCH 046/244] test: updated test samples. 1. added testTransform 2. replaced testShape with testMergeShapes Change-Id: I1f7b25a1d2f62ac682f7a19e75fc3a44db7c52f0 --- .gitignore | 2 +- test/makefile | 2 +- test/testDirectUpdate.cpp | 1 - test/testMergeShapes.cpp | 70 -------------------------- test/testShape.cpp | 10 ++-- test/testTransform.cpp | 101 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 76 deletions(-) delete mode 100644 test/testMergeShapes.cpp create mode 100644 test/testTransform.cpp diff --git a/.gitignore b/.gitignore index a5643f45..e5a2d6eb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,10 @@ build *.swp testShape testMultiShapes -testMergeShapes testBoundary testPath testPathCopy testBlending testUpdate testDirectUpdate +testTransform diff --git a/test/makefile b/test/makefile index 23fd51a0..4c780680 100644 --- a/test/makefile +++ b/test/makefile @@ -1,10 +1,10 @@ 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 testMergeShapes testMergeShapes.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 testTransform testTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 9a6152c6..723222b9 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -44,7 +44,6 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->reset(); //reset path pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); - pShape->scale(1 - 0.75 * progress); //Update shape for drawing (this may work asynchronously) pShape->update(canvas->engine()); diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp deleted file mode 100644 index 8cff17d2..00000000 --- a/test/testMergeShapes.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() -{ - //Initialize TizenVG Engine - tvg::Engine::init(); - - //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 - 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 - - /* 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->draw(); - canvas->sync(); - - //Terminate TizenVG Engine - tvg::Engine::term(); -} - -void -win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - - -int main(int argc, char **argv) -{ - tvgtest(); - - //Show the result using EFL... - elm_init(argc, argv); - - Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); -} diff --git a/test/testShape.cpp b/test/testShape.cpp index 8f60263a..8cff17d2 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -17,10 +17,13 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Prepare a Shape (Rectangle) + //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::Shape::gen(); - shape1->appendRect(100, 100, 400, 400, 0); //x, y, w, h, cornerRadius - shape1->fill(255, 0, 0, 255); //r, g, b, a + 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 /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare @@ -41,6 +44,7 @@ win_del(void *data, Evas_Object *o, void *ev) elm_exit(); } + int main(int argc, char **argv) { tvgtest(); diff --git a/test/testTransform.cpp b/test/testTransform.cpp new file mode 100644 index 00000000..9cf5e37d --- /dev/null +++ b/test/testTransform.cpp @@ -0,0 +1,101 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::Shape* pShape = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape + auto shape = tvg::Shape::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->appendRect(0, 0, 200, 200, 0); + shape->appendRect(100, 100, 300, 300, 100); + shape->appendCircle(400, 400, 100, 100); + shape->appendCircle(400, 500, 170, 100); + 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) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + pShape->scale(1 - 0.75 * progress); + pShape->rotate(360 * progress); + + //Update shape for drawing (this may work asynchronously) + pShape->update(canvas->engine()); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + 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 TizenVG Engine + tvg::Engine::term(); +} From 211dafdaedcd471b459dcdd507f88912f12c4711 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 4 May 2020 21:10:04 +0900 Subject: [PATCH 047/244] common shape: refactored interfaces. hide engine() interface of shape that's not friendly one by users. instead canvas would access shape internal data to update/draw it. Now Paint cannot update itself but has to request to Canvas for it. Change-Id: Ibafd0864a65c3c33238789d1a3e06c49c4378349 --- inc/tizenvg.h | 12 +++--- src/lib/meson.build | 3 +- src/lib/tvgCanvas.cpp | 78 ++++++++++++++++++++++++--------------- src/lib/tvgScene.cpp | 7 ---- src/lib/tvgShape.cpp | 55 +-------------------------- src/lib/tvgShapeImpl.h | 78 +++++++++++++++++++++++++++++++++++++++ test/testDirectUpdate.cpp | 2 +- test/testTransform.cpp | 2 +- 8 files changed, 137 insertions(+), 100 deletions(-) create mode 100644 src/lib/tvgShapeImpl.h diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 93e13fc2..d7ed6efd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -43,6 +43,9 @@ private: \ const A& operator=(const A&) = delete; \ A() +#define _TIZENVG_DECLARE_ACCESSOR(A) \ + friend A + #define _TIZENVG_DISABLE_CTOR(A) \ A() = delete; \ ~A() = delete @@ -73,8 +76,6 @@ class TIZENVG_EXPORT Paint public: virtual ~Paint() {} - virtual int update(RenderMethod*) = 0; - virtual int rotate(float degree) = 0; virtual int scale(float factor) = 0; @@ -102,6 +103,7 @@ public: virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; + virtual int update(Paint* paint) noexcept; virtual int draw(bool async = true) noexcept; virtual int sync() = 0; @@ -124,7 +126,6 @@ class TIZENVG_EXPORT Shape final : public Paint public: ~Shape(); - int update(RenderMethod* engine) noexcept override; int reset() noexcept; int moveTo(float x, float y) noexcept; @@ -150,10 +151,8 @@ public: static std::unique_ptr gen() noexcept; - //FIXME: Ugly... Better design? - void *engine() noexcept; - _TIZENVG_DECLARE_PRIVATE(Shape); + _TIZENVG_DECLARE_ACCESSOR(Canvas); }; @@ -170,7 +169,6 @@ class TIZENVG_EXPORT Scene final : public Paint public: ~Scene(); - int update(RenderMethod* engine) noexcept override; int push(std::unique_ptr shape) noexcept; int rotate(float degree) noexcept override; diff --git a/src/lib/meson.build b/src/lib/meson.build index 5b47bcf9..1087bb8c 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,8 +4,9 @@ subdir('gl_engine') source_file = [ 'tvgCommon.h', 'tvgRenderCommon.h', - 'tvgEngine.cpp', 'tvgShapePath.h', + 'tvgShapeImpl.h', + 'tvgEngine.cpp', 'tvgCanvas.cpp', 'tvgSwCanvas.cpp', 'tvgGlCanvas.cpp', diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 84a13275..49df7e17 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -18,7 +18,7 @@ #define _TVG_CANVAS_CPP_ #include "tvgCommon.h" - +#include "tvgShapeImpl.h" /************************************************************************/ /* Internal Class Implementation */ @@ -26,8 +26,8 @@ struct Canvas::Impl { - vector nodes; - RenderMethod* renderer; + vector paints; + RenderMethod* renderer; Impl(RenderMethod* pRenderer):renderer(pRenderer) { @@ -40,34 +40,30 @@ struct Canvas::Impl renderer->unref(); } - int reserve(size_t n) - { - nodes.reserve(n); - - return 0; - } - int push(unique_ptr paint) { - Paint* node = paint.release(); - assert(node); - nodes.push_back(node); - return node->update(renderer); + Paint* pPaint = paint.release(); + assert(pPaint); + paints.push_back(pPaint); + + return update(pPaint); } int clear() { assert(renderer); - for (auto node : nodes) { - if (Scene* scene = dynamic_cast(node)) { + for (auto paint : paints) { + if (auto scene = dynamic_cast(paint)) { cout << "TODO: " << scene << endl; - } else if (Shape *shape = dynamic_cast(node)) { - if (!renderer->dispose(*shape, shape->engine())) return -1; + } else if (auto shape = dynamic_cast(paint)) { + auto p = shape->pImpl.get(); + assert(p); + if (!p->dispose(*shape, *renderer)) return -1; } - delete(node); + delete(paint); } - nodes.clear(); + paints.clear(); return 0; } @@ -76,8 +72,29 @@ struct Canvas::Impl { assert(renderer); - for(auto node: nodes) { - if (!node->update(renderer)) return -1; + for(auto paint: paints) { + if (auto scene = dynamic_cast(paint)) { + cout << "TODO: " << scene << endl; + } else if (auto shape = dynamic_cast(paint)) { + auto p = shape->pImpl.get(); + assert(p); + if (!p->update(*shape, *renderer)) return -1; + } + } + + return 0; + } + + int update(Paint* paint) + { + assert(renderer); + + if (auto scene = dynamic_cast(paint)) { + cout << "TODO: " << scene << endl; + } else if (auto shape = dynamic_cast(paint)) { + auto p = shape->pImpl.get(); + assert(p); + if (!p->update(*shape, *renderer)) return -1; } return 0; @@ -90,11 +107,13 @@ struct Canvas::Impl //Clear render target before drawing if (!renderer->clear()) return -1; - for(auto node: nodes) { - if (Scene* scene = dynamic_cast(node)) { + for(auto paint: paints) { + if (auto scene = dynamic_cast(paint)) { cout << "TODO: " << scene << endl; - } else if (Shape *shape = dynamic_cast(node)) { - if (!renderer->render(*shape, shape->engine())) return -1; + } else if (auto shape = dynamic_cast(paint)) { + auto p = shape->pImpl.get(); + assert(p); + if(!p->render(*shape, *renderer)) return -1; } } return 0; @@ -121,7 +140,8 @@ int Canvas::reserve(size_t n) noexcept { auto impl = pImpl.get(); assert(impl); - return impl->reserve(n); + impl->paints.reserve(n); + return 0; } @@ -158,11 +178,11 @@ int Canvas::update() noexcept } -RenderMethod* Canvas::engine() noexcept +int Canvas::update(Paint* paint) noexcept { auto impl = pImpl.get(); assert(impl); - return impl->renderer; + return impl->update(paint); } #endif /* _TVG_CANVAS_CPP_ */ diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 0be6f4d7..bc26a99b 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -58,13 +58,6 @@ int Scene::push(unique_ptr shape) noexcept } -int Scene::update(RenderMethod* engine) noexcept -{ - - return 0; -} - - int Scene::scale(float scaleFacator) noexcept { return 0; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 17e3a274..1e5545d2 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -18,46 +18,13 @@ #define _TVG_SHAPE_CPP_ #include "tvgCommon.h" -#include "tvgShapePath.h" +#include "tvgShapeImpl.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ constexpr auto PATH_KAPPA = 0.552284f; -struct ShapeFill -{ -}; - - -struct ShapeStroke -{ -}; - - -struct Shape::Impl -{ - ShapeFill *fill = nullptr; - ShapeStroke *stroke = nullptr; - ShapePath *path = nullptr; - uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a - float scale = 1; - float rotate = 0; - void *edata = nullptr; //engine data - size_t flag = RenderUpdateFlag::None; - - Impl() : path(new ShapePath) - { - } - - ~Impl() - { - if (path) delete(path); - if (stroke) delete(stroke); - if (fill) delete(fill); - } -}; - /************************************************************************/ /* External Class Implementation */ @@ -79,26 +46,6 @@ unique_ptr Shape::gen() noexcept } -void* Shape::engine() noexcept -{ - auto impl = pImpl.get(); - assert(impl); - return impl->edata; -} - - -int Shape::update(RenderMethod* engine) noexcept -{ - auto impl = pImpl.get(); - assert(impl); - - impl->edata = engine->prepare(*this, impl->edata, static_cast(impl->flag)); - impl->flag = RenderUpdateFlag::None; - if (impl->edata) return 0; - return -1; -} - - int Shape::reset() noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h new file mode 100644 index 00000000..f1bb1ebc --- /dev/null +++ b/src/lib/tvgShapeImpl.h @@ -0,0 +1,78 @@ +/* + * 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_SHAPE_IMPL_H_ +#define _TVG_SHAPE_IMPL_H_ + +#include "tvgCommon.h" +#include "tvgShapePath.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct ShapeFill +{ +}; + + +struct ShapeStroke +{ +}; + + +struct Shape::Impl +{ + ShapeFill *fill = nullptr; + ShapeStroke *stroke = nullptr; + ShapePath *path = nullptr; + uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a + float scale = 1; + float rotate = 0; + void *edata = nullptr; //engine data + size_t flag = RenderUpdateFlag::None; + + Impl() : path(new ShapePath) + { + } + + ~Impl() + { + if (path) delete(path); + if (stroke) delete(stroke); + if (fill) delete(fill); + } + + bool dispose(Shape& shape, RenderMethod& renderer) + { + return renderer.dispose(shape, edata); + } + + bool render(Shape& shape, RenderMethod& renderer) + { + return renderer.render(shape, edata); + } + + bool update(Shape& shape, RenderMethod& renderer) + { + edata = renderer.prepare(shape, edata, static_cast(flag)); + flag = RenderUpdateFlag::None; + if (edata) return true; + return false; + } +}; + +#endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 723222b9..735231a6 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -46,7 +46,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); //Update shape for drawing (this may work asynchronously) - pShape->update(canvas->engine()); + canvas->update(pShape); //Draw Next frames canvas->draw(); diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 9cf5e37d..1224299b 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -46,7 +46,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->rotate(360 * progress); //Update shape for drawing (this may work asynchronously) - pShape->update(canvas->engine()); + canvas->update(pShape); //Draw Next frames canvas->draw(); From 4ff97a6a40bab55a34ad8a1fa8797d1722b961dd Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 4 May 2020 21:23:42 +0900 Subject: [PATCH 048/244] common canvas: hide engine() interface this engine() is not necessary by users, we can hide this by moving out CanvasImpl class. Change-Id: Iaf47dbd3c523e96d6af0bd1fd4caa11a7fd3778a --- inc/tizenvg.h | 4 +- src/lib/meson.build | 1 + src/lib/tvgCanvas.cpp | 104 +----------------------------------- src/lib/tvgCanvasImpl.h | 113 ++++++++++++++++++++++++++++++++++++++++ src/lib/tvgGlCanvas.cpp | 1 + src/lib/tvgSwCanvas.cpp | 3 +- 6 files changed, 119 insertions(+), 107 deletions(-) create mode 100644 src/lib/tvgCanvasImpl.h diff --git a/inc/tizenvg.h b/inc/tizenvg.h index d7ed6efd..e9a501ad 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -36,7 +36,7 @@ extern "C" { #endif #define _TIZENVG_DECLARE_PRIVATE(A) \ -private: \ +protected: \ struct Impl; \ std::unique_ptr pImpl; \ A(const A&) = delete; \ @@ -107,8 +107,6 @@ public: virtual int draw(bool async = true) noexcept; virtual int sync() = 0; - RenderMethod* engine() noexcept; - _TIZENVG_DECLARE_PRIVATE(Canvas); }; diff --git a/src/lib/meson.build b/src/lib/meson.build index 1087bb8c..a2ef7433 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -6,6 +6,7 @@ source_file = [ 'tvgRenderCommon.h', 'tvgShapePath.h', 'tvgShapeImpl.h', + 'tvgCanvasImpl.h', 'tvgEngine.cpp', 'tvgCanvas.cpp', 'tvgSwCanvas.cpp', diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 49df7e17..f31373e4 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -18,109 +18,7 @@ #define _TVG_CANVAS_CPP_ #include "tvgCommon.h" -#include "tvgShapeImpl.h" - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -struct Canvas::Impl -{ - vector paints; - RenderMethod* renderer; - - Impl(RenderMethod* pRenderer):renderer(pRenderer) - { - renderer->ref(); - } - - ~Impl() - { - clear(); - renderer->unref(); - } - - int push(unique_ptr paint) - { - Paint* pPaint = paint.release(); - assert(pPaint); - paints.push_back(pPaint); - - return update(pPaint); - } - - int clear() - { - assert(renderer); - - for (auto paint : paints) { - if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; - } else if (auto shape = dynamic_cast(paint)) { - auto p = shape->pImpl.get(); - assert(p); - if (!p->dispose(*shape, *renderer)) return -1; - } - delete(paint); - } - paints.clear(); - - return 0; - } - - int update() - { - assert(renderer); - - for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; - } else if (auto shape = dynamic_cast(paint)) { - auto p = shape->pImpl.get(); - assert(p); - if (!p->update(*shape, *renderer)) return -1; - } - } - - return 0; - } - - int update(Paint* paint) - { - assert(renderer); - - if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; - } else if (auto shape = dynamic_cast(paint)) { - auto p = shape->pImpl.get(); - assert(p); - if (!p->update(*shape, *renderer)) return -1; - } - - return 0; - } - - int draw() - { - assert(renderer); - - //Clear render target before drawing - if (!renderer->clear()) return -1; - - for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; - } else if (auto shape = dynamic_cast(paint)) { - auto p = shape->pImpl.get(); - assert(p); - if(!p->render(*shape, *renderer)) return -1; - } - } - return 0; - } - -}; - +#include "tvgCanvasImpl.h" /************************************************************************/ /* External Class Implementation */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h new file mode 100644 index 00000000..f70753a4 --- /dev/null +++ b/src/lib/tvgCanvasImpl.h @@ -0,0 +1,113 @@ +/* + * 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_CANVAS_IMPL_H_ +#define _TVG_CANVAS_IMPL_H_ + +#include "tvgCommon.h" +#include "tvgShapeImpl.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct Canvas::Impl +{ + vector paints; + RenderMethod* renderer; + + Impl(RenderMethod* pRenderer):renderer(pRenderer) + { + renderer->ref(); + } + + ~Impl() + { + clear(); + renderer->unref(); + } + + int push(unique_ptr paint) + { + auto p = paint.release(); + assert(p); + paints.push_back(p); + + return update(p); + } + + int clear() + { + assert(renderer); + + for (auto paint : paints) { + if (auto scene = dynamic_cast(paint)) { + cout << "TODO: " << scene << endl; + } else if (auto shape = dynamic_cast(paint)) { + if (!shape->pImpl.get()->dispose(*shape, *renderer)) return -1; + } + delete(paint); + } + paints.clear(); + + return 0; + } + + int update() + { + assert(renderer); + + for(auto paint: paints) { + if (auto scene = dynamic_cast(paint)) { + cout << "TODO: " << scene << endl; + } else if (auto shape = dynamic_cast(paint)) { + if (!shape->pImpl.get()->update(*shape, *renderer)) return -1; + } + } + return 0; + } + + int update(Paint* paint) + { + assert(renderer); + + if (auto scene = dynamic_cast(paint)) { + cout << "TODO: " << scene << endl; + } else if (auto shape = dynamic_cast(paint)) { + if (!shape->pImpl.get()->update(*shape, *renderer)) return -1; + } + return 0; + } + + int draw() + { + assert(renderer); + + //Clear render target before drawing + if (!renderer->clear()) return -1; + + for(auto paint: paints) { + if (auto scene = dynamic_cast(paint)) { + cout << "TODO: " << scene << endl; + } else if (auto shape = dynamic_cast(paint)) { + if(!shape->pImpl.get()->render(*shape, *renderer)) return -1; + } + } + return 0; + } +}; + +#endif /* _TVG_CANVAS_IMPL_H_ */ \ No newline at end of file diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index a7719d30..fb769a83 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -19,6 +19,7 @@ #include "tvgCommon.h" #include "tvgGlRenderer.h" +#include "tvgCanvasImpl.h" /************************************************************************/ /* Internal Class Implementation */ diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index a4e49ddb..ea95e987 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -19,6 +19,7 @@ #include "tvgCommon.h" #include "tvgSwRenderer.h" +#include "tvgCanvasImpl.h" /************************************************************************/ @@ -46,7 +47,7 @@ SwCanvas::~SwCanvas() int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { - auto renderer = dynamic_cast(engine()); + auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); assert(renderer); if (!renderer->target(buffer, stride, w, h)) return -1; From 0716d3e774254934f7bf476a7c2d084cc160c173 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 5 May 2020 10:20:50 +0900 Subject: [PATCH 049/244] common scene: implement basic scene behaviors and testScene sample. Scene is a group(list) of paints. This class is designed for vector data set which is prepared before canvas. If a set of vector data is loaded from other resources such as files, they can construct these data set using Scene. This then can be pushed into canvas as one completed image. Scene is supposed to be used in svg loading and storing to tvg specific data format(tvg) Change-Id: Ie2ffebf74e79c59d99a77880630a54b6baad7eec --- .gitignore | 1 + inc/tizenvg.h | 9 +++- src/lib/meson.build | 1 + src/lib/tvgCanvasImpl.h | 17 ++++--- src/lib/tvgCommon.h | 9 +++- src/lib/tvgScene.cpp | 32 +++++++------ src/lib/tvgSceneImpl.h | 76 ++++++++++++++++++++++++++++++ src/lib/tvgShapeImpl.h | 1 - test/makefile | 1 + test/testScene.cpp | 100 ++++++++++++++++++++++++++++++++++------ 10 files changed, 207 insertions(+), 40 deletions(-) create mode 100644 src/lib/tvgSceneImpl.h diff --git a/.gitignore b/.gitignore index e5a2d6eb..29175734 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ testPathCopy testBlending testUpdate testDirectUpdate +testScene testTransform diff --git a/inc/tizenvg.h b/inc/tizenvg.h index e9a501ad..63da89fc 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -56,6 +56,7 @@ namespace tvg enum class TIZENVG_EXPORT PathCommand { Close, MoveTo, LineTo, CubicTo }; class RenderMethod; +class Scene; struct Point { @@ -107,6 +108,7 @@ public: virtual int draw(bool async = true) noexcept; virtual int sync() = 0; + _TIZENVG_DECLARE_ACCESSOR(Scene); _TIZENVG_DECLARE_PRIVATE(Canvas); }; @@ -149,8 +151,9 @@ public: static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(Shape); + _TIZENVG_DECLARE_ACCESSOR(Scene); _TIZENVG_DECLARE_ACCESSOR(Canvas); + _TIZENVG_DECLARE_PRIVATE(Shape); }; @@ -167,7 +170,8 @@ class TIZENVG_EXPORT Scene final : public Paint public: ~Scene(); - int push(std::unique_ptr shape) noexcept; + int push(std::unique_ptr shape) noexcept; + int reserve(size_t size) noexcept; int rotate(float degree) noexcept override; int scale(float factor) noexcept override; @@ -179,6 +183,7 @@ public: static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(Scene); + _TIZENVG_DECLARE_ACCESSOR(Canvas); }; diff --git a/src/lib/meson.build b/src/lib/meson.build index a2ef7433..0a56f0dd 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -7,6 +7,7 @@ source_file = [ 'tvgShapePath.h', 'tvgShapeImpl.h', 'tvgCanvasImpl.h', + 'tvgSceneImpl.h', 'tvgEngine.cpp', 'tvgCanvas.cpp', 'tvgSwCanvas.cpp', diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index f70753a4..20a5efd0 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -18,7 +18,6 @@ #define _TVG_CANVAS_IMPL_H_ #include "tvgCommon.h" -#include "tvgShapeImpl.h" /************************************************************************/ /* Internal Class Implementation */ @@ -55,9 +54,9 @@ struct Canvas::Impl for (auto paint : paints) { if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; + if (!SCENE_IMPL->clear(*renderer)) return -1; } else if (auto shape = dynamic_cast(paint)) { - if (!shape->pImpl.get()->dispose(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->dispose(*shape, *renderer)) return -1; } delete(paint); } @@ -72,9 +71,9 @@ struct Canvas::Impl for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; + if (!SCENE_IMPL->update(*renderer)) return -1; } else if (auto shape = dynamic_cast(paint)) { - if (!shape->pImpl.get()->update(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer)) return -1; } } return 0; @@ -85,9 +84,9 @@ struct Canvas::Impl assert(renderer); if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; + if (!SCENE_IMPL->update(*renderer)) return -1; } else if (auto shape = dynamic_cast(paint)) { - if (!shape->pImpl.get()->update(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer)) return -1; } return 0; } @@ -101,9 +100,9 @@ struct Canvas::Impl for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - cout << "TODO: " << scene << endl; + if(!SCENE_IMPL->render(*renderer)) return -1; } else if (auto shape = dynamic_cast(paint)) { - if(!shape->pImpl.get()->render(*shape, *renderer)) return -1; + if(!SHAPE_IMPL->render(*shape, *renderer)) return -1; } } return 0; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index c3f0c568..c404f1fa 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -24,9 +24,16 @@ #include #include #include "tizenvg.h" -#include "tvgRenderCommon.h" using namespace std; using namespace tvg; +#define SCENE_IMPL scene->pImpl.get() +#define SHAPE_IMPL shape->pImpl.get() + +#include "tvgRenderCommon.h" +#include "tvgShapePath.h" +#include "tvgShapeImpl.h" +#include "tvgSceneImpl.h" + #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index bc26a99b..9b9844bd 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -19,17 +19,6 @@ #include "tvgCommon.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -struct Scene::Impl -{ - -}; - - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -42,7 +31,6 @@ Scene::Scene() : pImpl(make_unique()) Scene::~Scene() { - cout << "Scene(" << this << ") destroyed!" << endl; } @@ -52,8 +40,26 @@ unique_ptr Scene::gen() noexcept } -int Scene::push(unique_ptr shape) noexcept +int Scene::push(unique_ptr paint) noexcept { + auto impl = pImpl.get(); + assert(impl); + + auto p = paint.release(); + assert(p); + impl->paints.push_back(p); + + return 0; +} + + +int Scene::reserve(size_t size) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->paints.reserve(size); + return 0; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h new file mode 100644 index 00000000..31a36147 --- /dev/null +++ b/src/lib/tvgSceneImpl.h @@ -0,0 +1,76 @@ +/* + * 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_SCENE_IMPL_H_ +#define _TVG_SCENE_IMPL_H_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct Scene::Impl +{ + vector paints; + + ~Impl() + { + //Are you sure clear() prior to this? + assert(paints.empty()); + } + + bool clear(RenderMethod& renderer) + { + for (auto paint : paints) { + if (auto scene = dynamic_cast(paint)) { + if (!SCENE_IMPL->clear(renderer)) return false; + } else if (auto shape = dynamic_cast(paint)) { + if (!SHAPE_IMPL->dispose(*shape, renderer)) return false; + } + delete(paint); + } + paints.clear(); + + return true; + } + + bool update(RenderMethod &renderer) + { + for(auto paint: paints) { + if (auto scene = dynamic_cast(paint)) { + if (!SCENE_IMPL->update(renderer)) return false; + } else if (auto shape = dynamic_cast(paint)) { + if (!SHAPE_IMPL->update(*shape, renderer)) return false; + } + } + return true; + } + + bool render(RenderMethod &renderer) + { + for(auto paint: paints) { + if (auto scene = dynamic_cast(paint)) { + if(!SCENE_IMPL->render(renderer)) return false; + } else if (auto shape = dynamic_cast(paint)) { + if(!SHAPE_IMPL->render(*shape, renderer)) return false; + } + } + return true; + } +}; + +#endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index f1bb1ebc..63b74773 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -18,7 +18,6 @@ #define _TVG_SHAPE_IMPL_H_ #include "tvgCommon.h" -#include "tvgShapePath.h" /************************************************************************/ /* Internal Class Implementation */ diff --git a/test/makefile b/test/makefile index 4c780680..e437084c 100644 --- a/test/makefile +++ b/test/makefile @@ -7,4 +7,5 @@ all: 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` diff --git a/test/testScene.cpp b/test/testScene.cpp index 3232b659..f7c9ea5b 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -7,39 +8,79 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -int main(int argc, char **argv) +void tvgtest() { //Initialize TizenVG Engine tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + 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) - //Shape1 + //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->rect(0, 0, 400, 400, 0.1); - shape1->fill(255, 0, 0, 255); - shape1->rotate(0, 0, 45); //axis x, y, z + shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->fill(0, 255, 0, 255); //r, g, b, a scene->push(move(shape1)); - //Shape2 + //Prepare Circle auto shape2 = tvg::Shape::gen(); - shape2->rect(0, 0, 400, 400, 0.1); - shape2->fill(0, 255, 0, 255); - shape2->transform(matrix); //by matrix (var matrix[4 * 4];) + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH + shape2->fill(255, 255, 0, 255); //r, g, b, a scene->push(move(shape2)); - //Shape3 + //Prepare Ellipse auto shape3 = tvg::Shape::gen(); - shape3->rect(0, 0, 400, 400, 0.1); - shape3->fill(0, 0, 255, 255); - shape3->origin(100, 100); //offset + shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH + shape3->fill(0, 255, 255, 255); //r, g, b, a scene->push(move(shape3)); + //Create another Scene + auto scene2 = tvg::Scene::gen(); + scene2->reserve(2); //reserve 2 shape nodes (optional) + + //Star + auto shape4 = tvg::Shape::gen(); + + //Appends Paths + shape4->moveTo(199, 34); + shape4->lineTo(253, 143); + shape4->lineTo(374, 160); + shape4->lineTo(287, 244); + shape4->lineTo(307, 365); + shape4->lineTo(199, 309); + shape4->lineTo(97, 365); + shape4->lineTo(112, 245); + shape4->lineTo(26, 161); + shape4->lineTo(146, 143); + shape4->close(); + shape4->fill(0, 0, 255, 255); + scene2->push(move(shape4)); + + //Circle + auto shape5 = tvg::Shape::gen(); + + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Append Paths + shape5->moveTo(cx, cy - radius); + shape5->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy); + shape5->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); + shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); + shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); + shape5->fill(255, 0, 0, 255); + scene2->push(move(shape5)); + + //Push scene2 onto the scene + scene->push(move(scene2)); + //Draw the Scene onto the Canvas canvas->push(move(scene)); canvas->draw(); @@ -48,3 +89,34 @@ int main(int argc, char **argv) //Terminate TizenVG Engine tvg::Engine::term(); } + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 17af011eae83e7e49142303968a184961147d591 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 5 May 2020 20:38:26 +0900 Subject: [PATCH 050/244] common scene: support bounds() method this method returns boundary of a scene. Change-Id: I1a32c8e034f53822008048f1d8ae7062fb72cca3 --- src/lib/tvgScene.cpp | 10 ++++++++++ src/lib/tvgSceneImpl.h | 23 +++++++++++++++++++++++ src/lib/tvgShape.cpp | 4 ++-- src/lib/tvgShapeImpl.h | 6 ++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 9b9844bd..471d2ab1 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -78,6 +78,16 @@ int Scene::rotate(float degree) noexcept int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept { + auto impl = pImpl.get(); + assert(impl); + + x = FLT_MAX; + y = FLT_MAX; + w = 0; + h = 0; + + if (!impl->bounds(x, y, w, h)) return -1; + return 0; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 31a36147..a2ce90d4 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -71,6 +71,29 @@ struct Scene::Impl } return true; } + + bool bounds(float& x, float& y, float& w, float& h) + { + for(auto paint: paints) { + auto x2 = FLT_MAX; + auto y2 = FLT_MAX; + auto w2 = 0.0f; + auto h2 = 0.0f; + + if (auto scene = dynamic_cast(paint)) { + if (!SCENE_IMPL->bounds(x2, y2, w2, h2)) return false; + } else if (auto shape = dynamic_cast(paint)) { + if (!SHAPE_IMPL->bounds(x2, y2, w2, h2)) return false; + } + + //Merge regions + if (x2 < x) x = x2; + if (x + w < x2 + w2) w = (x2 + w2) - x; + if (y2 < y) y = x2; + if (y + h < y2 + h2) h = (y2 + h2) - y; + } + return true; + } }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 1e5545d2..272b194d 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -273,9 +273,9 @@ int Shape::rotate(float degree) noexcept int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + assert(impl); - if (!impl->path->bounds(x, y, w, h)) return -1; + if (!impl->bounds(x, y, w, h)) return -1; return 0; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 63b74773..5894b1e8 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -72,6 +72,12 @@ struct Shape::Impl if (edata) return true; return false; } + + bool bounds(float& x, float& y, float& w, float& h) + { + assert(path); + return path->bounds(x, y, w, h); + } }; #endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file From b08d144dc98a1cf0b528351feb4586d1a5bf081c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 6 May 2020 01:37:50 +0900 Subject: [PATCH 051/244] common shape: introduce transformation matrix Paint supports translate, rotate, scale functions for transformation The origin of these transformation is center of the paint, thus you have to consider the center-aligned vertices if you'd like to use these transformation functions. This policy has been considered for scene transformation. Change-Id: I78b63d7965faec0ec5b9a98a7776993744534b54 --- inc/tizenvg.h | 9 ++-- src/lib/gl_engine/tvgGlRenderer.cpp | 10 +++- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +-- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 47 +++-------------- src/lib/tvgRenderCommon.h | 78 ++++++++++++++++++++++++++++- src/lib/tvgScene.cpp | 18 +++---- src/lib/tvgShape.cpp | 34 ++++++------- src/lib/tvgShapeImpl.h | 15 +++++- test/testTransform.cpp | 9 ++-- test/testUpdate.cpp | 3 +- 13 files changed, 144 insertions(+), 91 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 63da89fc..98b6fafd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -79,10 +79,9 @@ public: virtual int rotate(float degree) = 0; virtual int scale(float factor) = 0; + virtual int translate(float x, float y) = 0; virtual int bounds(float&x, float& y, float& w, float& h) const = 0; - virtual float scale() const = 0; - virtual float rotate() const = 0; }; @@ -141,13 +140,12 @@ public: int rotate(float degree) noexcept override; int scale(float factor) noexcept override; + int translate(float x, float y) noexcept override; size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; int bounds(float&x, float& y, float& w, float& h) const noexcept override; - float scale() const noexcept override; - float rotate() const noexcept override; static std::unique_ptr gen() noexcept; @@ -175,10 +173,9 @@ public: int rotate(float degree) noexcept override; int scale(float factor) noexcept override; + int translate(float x, float y) noexcept override; int bounds(float&x, float& y, float& w, float& h) const noexcept override; - float scale() const noexcept override; - float rotate() const noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 0b1a9c73..08a9c30e 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); @@ -74,6 +74,14 @@ void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags assert(sdata); } + if (RenderUpdateFlag::Path) { + //TODO: Updated Vertices + } + + if (RenderUpdateFlag::Transform) { + //TODO: Updated Transform + } + //TODO: return sdata; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index e9e5abe8..4d6ba793 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,7 +23,7 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 00ff3156..62a6b297 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -96,7 +96,7 @@ void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -bool shapeTransformOutline(const Shape& shape, SwShape& sdata); +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index c9df96f7..ce741ffb 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -98,10 +98,10 @@ void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags if (alpha == 0) return sdata; //TODO: Threading - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { + if (flags & RenderUpdateFlag::Path || RenderUpdateFlag::Transform) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; - if (!shapeTransformOutline(shape, *sdata)) return sdata; + if (transform) shapeTransformOutline(shape, *sdata, *transform); SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index b299d70a..3dfb076c 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 03be175d..d7229dce 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -215,54 +215,19 @@ void _deleteRle(SwShape& sdata) /* External Class Implementation */ /************************************************************************/ -bool shapeTransformOutline(const Shape& shape, SwShape& sdata) +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform) { - constexpr auto PI = 3.141592f; - - auto degree = shape.rotate(); - auto scale = shape.scale(); - bool rotateOn = false; - bool scaleOn = false; - - if (fabsf(degree) > FLT_EPSILON) rotateOn = true; - if (fabsf(scale - 1) > FLT_EPSILON) scaleOn = true; - - if (!rotateOn && !scaleOn) return true; - auto outline = sdata.outline; assert(outline); - float x, y, w, h; - shape.bounds(x, y, w, h); - - auto cx = x + w * 0.5f; - auto cy = y + h * 0.5f; - - float radian, cosVal, sinVal; - if (rotateOn) { - radian = degree / 180.0f * PI; - cosVal = cosf(radian); - sinVal = sinf(radian); - } - for(size_t i = 0; i < outline->ptsCnt; ++i) { - auto dx = static_cast(outline->pts[i].x >> 6) - cx; - auto dy = static_cast(outline->pts[i].y >> 6) - cy; - if (rotateOn) { - auto tx = (cosVal * dx - sinVal * dy); - auto ty = (sinVal * dx + cosVal * dy); - dx = tx; - dy = ty; - } - if (scaleOn) { - dx *= scale; - dy *= scale; - } - auto pt = Point{dx + cx, dy + cy}; + auto dx = static_cast(outline->pts[i].x >> 6); + auto dy = static_cast(outline->pts[i].y >> 6); + auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13; + auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23; + auto pt = Point{tx + transform.e31, ty + transform.e32}; outline->pts[i] = TO_SWPOINT(&pt); } - - return true; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 9e8662bf..b21c2440 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -30,11 +30,87 @@ struct Surface enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; +struct RenderTransform +{ + float e11, e12, e13; + float e21, e22, e23; + float e31, e32, e33; + + void identity() + { + e11 = 1.0f; + e12 = 0.0f; + e13 = 0.0f; + e21 = 0.0f; + e22 = 1.0f; + e23 = 0.0f; + e31 = 0.0f; + e32 = 0.0f; + e33 = 1.0f; + } + + void rotate(float degree) + { + constexpr auto PI = 3.141592f; + + if (fabsf(degree) <= FLT_EPSILON) return; + + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; + + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } + + void translate(float x, float y) + { + e31 += x; + e32 += y; + } + + void scale(float factor) + { + e11 *= factor; + e22 *= factor; + e33 *= factor; + } + + RenderTransform& operator*=(const RenderTransform rhs) + { + e11 = e11 * rhs.e11 + e12 * rhs.e21 + e13 * rhs.e31; + e12 = e11 * rhs.e12 + e12 * rhs.e22 + e13 * rhs.e32; + e13 = e11 * rhs.e13 + e12 * rhs.e23 + e13 * rhs.e33; + + e21 = e21 * rhs.e11 + e22 * rhs.e21 + e23 * rhs.e31; + e22 = e21 * rhs.e12 + e22 * rhs.e22 + e23 * rhs.e32; + e23 = e21 * rhs.e13 + e22 * rhs.e23 + e23 * rhs.e33; + + e31 = e31 * rhs.e11 + e32 * rhs.e21 + e33 * rhs.e31; + e32 = e31 * rhs.e12 + e32 * rhs.e22 + e33 * rhs.e32; + e33 = e31 * rhs.e13 + e32 * rhs.e23 + e33 * rhs.e33; + + return *this; + } +}; + + class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) = 0; + virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 471d2ab1..4b2a6131 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -76,6 +76,12 @@ int Scene::rotate(float degree) noexcept } +int Scene::translate(float x, float y) noexcept +{ + return 0; +} + + int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept { auto impl = pImpl.get(); @@ -91,16 +97,4 @@ int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept return 0; } - -float Scene::scale() const noexcept -{ - return 0; -} - - -float Scene::rotate() const noexcept -{ - return 0; -} - #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 272b194d..6665a558 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -247,7 +247,7 @@ int Shape::scale(float factor) noexcept auto impl = pImpl.get(); assert(impl); - if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; + if (fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; impl->scale = factor; impl->flag |= RenderUpdateFlag::Transform; @@ -270,6 +270,21 @@ int Shape::rotate(float degree) noexcept } +int Shape::translate(float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (fabsf(x - impl->x) <= FLT_EPSILON && fabsf(y - impl->y) <= FLT_EPSILON) return -1; + + impl->x = x; + impl->y = y; + impl->flag |= RenderUpdateFlag::Transform; + + return 0; +} + + int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept { auto impl = pImpl.get(); @@ -281,21 +296,4 @@ int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept } -float Shape::scale() const noexcept -{ - auto impl = pImpl.get(); - assert(impl); - - return impl->scale; -} - - -float Shape::rotate() const noexcept -{ - auto impl = pImpl.get(); - assert(impl); - - return impl->rotate; -} - #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 5894b1e8..6b81dc03 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -41,6 +41,8 @@ struct Shape::Impl uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a float scale = 1; float rotate = 0; + float x = 0; + float y = 0; void *edata = nullptr; //engine data size_t flag = RenderUpdateFlag::None; @@ -67,8 +69,19 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer) { - edata = renderer.prepare(shape, edata, static_cast(flag)); + if (flag & RenderUpdateFlag::Transform) { + RenderTransform transform; + transform.identity(); + transform.rotate(rotate); + transform.scale(scale); + transform.translate(x, y); + edata = renderer.prepare(shape, edata, &transform, static_cast(flag)); + } else { + edata = renderer.prepare(shape, edata, nullptr, static_cast(flag)); + } + flag = RenderUpdateFlag::None; + if (edata) return true; return false; } diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 1224299b..faab048f 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -23,11 +23,12 @@ void tvgtest() instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(0, 0, 200, 200, 0); - shape->appendRect(100, 100, 300, 300, 100); - shape->appendCircle(400, 400, 100, 100); - shape->appendCircle(400, 500, 170, 100); + shape->appendRect(-285, -300, 200, 200, 0); + shape->appendRect(-185, -200, 300, 300, 100); + shape->appendCircle(115, 100, 100, 100); + shape->appendCircle(115, 200, 170, 100); shape->fill(255, 255, 255, 255); + shape->translate(285, 300); canvas->push(move(shape)); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index d941e26d..453b47c0 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -33,8 +33,9 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres //Shape auto shape = tvg::Shape::gen(); - shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + shape->appendRect(-100, -100, 200, 200, (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); + shape->translate(800 * progress, 800 * progress); shape->scale(1 - 0.75 * progress); shape->rotate(360 * progress); From 40ef2f1575053bbb2fe4803e55926ac618d52864 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 6 May 2020 11:56:17 +0900 Subject: [PATCH 052/244] fix wrong flag operation. just correct mistakes. Change-Id: I8de0fe68cd298cacf3bdc951f67657095c5fa5fe --- src/lib/gl_engine/tvgGlRenderer.cpp | 4 ++-- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 08a9c30e..792e5241 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -74,11 +74,11 @@ void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* assert(sdata); } - if (RenderUpdateFlag::Path) { + if (flags & RenderUpdateFlag::Path) { //TODO: Updated Vertices } - if (RenderUpdateFlag::Transform) { + if (flags & RenderUpdateFlag::Transform) { //TODO: Updated Transform } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index ce741ffb..36e367b2 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -98,7 +98,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* if (alpha == 0) return sdata; //TODO: Threading - if (flags & RenderUpdateFlag::Path || RenderUpdateFlag::Transform) { + if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (transform) shapeTransformOutline(shape, *sdata, *transform); From 2f2efb73dd2ffc07c4e7d11d02f86671658bda8d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 17 May 2020 14:54:55 +0900 Subject: [PATCH 053/244] common shape: revise RenderTransform for Scene Transformation This RenderTransform takes over all transform information. Change-Id: I21b6a55de05feca56c40f3ff402d18445417463c --- src/lib/tvgRenderCommon.h | 73 ++++++++++++++++++++++----------------- src/lib/tvgShape.cpp | 22 ++---------- src/lib/tvgShapeImpl.h | 70 +++++++++++++++++++++++++++++-------- 3 files changed, 100 insertions(+), 65 deletions(-) diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index b21c2440..a3bfcb6d 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -32,12 +32,27 @@ enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; struct RenderTransform { + //3x3 Matrix Elements float e11, e12, e13; float e21, e22, e23; float e31, e32, e33; - void identity() + float x = 0.0f; + float y = 0.0f; + float degree = 0.0f; //rotation degree + float factor = 1.0f; //scale factor + + bool update() { + constexpr auto PI = 3.141592f; + + //Init Status + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && + fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { + return false; + } + + //identity e11 = 1.0f; e12 = 0.0f; e13 = 0.0f; @@ -47,44 +62,38 @@ struct RenderTransform e31 = 0.0f; e32 = 0.0f; e33 = 1.0f; - } - void rotate(float degree) - { - constexpr auto PI = 3.141592f; + //rotation + if (fabsf(degree) > FLT_EPSILON) { + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); - if (fabsf(degree) <= FLT_EPSILON) return; + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; - auto radian = degree / 180.0f * PI; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; - - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; - } - - void translate(float x, float y) - { - e31 += x; - e32 += y; - } - - void scale(float factor) - { + //scale e11 *= factor; e22 *= factor; e33 *= factor; + + //translate + e31 += x; + e32 += y; + + return true; } RenderTransform& operator*=(const RenderTransform rhs) diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 6665a558..432a8a66 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -247,12 +247,7 @@ int Shape::scale(float factor) noexcept auto impl = pImpl.get(); assert(impl); - if (fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; - - impl->scale = factor; - impl->flag |= RenderUpdateFlag::Transform; - - return 0; + return impl->scale(factor); } @@ -261,12 +256,7 @@ int Shape::rotate(float degree) noexcept auto impl = pImpl.get(); assert(impl); - if (fabsf(degree - impl->rotate) <= FLT_EPSILON) return -1; - - impl->rotate = degree; - impl->flag |= RenderUpdateFlag::Transform; - - return 0; + return impl->rotate(degree); } @@ -275,13 +265,7 @@ int Shape::translate(float x, float y) noexcept auto impl = pImpl.get(); assert(impl); - if (fabsf(x - impl->x) <= FLT_EPSILON && fabsf(y - impl->y) <= FLT_EPSILON) return -1; - - impl->x = x; - impl->y = y; - impl->flag |= RenderUpdateFlag::Transform; - - return 0; + return impl->translate(x, y); } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 6b81dc03..e552a3ba 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -38,13 +38,11 @@ struct Shape::Impl ShapeFill *fill = nullptr; ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; + RenderTransform *transform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a - float scale = 1; - float rotate = 0; - float x = 0; - float y = 0; - void *edata = nullptr; //engine data size_t flag = RenderUpdateFlag::None; + void *edata = nullptr; //engine data + Impl() : path(new ShapePath) { @@ -55,6 +53,7 @@ struct Shape::Impl if (path) delete(path); if (stroke) delete(stroke); if (fill) delete(fill); + if (transform) delete(transform); } bool dispose(Shape& shape, RenderMethod& renderer) @@ -70,16 +69,13 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer) { if (flag & RenderUpdateFlag::Transform) { - RenderTransform transform; - transform.identity(); - transform.rotate(rotate); - transform.scale(scale); - transform.translate(x, y); - edata = renderer.prepare(shape, edata, &transform, static_cast(flag)); - } else { - edata = renderer.prepare(shape, edata, nullptr, static_cast(flag)); + assert(transform); + if (!transform->update()) { + delete(transform); + transform = nullptr; + } } - + edata = renderer.prepare(shape, edata, transform, static_cast(flag)); flag = RenderUpdateFlag::None; if (edata) return true; @@ -91,6 +87,52 @@ struct Shape::Impl assert(path); return path->bounds(x, y, w, h); } + + bool scale(float factor) + { + if (transform) { + if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1; + } else { + if (fabsf(factor) <= FLT_EPSILON) return -1; + transform = new RenderTransform(); + assert(transform); + } + transform->factor = factor; + flag |= RenderUpdateFlag::Transform; + + return 0; + } + + bool rotate(float degree) + { + if (transform) { + if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1; + } else { + if (fabsf(degree) <= FLT_EPSILON) return -1; + transform = new RenderTransform(); + assert(transform); + } + transform->degree = degree; + flag |= RenderUpdateFlag::Transform; + + return 0; + } + + bool translate(float x, float y) + { + if (transform) { + if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1; + } else { + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1; + transform = new RenderTransform(); + assert(transform); + } + transform->x = x; + transform->y = y; + flag |= RenderUpdateFlag::Transform; + + return 0; + } }; #endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file From fdbf42f478137cf4c4caf4b4345cc7b2592d525c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 17 May 2020 16:50:19 +0900 Subject: [PATCH 054/244] common: support Scene Transform this contains testSceneTransform example Change-Id: I460b05dc8bc4a842e26e950c800c5c35f8d3da7f --- .gitignore | 1 + src/lib/gl_engine/tvgGlRenderer.cpp | 2 +- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 2 +- src/lib/tvgCanvasImpl.h | 4 +- src/lib/tvgRenderCommon.h | 139 +++++++++++++---------- src/lib/tvgScene.cpp | 17 ++- src/lib/tvgSceneImpl.h | 81 +++++++++++++- src/lib/tvgShapeImpl.h | 13 ++- test/makefile | 1 + test/testSceneTransform.cpp | 168 ++++++++++++++++++++++++++++ 14 files changed, 358 insertions(+), 78 deletions(-) create mode 100644 test/testSceneTransform.cpp diff --git a/.gitignore b/.gitignore index 29175734..6210eb83 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ testUpdate testDirectUpdate testScene testTransform +testSceneTransform diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 792e5241..48a0ee56 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 4d6ba793..557f9e70 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,7 +23,7 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 62a6b297..3068b9bb 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -96,7 +96,7 @@ void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderMatrix& transform); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 36e367b2..2d974450 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 3dfb076c..4c0a7baa 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d7229dce..efad9328 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -215,7 +215,7 @@ void _deleteRle(SwShape& sdata) /* External Class Implementation */ /************************************************************************/ -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform) +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderMatrix& transform) { auto outline = sdata.outline; assert(outline); diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 20a5efd0..afa2a0b1 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -71,9 +71,9 @@ struct Canvas::Impl for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->update(*renderer)) return -1; + if (!SCENE_IMPL->update(*renderer, nullptr)) return -1; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->update(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return -1; } } return 0; diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index a3bfcb6d..0ad1d558 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -30,13 +30,85 @@ struct Surface enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; -struct RenderTransform +struct RenderMatrix { //3x3 Matrix Elements float e11, e12, e13; float e21, e22, e23; float e31, e32, e33; + static void rotate(RenderMatrix* out, float degree) + { + constexpr auto PI = 3.141592f; + + if (fabsf(degree) < FLT_EPSILON) return; + + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = out->e11 * cosVal + out->e12 * sinVal; + auto t12 = out->e11 * -sinVal + out->e12 * cosVal; + auto t21 = out->e21 * cosVal + out->e22 * sinVal; + auto t22 = out->e21 * -sinVal + out->e22 * cosVal; + auto t31 = out->e31 * cosVal + out->e32 * sinVal; + auto t32 = out->e31 * -sinVal + out->e32 * cosVal; + + out->e11 = t11; + out->e12 = t12; + out->e21 = t21; + out->e22 = t22; + out->e31 = t31; + out->e32 = t32; + } + + static void scale(RenderMatrix* out, float factor) + { + out->e11 *= factor; + out->e22 *= factor; + out->e33 *= factor; + } + + static void identity(RenderMatrix* out) + { + out->e11 = 1.0f; + out->e12 = 0.0f; + out->e13 = 0.0f; + out->e21 = 0.0f; + out->e22 = 1.0f; + out->e23 = 0.0f; + out->e31 = 0.0f; + out->e32 = 0.0f; + out->e33 = 1.0f; + } + + static void translate(RenderMatrix* out, float x, float y) + { + out->e31 += x; + out->e32 += y; + } + + static void multiply(const RenderMatrix* lhs, const RenderMatrix* rhs, RenderMatrix* out) + { + assert(lhs && rhs && out); + + out->e11 = lhs->e11 * rhs->e11 + lhs->e12 * rhs->e21 + lhs->e13 * rhs->e31; + out->e12 = lhs->e11 * rhs->e12 + lhs->e12 * rhs->e22 + lhs->e13 * rhs->e32; + out->e13 = lhs->e11 * rhs->e13 + lhs->e12 * rhs->e23 + lhs->e13 * rhs->e33; + + out->e21 = lhs->e21 * rhs->e11 + lhs->e22 * rhs->e21 + lhs->e23 * rhs->e31; + out->e22 = lhs->e21 * rhs->e12 + lhs->e22 * rhs->e22 + lhs->e23 * rhs->e32; + out->e23 = lhs->e21 * rhs->e13 + lhs->e22 * rhs->e23 + lhs->e23 * rhs->e33; + + out->e31 = lhs->e31 * rhs->e11 + lhs->e32 * rhs->e21 + lhs->e33 * rhs->e31; + out->e32 = lhs->e31 * rhs->e12 + lhs->e32 * rhs->e22 + lhs->e33 * rhs->e32; + out->e33 = lhs->e31 * rhs->e13 + lhs->e32 * rhs->e23 + lhs->e33 * rhs->e33; + } +}; + +struct RenderTransform +{ + RenderMatrix m; float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree @@ -44,74 +116,19 @@ struct RenderTransform bool update() { - constexpr auto PI = 3.141592f; - //Init Status if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { return false; } - //identity - e11 = 1.0f; - e12 = 0.0f; - e13 = 0.0f; - e21 = 0.0f; - e22 = 1.0f; - e23 = 0.0f; - e31 = 0.0f; - e32 = 0.0f; - e33 = 1.0f; - - //rotation - if (fabsf(degree) > FLT_EPSILON) { - auto radian = degree / 180.0f * PI; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; - - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; - } - - //scale - e11 *= factor; - e22 *= factor; - e33 *= factor; - - //translate - e31 += x; - e32 += y; + RenderMatrix::identity(&m); + RenderMatrix::scale(&m, factor); + RenderMatrix::rotate(&m, degree); + RenderMatrix::translate(&m, x, y); return true; } - - RenderTransform& operator*=(const RenderTransform rhs) - { - e11 = e11 * rhs.e11 + e12 * rhs.e21 + e13 * rhs.e31; - e12 = e11 * rhs.e12 + e12 * rhs.e22 + e13 * rhs.e32; - e13 = e11 * rhs.e13 + e12 * rhs.e23 + e13 * rhs.e33; - - e21 = e21 * rhs.e11 + e22 * rhs.e21 + e23 * rhs.e31; - e22 = e21 * rhs.e12 + e22 * rhs.e22 + e23 * rhs.e32; - e23 = e21 * rhs.e13 + e22 * rhs.e23 + e23 * rhs.e33; - - e31 = e31 * rhs.e11 + e32 * rhs.e21 + e33 * rhs.e31; - e32 = e31 * rhs.e12 + e32 * rhs.e22 + e33 * rhs.e32; - e33 = e31 * rhs.e13 + e32 * rhs.e23 + e33 * rhs.e33; - - return *this; - } }; @@ -119,7 +136,7 @@ class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; + virtual void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 4b2a6131..dba9637a 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -64,21 +64,30 @@ int Scene::reserve(size_t size) noexcept } -int Scene::scale(float scaleFacator) noexcept +int Scene::scale(float factor) noexcept { - return 0; + auto impl = pImpl.get(); + assert(impl); + + return impl->scale(factor); } int Scene::rotate(float degree) noexcept { - return 0; + auto impl = pImpl.get(); + assert(impl); + + return impl->rotate(degree); } int Scene::translate(float x, float y) noexcept { - return 0; + auto impl = pImpl.get(); + assert(impl); + + return impl->translate(x, y); } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index a2ce90d4..4def2231 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -26,11 +26,14 @@ struct Scene::Impl { vector paints; + RenderTransform *transform = nullptr; + size_t flag = RenderUpdateFlag::None; ~Impl() { //Are you sure clear() prior to this? assert(paints.empty()); + if (transform) delete(transform); } bool clear(RenderMethod& renderer) @@ -48,18 +51,44 @@ struct Scene::Impl return true; } - bool update(RenderMethod &renderer) + bool updateInternal(RenderMethod &renderer, const RenderMatrix* transform, size_t flag) { for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->update(renderer)) return false; + if (!SCENE_IMPL->update(renderer, transform, flag)) return false; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->update(*shape, renderer)) return false; + if (!SHAPE_IMPL->update(*shape, renderer, transform, flag)) return false; } } return true; } + bool update(RenderMethod &renderer, const RenderMatrix* pTransform = nullptr, size_t pFlag = 0) + { + if (flag & RenderUpdateFlag::Transform) { + assert(transform); + if (!transform->update()) { + delete(transform); + transform = nullptr; + } + } + + auto ret = true; + + if (transform && pTransform) { + RenderMatrix outTransform; + RenderMatrix::multiply(pTransform, &transform->m, &outTransform); + ret = updateInternal(renderer, &outTransform, pFlag | flag); + } else { + auto outTransform = pTransform ? pTransform : &transform->m; + ret = updateInternal(renderer, outTransform, pFlag | flag); + } + + flag = RenderUpdateFlag::None; + + return ret; + } + bool render(RenderMethod &renderer) { for(auto paint: paints) { @@ -94,6 +123,52 @@ struct Scene::Impl } return true; } + + bool scale(float factor) + { + if (transform) { + if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1; + } else { + if (fabsf(factor) <= FLT_EPSILON) return -1; + transform = new RenderTransform(); + assert(transform); + } + transform->factor = factor; + flag |= RenderUpdateFlag::Transform; + + return 0; + } + + bool rotate(float degree) + { + if (transform) { + if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1; + } else { + if (fabsf(degree) <= FLT_EPSILON) return -1; + transform = new RenderTransform(); + assert(transform); + } + transform->degree = degree; + flag |= RenderUpdateFlag::Transform; + + return 0; + } + + bool translate(float x, float y) + { + if (transform) { + if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1; + } else { + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1; + transform = new RenderTransform(); + assert(transform); + } + transform->x = x; + transform->y = y; + flag |= RenderUpdateFlag::Transform; + + return 0; + } }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index e552a3ba..30874262 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -66,7 +66,7 @@ struct Shape::Impl return renderer.render(shape, edata); } - bool update(Shape& shape, RenderMethod& renderer) + bool update(Shape& shape, RenderMethod& renderer, const RenderMatrix* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { assert(transform); @@ -75,7 +75,16 @@ struct Shape::Impl transform = nullptr; } } - edata = renderer.prepare(shape, edata, transform, static_cast(flag)); + + if (transform && pTransform) { + RenderMatrix outTransform; + RenderMatrix::multiply(pTransform, &transform->m, &outTransform); + edata = renderer.prepare(shape, edata, &outTransform, static_cast(pFlag | flag)); + } else { + auto outTransform = pTransform ? pTransform : &transform->m; + edata = renderer.prepare(shape, edata, outTransform, static_cast(pFlag | flag)); + } + flag = RenderUpdateFlag::None; if (edata) return true; diff --git a/test/makefile b/test/makefile index e437084c..50710e08 100644 --- a/test/makefile +++ b/test/makefile @@ -9,3 +9,4 @@ all: 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 testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp new file mode 100644 index 00000000..622dafc4 --- /dev/null +++ b/test/testSceneTransform.cpp @@ -0,0 +1,168 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::Scene* pScene1 = nullptr; +tvg::Scene* pScene2 = nullptr; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Create a Scene + auto scene = tvg::Scene::gen(); + pScene1 = scene.get(); + scene->reserve(3); //reserve 3 shape nodes (optional) + + //Prepare Round Rectangle + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(-235, -250, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->fill(0, 255, 0, 255); //r, g, b, a + scene->push(move(shape1)); + + //Prepare Circle + auto shape2 = tvg::Shape::gen(); + shape2->appendCircle(-165, -150, 200, 200); //cx, cy, radiusW, radiusH + shape2->fill(255, 255, 0, 255); //r, g, b, a + scene->push(move(shape2)); + + //Prepare Ellipse + auto shape3 = tvg::Shape::gen(); + shape3->appendCircle(265, 250, 150, 100); //cx, cy, radiusW, radiusH + shape3->fill(0, 255, 255, 255); //r, g, b, a + scene->push(move(shape3)); + + scene->translate(350, 350); + scene->scale(0.7); + + //Create another Scene + auto scene2 = tvg::Scene::gen(); + pScene2 = scene2.get(); + scene2->reserve(2); //reserve 2 shape nodes (optional) + +#if 0 + //Star + auto shape4 = tvg::Shape::gen(); + + //Appends Paths + shape4->moveTo(0, -114.5); + shape4->lineTo(54, -5.5); + shape4->lineTo(175, 11.5); + shape4->lineTo(88, 95.5); + shape4->lineTo(108, 216.5); + shape4->lineTo(0, 160.5); + shape4->lineTo(-102, 216.5); + shape4->lineTo(-87, 96.5); + shape4->lineTo(-173, 12.5); + shape4->lineTo(-53, -5.5); + shape4->close(); + shape4->fill(0, 0, 127, 127); + + float x, y, w, h; + shape4->bounds(x, y, w, h); + scene2->push(move(shape4)); + + //Circle + auto shape5 = tvg::Shape::gen(); + + auto cx = -150.0f; + auto cy = -150.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Append Paths + shape5->moveTo(cx, cy - radius); + shape5->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy); + shape5->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); + shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); + shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); + shape5->fill(127, 0, 0, 127); + scene2->push(move(shape5)); + + scene2->translate(300, 300); + + //Push scene2 onto the scene + scene->push(move(scene2)); +#endif + //Draw the Scene onto the Canvas + canvas->push(move(scene)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + /* Update scene directly. + You can update only necessary properties of this scene, + while retaining other properties. */ + + pScene1->rotate(360 * progress); + + //Update shape for drawing (this may work asynchronously) + canvas->update(pScene1); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + 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_go(transit); + + elm_run(); + elm_shutdown(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} From 2f833298c3b68d41771edf8093da4fb39184bcad Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 17 May 2020 20:34:58 +0900 Subject: [PATCH 055/244] test: update transform sample Change-Id: I7f1416d9e32b241e50b7e2132764cac28d590a93 --- test/testTransform.cpp | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/test/testTransform.cpp b/test/testTransform.cpp index faab048f..48d496b2 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -9,6 +9,8 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; unique_ptr canvas = nullptr; tvg::Shape* pShape = nullptr; +tvg::Shape* pShape2 = nullptr; +tvg::Shape* pShape3 = nullptr; void tvgtest() { @@ -16,7 +18,7 @@ void tvgtest() canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape + //Shape1 auto shape = tvg::Shape::gen(); /* Acquire shape pointer to access it again. @@ -28,10 +30,28 @@ void tvgtest() shape->appendCircle(115, 100, 100, 100); shape->appendCircle(115, 200, 170, 100); shape->fill(255, 255, 255, 255); - shape->translate(285, 300); - + shape->translate(385, 400); canvas->push(move(shape)); + //Shape2 + auto shape2 = tvg::Shape::gen(); + pShape2 = shape2.get(); + shape2->appendRect(-50, -50, 100, 100, 0); + shape2->fill(0, 255, 255, 255); + shape2->translate(400, 400); + canvas->push(move(shape2)); + + //Shape3 + auto shape3 = tvg::Shape::gen(); + pShape3 = shape3.get(); + + /* Look, how shape3's origin is different with shape2 + The center of the shape is the anchor point for transformation. */ + shape3->appendRect(100, 100, 150, 50, 20); + shape3->fill(255, 0, 255, 255); + shape3->translate(400, 400); + canvas->push(move(shape3)); + //Draw first frame canvas->draw(); canvas->sync(); @@ -43,12 +63,23 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres You can update only necessary properties of this shape, while retaining other properties. */ + //Update Shape1 pShape->scale(1 - 0.75 * progress); pShape->rotate(360 * progress); //Update shape for drawing (this may work asynchronously) canvas->update(pShape); + //Update Shape2 + pShape2->rotate(360 * progress); + pShape2->translate(400 + progress * 300, 400); + canvas->update(pShape2); + + //Update Shape2 + pShape3->rotate(-360 * progress); + pShape3->scale(0.5 + progress); + canvas->update(pShape3); + //Draw Next frames canvas->draw(); canvas->sync(); From 1f6da2d0b6779b2d3a4779d42d881bad9bc5dd09 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 17 May 2020 20:52:58 +0900 Subject: [PATCH 056/244] test: update samples fix some broken test code. Change-Id: I42b0dd8b4c599ea59e0860a40b828936dca1e54d --- test/testDirectUpdate.cpp | 4 ++-- test/testTransform.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 735231a6..799d1351 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -25,9 +25,9 @@ void tvgtest() shape->appendRect(-100, -100, 200, 200, 0); - //fill and rotate properties will be retained + //fill property will be retained shape->fill(127, 255, 255, 255); - shape->rotate(45); + canvas->push(move(shape)); //Draw first frame diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 48d496b2..0a126cc5 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -75,7 +75,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape2->translate(400 + progress * 300, 400); canvas->update(pShape2); - //Update Shape2 + //Update Shape3 pShape3->rotate(-360 * progress); pShape3->scale(0.5 + progress); canvas->update(pShape3); From a5f15a588c5dda01456b6848380aff0547bb541c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 17 May 2020 21:33:56 +0900 Subject: [PATCH 057/244] common scene: complete scene tranfsormation feature. Each scene could conserve its own transformation, the origin could be the parent Paint (if they were beloned to) Thus, you can compose the multi-tranformed scene group which simultenoulsly working in own spaces. See testTransform and testSceneTransform, how they work. Change-Id: I51deb4d66f8fcd024f8dc7a1e1af57c398a9d7fe --- src/lib/gl_engine/tvgGlRenderer.cpp | 2 +- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 2 +- src/lib/tvgRenderCommon.h | 142 +++++++++++++--------------- src/lib/tvgSceneImpl.h | 9 +- src/lib/tvgShapeImpl.h | 7 +- test/testSceneTransform.cpp | 27 +++--- 10 files changed, 89 insertions(+), 108 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 48a0ee56..792e5241 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 557f9e70..4d6ba793 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,7 +23,7 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 3068b9bb..62a6b297 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -96,7 +96,7 @@ void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderMatrix& transform); +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 2d974450..36e367b2 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 4c0a7baa..3dfb076c 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index efad9328..d7229dce 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -215,7 +215,7 @@ void _deleteRle(SwShape& sdata) /* External Class Implementation */ /************************************************************************/ -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderMatrix& transform) +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform) { auto outline = sdata.outline; assert(outline); diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 0ad1d558..f40639db 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -30,85 +30,13 @@ struct Surface enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; -struct RenderMatrix +struct RenderTransform { //3x3 Matrix Elements float e11, e12, e13; float e21, e22, e23; float e31, e32, e33; - static void rotate(RenderMatrix* out, float degree) - { - constexpr auto PI = 3.141592f; - - if (fabsf(degree) < FLT_EPSILON) return; - - auto radian = degree / 180.0f * PI; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - auto t11 = out->e11 * cosVal + out->e12 * sinVal; - auto t12 = out->e11 * -sinVal + out->e12 * cosVal; - auto t21 = out->e21 * cosVal + out->e22 * sinVal; - auto t22 = out->e21 * -sinVal + out->e22 * cosVal; - auto t31 = out->e31 * cosVal + out->e32 * sinVal; - auto t32 = out->e31 * -sinVal + out->e32 * cosVal; - - out->e11 = t11; - out->e12 = t12; - out->e21 = t21; - out->e22 = t22; - out->e31 = t31; - out->e32 = t32; - } - - static void scale(RenderMatrix* out, float factor) - { - out->e11 *= factor; - out->e22 *= factor; - out->e33 *= factor; - } - - static void identity(RenderMatrix* out) - { - out->e11 = 1.0f; - out->e12 = 0.0f; - out->e13 = 0.0f; - out->e21 = 0.0f; - out->e22 = 1.0f; - out->e23 = 0.0f; - out->e31 = 0.0f; - out->e32 = 0.0f; - out->e33 = 1.0f; - } - - static void translate(RenderMatrix* out, float x, float y) - { - out->e31 += x; - out->e32 += y; - } - - static void multiply(const RenderMatrix* lhs, const RenderMatrix* rhs, RenderMatrix* out) - { - assert(lhs && rhs && out); - - out->e11 = lhs->e11 * rhs->e11 + lhs->e12 * rhs->e21 + lhs->e13 * rhs->e31; - out->e12 = lhs->e11 * rhs->e12 + lhs->e12 * rhs->e22 + lhs->e13 * rhs->e32; - out->e13 = lhs->e11 * rhs->e13 + lhs->e12 * rhs->e23 + lhs->e13 * rhs->e33; - - out->e21 = lhs->e21 * rhs->e11 + lhs->e22 * rhs->e21 + lhs->e23 * rhs->e31; - out->e22 = lhs->e21 * rhs->e12 + lhs->e22 * rhs->e22 + lhs->e23 * rhs->e32; - out->e23 = lhs->e21 * rhs->e13 + lhs->e22 * rhs->e23 + lhs->e23 * rhs->e33; - - out->e31 = lhs->e31 * rhs->e11 + lhs->e32 * rhs->e21 + lhs->e33 * rhs->e31; - out->e32 = lhs->e31 * rhs->e12 + lhs->e32 * rhs->e22 + lhs->e33 * rhs->e32; - out->e33 = lhs->e31 * rhs->e13 + lhs->e32 * rhs->e23 + lhs->e33 * rhs->e33; - } -}; - -struct RenderTransform -{ - RenderMatrix m; float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree @@ -116,19 +44,77 @@ struct RenderTransform bool update() { + constexpr auto PI = 3.141592f; + //Init Status if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { return false; } - RenderMatrix::identity(&m); - RenderMatrix::scale(&m, factor); - RenderMatrix::rotate(&m, degree); - RenderMatrix::translate(&m, x, y); + //identity + e11 = 1.0f; + e12 = 0.0f; + e13 = 0.0f; + e21 = 0.0f; + e22 = 1.0f; + e23 = 0.0f; + e31 = 0.0f; + e32 = 0.0f; + e33 = 1.0f; + + //scale + e11 *= factor; + e22 *= factor; + e33 *= factor; + + //rotation + if (fabsf(degree) > FLT_EPSILON) { + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; + + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } + + e31 += x; + e32 += y; return true; } + + RenderTransform() + { + } + + RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) + { + assert(lhs && rhs); + + auto dx = rhs->x * lhs->factor; + auto dy = rhs->y * lhs->factor; + auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; + auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; + + x = lhs->x + tx; + y = lhs->y + ty; + degree = lhs->degree + rhs->degree; + factor = lhs->factor * rhs->factor; + + update(); + } }; @@ -136,7 +122,7 @@ class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) = 0; + virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 4def2231..abd29e67 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -51,7 +51,7 @@ struct Scene::Impl return true; } - bool updateInternal(RenderMethod &renderer, const RenderMatrix* transform, size_t flag) + bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, size_t flag) { for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { @@ -63,7 +63,7 @@ struct Scene::Impl return true; } - bool update(RenderMethod &renderer, const RenderMatrix* pTransform = nullptr, size_t pFlag = 0) + bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { assert(transform); @@ -76,11 +76,10 @@ struct Scene::Impl auto ret = true; if (transform && pTransform) { - RenderMatrix outTransform; - RenderMatrix::multiply(pTransform, &transform->m, &outTransform); + RenderTransform outTransform(pTransform, transform); ret = updateInternal(renderer, &outTransform, pFlag | flag); } else { - auto outTransform = pTransform ? pTransform : &transform->m; + auto outTransform = pTransform ? pTransform : transform; ret = updateInternal(renderer, outTransform, pFlag | flag); } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 30874262..b7f99277 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -66,7 +66,7 @@ struct Shape::Impl return renderer.render(shape, edata); } - bool update(Shape& shape, RenderMethod& renderer, const RenderMatrix* pTransform = nullptr, size_t pFlag = 0) + bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { assert(transform); @@ -77,11 +77,10 @@ struct Shape::Impl } if (transform && pTransform) { - RenderMatrix outTransform; - RenderMatrix::multiply(pTransform, &transform->m, &outTransform); + RenderTransform outTransform(pTransform, transform); edata = renderer.prepare(shape, edata, &outTransform, static_cast(pFlag | flag)); } else { - auto outTransform = pTransform ? pTransform : &transform->m; + auto outTransform = pTransform ? pTransform : transform; edata = renderer.prepare(shape, edata, outTransform, static_cast(pFlag | flag)); } diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 622dafc4..38bfb0f2 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -20,39 +20,38 @@ void tvgtest() canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Create a Scene + //Create a Scene1 auto scene = tvg::Scene::gen(); pScene1 = scene.get(); scene->reserve(3); //reserve 3 shape nodes (optional) - //Prepare Round Rectangle + //Prepare Round Rectangle (Scene1) auto shape1 = tvg::Shape::gen(); shape1->appendRect(-235, -250, 400, 400, 50); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //r, g, b, a scene->push(move(shape1)); - //Prepare Circle + //Prepare Circle (Scene1) auto shape2 = tvg::Shape::gen(); shape2->appendCircle(-165, -150, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(255, 255, 0, 255); //r, g, b, a scene->push(move(shape2)); - //Prepare Ellipse + //Prepare Ellipse (Scene1) auto shape3 = tvg::Shape::gen(); shape3->appendCircle(265, 250, 150, 100); //cx, cy, radiusW, radiusH shape3->fill(0, 255, 255, 255); //r, g, b, a scene->push(move(shape3)); scene->translate(350, 350); - scene->scale(0.7); + scene->scale(0.5); - //Create another Scene + //Create Scene2 auto scene2 = tvg::Scene::gen(); pScene2 = scene2.get(); scene2->reserve(2); //reserve 2 shape nodes (optional) -#if 0 - //Star + //Star (Scene2) auto shape4 = tvg::Shape::gen(); //Appends Paths @@ -68,17 +67,14 @@ void tvgtest() shape4->lineTo(-53, -5.5); shape4->close(); shape4->fill(0, 0, 127, 127); - - float x, y, w, h; - shape4->bounds(x, y, w, h); scene2->push(move(shape4)); - //Circle + //Circle (Scene2) auto shape5 = tvg::Shape::gen(); auto cx = -150.0f; auto cy = -150.0f; - auto radius = 125.0f; + auto radius = 100.0f; auto halfRadius = radius * 0.552284f; //Append Paths @@ -90,11 +86,11 @@ void tvgtest() shape5->fill(127, 0, 0, 127); scene2->push(move(shape5)); - scene2->translate(300, 300); + scene2->translate(500, 350); //Push scene2 onto the scene scene->push(move(scene2)); -#endif + //Draw the Scene onto the Canvas canvas->push(move(scene)); @@ -112,6 +108,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres while retaining other properties. */ pScene1->rotate(360 * progress); + pScene2->rotate(360 * progress); //Update shape for drawing (this may work asynchronously) canvas->update(pScene1); From 19999e7abd146b864e590cd1c4054c13f60fa439 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 22 May 2020 16:18:32 +0900 Subject: [PATCH 058/244] common stroke: implement stroke interfaces. Change-Id: I28fe5d5df4cde6640b143e67e241c6afc9c6b1fe --- inc/tizenvg.h | 8 +++++ src/lib/tvgRenderCommon.h | 2 +- src/lib/tvgShape.cpp | 75 +++++++++++++++++++++++++++++++++++++++ src/lib/tvgShapeImpl.h | 61 +++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 98b6fafd..bfaa960f 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -136,6 +136,10 @@ public: int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; + int stroke(size_t width) noexcept; + int stroke(size_t r, size_t g, size_t b, size_t a) noexcept; + int stroke(const size_t* dashPattern, size_t cnt) noexcept; + int fill(size_t r, size_t g, size_t b, size_t a) noexcept; int rotate(float degree) noexcept override; @@ -145,6 +149,10 @@ public: size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + size_t stroke() const noexcept; + int stroke(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + size_t stroke(const size_t** dashPattern) const noexcept; + int bounds(float&x, float& y, float& w, float& h) const noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index f40639db..61cd6556 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -28,7 +28,7 @@ struct Surface size_t w, h; }; -enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; +enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Stroke = 4, Transform = 8, All = 16}; struct RenderTransform { diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 432a8a66..342f4566 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -280,4 +280,79 @@ int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept } +int Shape::stroke(size_t width) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->strokeWidth(width)) return -1; + + return 0; +} + + +size_t Shape::stroke() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->stroke) return -1; + return impl->stroke->width; +} + + +int Shape::stroke(size_t r, size_t g, size_t b, size_t a) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->strokeColor(r, g, b, a)) return -1; + + return 0; +} + + +int Shape::stroke(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->stroke) return -1; + + if (r) *r = impl->stroke->color[0]; + if (g) *g = impl->stroke->color[1]; + if (b) *b = impl->stroke->color[2]; + if (a) *a = impl->stroke->color[3]; + + return 0; +} + + +int Shape::stroke(const size_t* dashPattern, size_t cnt) noexcept +{ + if (cnt < 2 || !dashPattern) return -1; + + auto impl = pImpl.get(); + assert(impl); + + if (!impl->strokeDash(dashPattern, cnt)) return -1; + + return 0; +} + + +size_t Shape::stroke(const size_t** dashPattern) const noexcept +{ + assert(dashPattern); + + auto impl = pImpl.get(); + assert(impl); + + if (!impl->stroke) return 0; + + *dashPattern = impl->stroke->dashPattern; + return impl->stroke->dashCnt; +} + + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index b7f99277..e2ba294a 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -30,6 +30,15 @@ struct ShapeFill struct ShapeStroke { + size_t width = 0; + size_t color[4] = {0, 0, 0, 0}; + size_t* dashPattern = nullptr; + size_t dashCnt = 0; + + ~ShapeStroke() + { + if (dashPattern) free(dashPattern); + } }; @@ -141,6 +150,58 @@ struct Shape::Impl return 0; } + + bool strokeWidth(size_t width) + { + //TODO: Size Exception? + + if (!stroke) stroke = new ShapeStroke(); + assert(stroke); + + stroke->width = width; + flag |= RenderUpdateFlag::Stroke; + + return 0; + } + + bool strokeColor(size_t r, size_t g, size_t b, size_t a) + { + if (!stroke) stroke = new ShapeStroke(); + assert(stroke); + + stroke->color[0] = r; + stroke->color[1] = g; + stroke->color[2] = b; + stroke->color[3] = a; + + flag |= RenderUpdateFlag::Stroke; + + return 0; + } + + bool strokeDash(const size_t* pattern, size_t cnt) + { + assert(pattern); + + if (!stroke) stroke = new ShapeStroke(); + assert(stroke); + + if (stroke->dashCnt != cnt) { + if (stroke->dashPattern) free(stroke->dashPattern); + stroke->dashPattern = nullptr; + } + + if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(size_t) * cnt)); + assert(stroke->dashPattern); + + memcpy(stroke->dashPattern, pattern, cnt); + stroke->dashCnt = cnt; + + flag |= RenderUpdateFlag::Stroke; + + return 0; + + } }; #endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file From a0521c83c3f56e9c022d5ed590d04f0d8e75baf6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 22 May 2020 16:30:13 +0900 Subject: [PATCH 059/244] common paint: revise bounds interface. we don't use the reference style for user interfaces. Change-Id: Id70682bf8c2d8ea9ffab2ea6fb567eaa8639da60 --- inc/tizenvg.h | 6 +++--- src/lib/tvgScene.cpp | 7 +------ src/lib/tvgSceneImpl.h | 17 ++++++++++++++--- src/lib/tvgShape.cpp | 2 +- src/lib/tvgShapeImpl.h | 2 +- src/lib/tvgShapePath.h | 10 +++++----- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index bfaa960f..dbdcd66c 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -81,7 +81,7 @@ public: virtual int scale(float factor) = 0; virtual int translate(float x, float y) = 0; - virtual int bounds(float&x, float& y, float& w, float& h) const = 0; + virtual int bounds(float* x, float* y, float* w, float* h) const = 0; }; @@ -153,7 +153,7 @@ public: int stroke(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; size_t stroke(const size_t** dashPattern) const noexcept; - int bounds(float&x, float& y, float& w, float& h) const noexcept override; + int bounds(float* x, float* y, float* w, float* h) const noexcept override; static std::unique_ptr gen() noexcept; @@ -183,7 +183,7 @@ public: int scale(float factor) noexcept override; int translate(float x, float y) noexcept override; - int bounds(float&x, float& y, float& w, float& h) const noexcept override; + int bounds(float* x, float* y, float* w, float* h) const noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index dba9637a..93a64b1c 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -91,16 +91,11 @@ int Scene::translate(float x, float y) noexcept } -int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept +int Scene::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); assert(impl); - x = FLT_MAX; - y = FLT_MAX; - w = 0; - h = 0; - if (!impl->bounds(x, y, w, h)) return -1; return 0; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index abd29e67..9064b533 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -100,8 +100,13 @@ struct Scene::Impl return true; } - bool bounds(float& x, float& y, float& w, float& h) + bool bounds(float* px, float* py, float* pw, float* ph) { + auto x = FLT_MAX; + auto y = FLT_MAX; + auto w = 0.0f; + auto h = 0.0f; + for(auto paint: paints) { auto x2 = FLT_MAX; auto y2 = FLT_MAX; @@ -109,9 +114,9 @@ struct Scene::Impl auto h2 = 0.0f; if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->bounds(x2, y2, w2, h2)) return false; + if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->bounds(x2, y2, w2, h2)) return false; + if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; } //Merge regions @@ -120,6 +125,12 @@ struct Scene::Impl if (y2 < y) y = x2; if (y + h < y2 + h2) h = (y2 + h2) - y; } + + if (px) *px = x; + if (py) *py = y; + if (pw) *pw = w; + if (ph) *ph = h; + return true; } diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 342f4566..c8483e1b 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -269,7 +269,7 @@ int Shape::translate(float x, float y) noexcept } -int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept +int Shape::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index e2ba294a..1800b70d 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -99,7 +99,7 @@ struct Shape::Impl return false; } - bool bounds(float& x, float& y, float& w, float& h) + bool bounds(float* x, float* y, float* w, float* h) { assert(path); return path->bounds(x, y, w, h); diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 9dafdf92..68205f48 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -113,7 +113,7 @@ struct ShapePath cmds[cmdCnt++] = PathCommand::Close; } - bool bounds(float& x, float& y, float& w, float& h) + bool bounds(float* x, float* y, float* w, float* h) { if (ptsCnt == 0) return false; @@ -127,10 +127,10 @@ struct ShapePath if (pts[i].y > max.y) max.y = pts[i].y; } - x = min.x; - y = min.y; - w = max.x - min.x; - h = max.y - min.y; + if (x) *x = min.x; + if (y) *y = min.y; + if (w) *w = max.x - min.x; + if (h) *h = max.y - min.y; return true; } From 4799426396f16d29a21c1d4632caae32fa383d73 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 23 May 2020 13:32:28 +0900 Subject: [PATCH 060/244] common shape: introduce stroke cap and join styles. + revise the getter functions for avoiding invalid overloading. Change-Id: Ie8b0cbe57435253d75871e864c7cd263a14d6df3 --- inc/tizenvg.h | 22 +++++++++++++---- src/lib/tvgShape.cpp | 54 +++++++++++++++++++++++++++++++++++++----- src/lib/tvgShapeImpl.h | 24 +++++++++++++++++++ 3 files changed, 89 insertions(+), 11 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index dbdcd66c..08c85563 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -53,7 +53,9 @@ protected: \ namespace tvg { -enum class TIZENVG_EXPORT PathCommand { Close, MoveTo, LineTo, CubicTo }; +enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; +enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; +enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; class RenderMethod; class Scene; @@ -127,34 +129,44 @@ public: int reset() noexcept; + //Path int moveTo(float x, float y) noexcept; int lineTo(float x, float y) noexcept; int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; int close() noexcept; + //Shape int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; + //Stroke int stroke(size_t width) noexcept; int stroke(size_t r, size_t g, size_t b, size_t a) noexcept; int stroke(const size_t* dashPattern, size_t cnt) noexcept; + int stroke(StrokeCap cap) noexcept; + int stroke(StrokeJoin join) noexcept; + //Fill int fill(size_t r, size_t g, size_t b, size_t a) noexcept; + //Transform int rotate(float degree) noexcept override; int scale(float factor) noexcept override; int translate(float x, float y) noexcept override; + //Getters size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; - size_t stroke() const noexcept; - int stroke(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; - size_t stroke(const size_t** dashPattern) const noexcept; - int bounds(float* x, float* y, float* w, float* h) const noexcept override; + size_t strokeWidth() const noexcept; + int strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + size_t strokeDash(const size_t** dashPattern) const noexcept; + StrokeCap strokeCap() const noexcept; + StrokeJoin strokeJoin() const noexcept; + static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_ACCESSOR(Scene); diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index c8483e1b..a17c53b0 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -291,7 +291,7 @@ int Shape::stroke(size_t width) noexcept } -size_t Shape::stroke() const noexcept +size_t Shape::strokeWidth() const noexcept { auto impl = pImpl.get(); assert(impl); @@ -312,7 +312,7 @@ int Shape::stroke(size_t r, size_t g, size_t b, size_t a) noexcept } -int Shape::stroke(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); @@ -341,18 +341,60 @@ int Shape::stroke(const size_t* dashPattern, size_t cnt) noexcept } -size_t Shape::stroke(const size_t** dashPattern) const noexcept +size_t Shape::strokeDash(const size_t** dashPattern) const noexcept { - assert(dashPattern); - auto impl = pImpl.get(); assert(impl); if (!impl->stroke) return 0; - *dashPattern = impl->stroke->dashPattern; + if (dashPattern) *dashPattern = impl->stroke->dashPattern; return impl->stroke->dashCnt; } +int Shape::stroke(StrokeCap cap) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->strokeCap(cap)) return -1; + + return 0; +} + + +int Shape::stroke(StrokeJoin join) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->strokeJoin(join)) return -1; + + return 0; +} + + +StrokeCap Shape::strokeCap() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->stroke) return StrokeCap::Square; + + return impl->stroke->cap; +} + + +StrokeJoin Shape::strokeJoin() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + if (!impl->stroke) return StrokeJoin::Bevel; + + return impl->stroke->join; +} + + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 1800b70d..682c29b7 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -34,6 +34,8 @@ struct ShapeStroke size_t color[4] = {0, 0, 0, 0}; size_t* dashPattern = nullptr; size_t dashCnt = 0; + StrokeCap cap = StrokeCap::Square; + StrokeJoin join = StrokeJoin::Bevel; ~ShapeStroke() { @@ -164,6 +166,28 @@ struct Shape::Impl return 0; } + bool strokeCap(StrokeCap cap) + { + if (!stroke) stroke = new ShapeStroke(); + assert(stroke); + + stroke->cap = cap; + flag |= RenderUpdateFlag::Stroke; + + return 0; + } + + bool strokeJoin(StrokeJoin join) + { + if (!stroke) stroke = new ShapeStroke(); + assert(stroke); + + stroke->join = join; + flag |= RenderUpdateFlag::Stroke; + + return 0; + } + bool strokeColor(size_t r, size_t g, size_t b, size_t a) { if (!stroke) stroke = new ShapeStroke(); From 48e47b272bd474b5a6f5fc1131e2730bfc73e5c0 Mon Sep 17 00:00:00 2001 From: Prudhvi Raj Vasireddi Date: Mon, 11 May 2020 17:39:08 -0400 Subject: [PATCH 061/244] gl_engine: gl infrastructure interfaces Change-Id: Ie1a9d1b6632433413098282c1cfaf4cf8e1cf9b9 Signed-off-by: Prudhvi Raj Vasireddi --- inc/tizenvg.h | 1 + src/lib/gl_engine/meson.build | 9 +- src/lib/gl_engine/tvgGlCommon.h | 19 +++ src/lib/gl_engine/tvgGlGeometry.h | 180 ++++++++++++++++++++++++++++ src/lib/gl_engine/tvgGlGpuBuffer.h | 26 ++++ src/lib/gl_engine/tvgGlProgram.h | 29 +++++ src/lib/gl_engine/tvgGlRenderer.cpp | 5 - src/lib/gl_engine/tvgGlRenderer.h | 12 ++ src/lib/gl_engine/tvgGlShader.h | 20 ++++ src/lib/tvgGlCanvas.cpp | 11 ++ src/meson.build | 6 +- 11 files changed, 310 insertions(+), 8 deletions(-) create mode 100644 src/lib/gl_engine/tvgGlCommon.h create mode 100644 src/lib/gl_engine/tvgGlGeometry.h create mode 100644 src/lib/gl_engine/tvgGlGpuBuffer.h create mode 100644 src/lib/gl_engine/tvgGlProgram.h create mode 100644 src/lib/gl_engine/tvgGlShader.h diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 98b6fafd..c133ace7 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -220,6 +220,7 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. + int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 13e7fefe..41a25e00 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -1,7 +1,12 @@ source_file = [ - 'tvgGlRenderer.h', + 'tvgGlCommon.h', + 'tvgGlGpuBuffer.h', + 'tvgGlProgram.h', 'tvgGlRenderer.cpp', -] + 'tvgGlRenderer.h', + 'tvgGlShader.h', + 'tvgGlGeometry.h', + ] glraster_dep = declare_dependency( include_directories : include_directories('.'), diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h new file mode 100644 index 00000000..f68666a4 --- /dev/null +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -0,0 +1,19 @@ +#ifndef _TVG_GL_COMMON_H_ +#define _TVG_GL_COMMON_H_ + +#include "tvgCommon.h" +#include "tvgGlProgram.h" +#include "tvgGlShader.h" +#include "tvgGlGeometry.h" + + +struct GlShape +{ + float viewWd; + float viewHt; + RenderUpdateFlag updateFlag; + unique_ptr geometry; +}; + + +#endif /* _TVG_GL_COMMON_H_ */ diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h new file mode 100644 index 00000000..8f7cc610 --- /dev/null +++ b/src/lib/gl_engine/tvgGlGeometry.h @@ -0,0 +1,180 @@ +#ifndef _TVG_GL_GEOMETRY_H_ +#define _TVG_GL_GEOMETRY_H_ + +#include "tvgGlGpuBuffer.h" + +class GlPoint +{ +public: + float x = 0.0f; + float y = 0.0f; + + GlPoint(float pX, float pY):x(pX), y(pY) + {} + + GlPoint(const Point& rhs):GlPoint(rhs.x, rhs.y) + {} + + GlPoint(const GlPoint& rhs) = default; + GlPoint(GlPoint&& rhs) = default; + + GlPoint& operator= (const GlPoint& rhs) = default; + GlPoint& operator= (GlPoint&& rhs) = default; + + GlPoint& operator= (const Point& rhs) + { + x = rhs.x; + y = rhs.y; + return *this; + } + + bool operator== (const GlPoint& rhs) + { + if (&rhs == this) + return true; + if (rhs.x == this->x && rhs.y == this->y) + return true; + return false; + } + + bool operator!= (const GlPoint& rhs) + { + if (&rhs == this) + return true; + if (rhs.x != this->x || rhs.y != this->y) + return true; + return false; + } + + GlPoint operator+ (const GlPoint& rhs) const + { + return GlPoint(x + rhs.x, y + rhs.y); + } + + GlPoint operator+ (const float c) const + { + return GlPoint(x + c, y + c); + } + + GlPoint operator- (const GlPoint& rhs) const + { + return GlPoint(x - rhs.x, y - rhs.y); + } + + GlPoint operator- (const float c) const + { + return GlPoint(x - c, y - c); + } + + GlPoint operator* (const GlPoint& rhs) const + { + return GlPoint(x * rhs.x, y * rhs.y); + } + + GlPoint operator* (const float c) const + { + return GlPoint(x * c, y * c); + } + + GlPoint operator/ (const GlPoint& rhs) const + { + return GlPoint(x / rhs.x, y / rhs.y); + } + + GlPoint operator/ (const float c) const + { + return GlPoint(x / c, y / c); + } + + void mod() + { + x = fabsf(x); + y = fabsf(y); + } + + void normalize() + { + auto length = sqrtf( (x * x) + (y * y) ); + if (length != 0.0f) + { + const auto inverseLen = 1.0f / length; + x *= inverseLen; + y *= inverseLen; + } + } +}; + +struct SmoothPoint +{ + GlPoint orgPt; + GlPoint fillOuterBlur; + GlPoint fillOuter; + GlPoint strokeOuterBlur; + GlPoint strokeOuter; + GlPoint strokeInnerBlur; + GlPoint strokeInner; + + SmoothPoint(GlPoint pt) + :orgPt(pt), + fillOuterBlur(pt), + fillOuter(pt), + strokeOuterBlur(pt), + strokeOuter(pt), + strokeInnerBlur(pt), + strokeInner(pt) + { + } +}; + +struct PointNormals +{ + GlPoint normal1; + GlPoint normal2; + GlPoint normalF; +}; + +struct VertexData +{ + GlPoint point; + float opacity = 0.0f; +}; + +struct VertexDataArray +{ + vector vertices; + vector indices; +}; + +class GlGeometry +{ +public: + GlGeometry(); + void reset(); + void updateBuffer(const uint32_t location, const VertexDataArray& geometry); + void draw(const VertexDataArray& geometry); + bool decomposeOutline(const Shape& shape); + bool generateAAPoints(const Shape& shape, float strokeWd, RenderUpdateFlag flag); + bool tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag); + + const VertexDataArray& getFill(); + const VertexDataArray& getStroke(); + +private: + GlPoint normalizePoint(GlPoint &pt, float viewWd, float viewHt); + void addGeometryPoint(VertexDataArray &geometry, GlPoint &pt, float viewWd, float viewHt, float opacity); + GlPoint getNormal(GlPoint &p1, GlPoint &p2); + float dotProduct(GlPoint &p1, GlPoint &p2); + GlPoint extendEdge(GlPoint &pt, GlPoint &normal, float scalar); + void addPoint(const GlPoint &pt); + void addTriangleFanIndices(uint32_t &curPt, vector &indices); + void addQuadIndices(uint32_t &curPt, vector &indices); + bool isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2); + void decomposeCubicCurve(const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2); + + unique_ptr mGpuBuffer; + vector mAAPoints; + VertexDataArray mFill; + VertexDataArray mStroke; +}; + +#endif /* _TVG_GL_GEOMETRY_H_ */ diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h new file mode 100644 index 00000000..fd7086a6 --- /dev/null +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -0,0 +1,26 @@ +#ifndef _TVG_GL_GPU_BUFFER_H_ +#define _TVG_GL_GPU_BUFFER_H_ + +#include +#include + +class GlGpuBuffer +{ +public: + enum class Target + { + ARRAY_BUFFER = GL_ARRAY_BUFFER, + ELEMENT_ARRAY_BUFFER = GL_ARRAY_BUFFER + }; + + GlGpuBuffer(); + ~GlGpuBuffer(); + void updateBufferData(Target target, size_t size, void* data); + +private: + uint32_t mGlBufferId = 0; + +}; + +#endif /* _TVG_GL_GPU_BUFFER_H_ */ + diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h new file mode 100644 index 00000000..d485d3d2 --- /dev/null +++ b/src/lib/gl_engine/tvgGlProgram.h @@ -0,0 +1,29 @@ +#ifndef _TVG_GL_PROGRAM_H_ +#define _TVG_GL_PROGRAM_H_ + +#include "tvgGlShader.h" + +#include + + +class GlProgram +{ +public: + GlProgram(shared_ptr shader); + void create(); + void load(); + int32_t getAttributeLocation(const char* name); + int32_t getUniformLocation(const char* name); + void setUniformValue(int32_t location, float r, float g, float b, float a); + +private: + void linkProgram(); + std::shared_ptr mShader; + uint32_t mProgramObj; + static uint32_t mCurrentProgram; + + static std::map mAttributeBuffer; + static std::map mUniformBuffer; +}; + +#endif /* _TVG_GL_PROGRAM_H_ */ diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 792e5241..0eb9bebc 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -26,11 +26,6 @@ static RenderInitializer renderInit; -struct GlShape -{ - //TODO: -}; - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 4d6ba793..fcde08f1 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -17,15 +17,23 @@ #ifndef _TVG_GL_RENDERER_H_ #define _TVG_GL_RENDERER_H_ +#include "tvgGlCommon.h" + namespace tvg { class GlRenderer : public RenderMethod { public: + Surface surface; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; + bool target(uint32_t* buffer, size_t stride, size_t w, size_t h) + { + return 0; + }; bool clear() override; size_t ref() override; size_t unref() override; @@ -37,6 +45,10 @@ public: private: GlRenderer(){}; ~GlRenderer(){}; + + std::unique_ptr mColorProgram; + int32_t mColorUniform; + uint32_t mVertexAttrID; }; } diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h new file mode 100644 index 00000000..36b125a9 --- /dev/null +++ b/src/lib/gl_engine/tvgGlShader.h @@ -0,0 +1,20 @@ +#ifndef _TVG_GL_SHADER_H_ +#define _TVG_GL_SHADER_H_ + +class GlShader +{ +public: + static shared_ptr gen(const char * vertSrc, const char * fragSrc); + + uint32_t getVertexShader(); + uint32_t getFragmentShader(); + +private: + void createShader(const char* vertSrc, const char* fragSrc); + uint32_t complileShader(uint32_t type, char* shaderSrc); + + uint32_t mVtShader; + uint32_t mFrShader; +}; + +#endif /* _TVG_GL_SHADER_H_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index fb769a83..c1b7aeb5 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -45,6 +45,17 @@ GlCanvas::~GlCanvas() } +int GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +{ + auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + assert(renderer); + + if (!renderer->target(buffer, stride, w, h)) return -1; + + return 0; +} + + int GlCanvas::sync() noexcept { return 0; diff --git a/src/meson.build b/src/meson.build index 495e4c79..aded0018 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,8 +2,12 @@ compiler_flags = ['-DTIZENVG_BUILD'] subdir('lib') subdir('examples') +m_dep = meson.get_compiler('cpp').find_library('m') +egl_dep = meson.get_compiler('cpp').find_library('EGL') +gl_dep = meson.get_compiler('cpp').find_library('GLESv2') + +tizenvg_lib_dep = [ src_dep, swraster_dep, glraster_dep, m_dep, egl_dep, gl_dep] -tizenvg_lib_dep = [ src_dep, swraster_dep, glraster_dep ] tizenvg_lib = library( 'tizenvg', From 6b54eb5c22342caad3dbc2731187ba0c6a25014e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 27 May 2020 11:03:07 +0900 Subject: [PATCH 062/244] updated AUTHORS Change-Id: Id756d25e475e8f8cb8379577032e5b41e772b88e --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 13ce5113..bcfd4d6c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,2 @@ Hermet Park +Prudhvi Raj Vasireddi From c51241f26b8f6ae726d0cf40cde9827e13116f0b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 23 May 2020 20:06:40 +0900 Subject: [PATCH 063/244] sw_engine: implment basic stroke functions. Change-Id: Ib9203b4d133ce7ffd80b40d7ad0cac3519b5273d --- .gitignore | 1 + src/lib/sw_engine/meson.build | 7 +- src/lib/sw_engine/tvgSwCommon.h | 93 +++- src/lib/sw_engine/tvgSwRaster.cpp | 18 +- src/lib/sw_engine/tvgSwRenderer.cpp | 44 +- src/lib/sw_engine/tvgSwRle.cpp | 20 +- src/lib/sw_engine/tvgSwShape.cpp | 111 +++-- src/lib/sw_engine/tvgSwStroke.cpp | 658 ++++++++++++++++++++++++++++ test/makefile | 23 +- test/testStroke.cpp | 66 ++- 10 files changed, 938 insertions(+), 103 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwStroke.cpp diff --git a/.gitignore b/.gitignore index 6210eb83..1353d089 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ testDirectUpdate testScene testTransform testSceneTransform +testStroke diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index a33059dc..b6664719 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,10 +1,11 @@ source_file = [ 'tvgSwCommon.h', 'tvgSwRenderer.h', - 'tvgSwRenderer.cpp', - 'tvgSwShape.cpp', - 'tvgSwRle.cpp', 'tvgSwRaster.cpp', + 'tvgSwRenderer.cpp', + 'tvgSwRle.cpp', + 'tvgSwShape.cpp', + 'tvgSwStroke.cpp', ] swraster_dep = declare_dependency( diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 62a6b297..66d6fe02 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -23,15 +23,27 @@ using namespace tvg; constexpr auto SW_CURVE_TYPE_POINT = 0; constexpr auto SW_CURVE_TYPE_CUBIC = 1; + constexpr auto SW_OUTLINE_FILL_WINDING = 0; constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; +constexpr auto SW_STROKE_TAG_ON = 1; +constexpr auto SW_STROKE_TAG_BEGIN = 4; +constexpr auto SW_STROKE_TAG_END = 8; + using SwCoord = signed long; +using SwFixed = signed long long; struct SwPoint { SwCoord x, y; + SwPoint& operator+=(const SwPoint& rhs) { + x += rhs.x; + y += rhs.y; + return *this; + } + SwPoint operator+(const SwPoint& rhs) const { return {x + rhs.x, y + rhs.y}; } @@ -56,14 +68,15 @@ struct SwSize struct SwOutline { - size_t* cntrs; //the contour end points - size_t cntrsCnt; //number of contours in glyph - size_t reservedCntrsCnt; - SwPoint* pts; //the outline's points - size_t ptsCnt; //number of points in the glyph - size_t reservedPtsCnt; - uint8_t* types; //curve type - uint8_t fillMode; //outline fill mode + uint32_t* cntrs; //the contour end points + uint32_t cntrsCnt; //number of contours in glyph + uint32_t reservedCntrsCnt; + SwPoint* pts; //the outline's points + uint32_t ptsCnt; //number of points in the glyph + uint32_t reservedPtsCnt; + uint8_t* types; //curve type + uint8_t fillMode; //outline fill mode + bool opened; //opened path? }; struct SwSpan @@ -76,8 +89,8 @@ struct SwSpan struct SwRleData { SwSpan *spans; - size_t alloc; - size_t size; + uint32_t alloc; + uint32_t size; }; struct SwBBox @@ -85,19 +98,77 @@ struct SwBBox SwPoint min, max; }; +struct SwStrokeBorder +{ + uint32_t ptsCnt; + uint32_t maxPts; + SwPoint* pts; + uint8_t* tags; + int32_t start; //index of current sub-path start point + bool movable; //true: for ends of lineto borders + bool valid; +}; + +struct SwStroke +{ + SwRleData* rle; + + SwFixed angleIn; + SwFixed angleOut; + SwPoint center; + SwFixed lineLength; + SwPoint subPathStart; + SwFixed subPathLineLength; + SwFixed width; + + StrokeCap cap; + StrokeJoin join; + StrokeJoin joinSaved; + + SwStrokeBorder borders[2]; + + bool firstPt; + bool subPathOpen; + bool subPathAngle; + bool handleWideStrokes; +}; + struct SwShape { SwOutline* outline; SwRleData* rle; + SwStroke* stroke; SwBBox bbox; }; +static inline SwPoint TO_SWPOINT(const Point* pt) +{ + return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; +} + + +static inline SwCoord TO_SWCOORD(float val) +{ + return SwCoord(val * 64); +} + + void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); -void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); +void shapeDelOutline(SwShape& sdata); +void shapeResetStroke(const Shape& shape, SwShape& sdata); +bool shapeGenStrokeOutline(const Shape& shape, SwShape& sdata); +bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip); void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); +void shapeFree(SwShape* sdata); + +void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join); +bool strokeParseOutline(SwStroke& stroke, SwOutline& outline); +void strokeFree(SwStroke* stroke); + SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); +SwRleData* rleStrokeRender(const SwShape& sdata); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 0b813fdf..ba7c6a35 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,52 +24,52 @@ /* Internal Class Implementation */ /************************************************************************/ -static inline size_t COLOR_ALPHA(size_t color) +static inline uint32_t COLOR_ALPHA(uint32_t color) { return (color >> 24) & 0xff; } -static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) +static inline uint32_t COLOR_ALPHA_BLEND(uint32_t color, uint32_t alpha) { return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + ((((color & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); } -static inline size_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (a << 24 | r << 16 | g << 8 | b); } static void -_rasterTranslucent(uint32_t* dst, size_t len, size_t color, size_t cov) +_rasterTranslucent(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) { //OPTIMIZE ME: SIMD if (cov < 255) color = COLOR_ALPHA_BLEND(color, cov); auto ialpha = 255 - COLOR_ALPHA(color); - for (size_t i = 0; i < len; ++i) { + for (uint32_t i = 0; i < len; ++i) { dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); } } static void -_rasterSolid(uint32_t* dst, size_t len, size_t color, size_t cov) +_rasterSolid(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) { //OPTIMIZE ME: SIMD //Fully Opaque if (cov == 255) { - for (size_t i = 0; i < len; ++i) { + for (uint32_t i = 0; i < len; ++i) { dst[i] = color; } } else { auto ialpha = 255 - cov; - for (size_t i = 0; i < len; ++i) { + for (uint32_t i = 0; i < len; ++i) { dst[i] = COLOR_ALPHA_BLEND(color, cov) + COLOR_ALPHA_BLEND(dst[i], ialpha); } } @@ -89,7 +89,7 @@ bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t auto stride = surface.stride; auto color = COLOR_ARGB_JOIN(r, g, b, a); - for (size_t i = 0; i < rle->size; ++i) { + for (uint32_t i = 0; i < rle->size; ++i) { assert(span); auto dst = &surface.buffer[span->y * stride + span->x]; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 36e367b2..bf97c9b3 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -37,8 +37,8 @@ bool SwRenderer::clear() assert(surface.stride > 0 && surface.w > 0 && surface.h > 0); //OPTIMIZE ME: SIMD! - for (size_t i = 0; i < surface.h; i++) { - for (size_t j = 0; j < surface.w; j++) + for (uint32_t i = 0; i < surface.h; i++) { + for (uint32_t j = 0; j < surface.w; j++) surface.buffer[surface.stride * i + j] = 0xff000000; //Solid Black } @@ -57,16 +57,20 @@ bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) return true; } - bool SwRenderer::render(const Shape& shape, void *data) { SwShape* sdata = static_cast(data); if (!sdata) return false; - //invisible? size_t r, g, b, a; shape.fill(&r, &g, &b, &a); + size_t sa; + shape.strokeColor(nullptr, nullptr, nullptr, &sa); + + //invisible? + if (a == 0 && sa == 0) return false; + //TODO: Threading return rasterShape(surface, *sdata, r, g, b, a); } @@ -74,10 +78,9 @@ bool SwRenderer::render(const Shape& shape, void *data) bool SwRenderer::dispose(const Shape& shape, void *data) { - SwShape* sdata = static_cast(data); + auto sdata = static_cast(data); if (!sdata) return false; - shapeReset(*sdata); - free(sdata); + shapeFree(sdata); return true; } @@ -93,21 +96,33 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* if (flags == RenderUpdateFlag::None) return sdata; //invisible? - size_t alpha; - shape.fill(nullptr, nullptr, nullptr, &alpha); - if (alpha == 0) return sdata; + size_t a, sa; + shape.fill(nullptr, nullptr, nullptr, &a); + shape.strokeColor(nullptr, nullptr, nullptr, &sa); + if (a == 0 && sa == 0) return sdata; //TODO: Threading + + SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; + + //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (transform) shapeTransformOutline(shape, *sdata, *transform); - - SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; - shapeDelOutline(*sdata); } + //Stroke + if (flags & RenderUpdateFlag::Stroke) { + shapeResetStroke(shape, *sdata); + if (shape.strokeWidth() > 0.01) { + if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + } + } + + shapeDelOutline(*sdata); + return sdata; } @@ -141,5 +156,4 @@ SwRenderer* SwRenderer::inst() return dynamic_cast(RenderInitializer::inst(renderInit)); } - -#endif /* _TVG_SW_RENDERER_CPP_ */ +#endif /* _TVG_SW_RENDERER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index ea2e4511..3a4b8eda 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -137,7 +137,7 @@ static inline SwCoord HYPOT(SwPoint pt) return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3))); } -static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count) +static void _genSpan(SwRleData* rle, SwSpan* spans, uint32_t count) { assert(rle && spans); @@ -598,15 +598,19 @@ static bool _decomposeOutline(RleWorker& rw) auto first = 0; //index of first point in contour - for (size_t n = 0; n < outline->cntrsCnt; ++n) { + for (uint32_t n = 0; n < outline->cntrsCnt; ++n) { auto last = outline->cntrs[n]; if (last < 0) goto invalid_outline; auto limit = outline->pts + last; assert(limit); + auto start = UPSCALE(outline->pts[first]); + auto pt = outline->pts + first; + assert(pt); auto types = outline->types + first; + assert(types); /* A contour cannot start with a cubic control point! */ if (types[0] == SW_CURVE_TYPE_CUBIC) goto invalid_outline; @@ -632,7 +636,7 @@ static bool _decomposeOutline(RleWorker& rw) _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0])); continue; } - _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(outline->pts[first])); + _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), start); goto close; } } @@ -665,6 +669,7 @@ static bool _genRle(RleWorker& rw) } + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -792,4 +797,13 @@ error: return nullptr; } + +SwRleData* rleStrokeRender(const SwShape& sdata) +{ + auto stroke = sdata.stroke; + assert(stroke); + + return nullptr; +} + #endif /* _TVG_SW_RLE_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d7229dce..f1ab06e0 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -23,13 +23,7 @@ /* Internal Class Implementation */ /************************************************************************/ -static inline SwPoint TO_SWPOINT(const Point* pt) -{ - return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; -} - - -static void _growOutlineContour(SwOutline& outline, size_t n) +static void _growOutlineContour(SwOutline& outline, uint32_t n) { if (n == 0) { free(outline.cntrs); @@ -42,12 +36,12 @@ static void _growOutlineContour(SwOutline& outline, size_t n) //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;; outline.reservedCntrsCnt = n; - outline.cntrs = static_cast(realloc(outline.cntrs, n * sizeof(size_t))); + outline.cntrs = static_cast(realloc(outline.cntrs, n * sizeof(uint32_t))); assert(outline.cntrs); } -static void _growOutlinePoint(SwOutline& outline, size_t n) +static void _growOutlinePoint(SwOutline& outline, uint32_t n) { if (n == 0) { free(outline.pts); @@ -132,9 +126,9 @@ static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* } -static bool _outlineClose(SwOutline& outline) +static void _outlineClose(SwOutline& outline) { - size_t i = 0; + uint32_t i = 0; if (outline.cntrsCnt > 0) { i = outline.cntrs[outline.cntrsCnt - 1] + 1; @@ -143,7 +137,10 @@ static bool _outlineClose(SwOutline& outline) } //Make sure there is at least one point in the current path - if (outline.ptsCnt == i) return false; + if (outline.ptsCnt == i) { + outline.opened = true; + return; + } //Close the path _growOutlinePoint(outline, 1); @@ -152,7 +149,7 @@ static bool _outlineClose(SwOutline& outline) outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; - return true; + outline.opened = false; } @@ -183,7 +180,7 @@ static bool _updateBBox(SwShape& sdata) ++pt; - for(size_t i = 1; i < outline->ptsCnt; ++i, ++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; @@ -201,16 +198,31 @@ static bool _updateBBox(SwShape& sdata) } -void _deleteRle(SwShape& sdata) +static bool _checkValid(SwShape& sdata, const SwSize& clip) { - if (sdata.rle) { - if (sdata.rle->spans) free(sdata.rle->spans); - free(sdata.rle); - } + assert(sdata.outline); + + if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) return false; + + //Check boundary + if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) || + (sdata.bbox.min.x + sdata.bbox.max.x < 0) || + (sdata.bbox.min.y + sdata.bbox.max.y < 0)) return false; + + return true; +} + + +static void _deleteRle(SwShape& sdata) +{ + if (!sdata.rle) return; + if (sdata.rle->spans) free(sdata.rle->spans); + free(sdata.rle); sdata.rle = nullptr; } + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -220,7 +232,7 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans auto outline = sdata.outline; assert(outline); - for(size_t i = 0; i < outline->ptsCnt; ++i) { + for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13; @@ -233,13 +245,8 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) { - if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) goto end; if (!_updateBBox(sdata)) goto end; - - //Check boundary - if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) || - (sdata.bbox.min.x + sdata.bbox.max.x < 0) || - (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end; + if (!_checkValid(sdata, clip)) goto end; sdata.rle = rleRender(sdata, clip); @@ -251,14 +258,13 @@ end: void shapeDelOutline(SwShape& sdata) { - if (!sdata.outline) return; + auto outline = sdata.outline; + if (!outline) return; - SwOutline* outline = sdata.outline; if (outline->cntrs) free(outline->cntrs); if (outline->pts) free(outline->pts); if (outline->types) free(outline->types); free(outline); - sdata.outline = nullptr; } @@ -286,7 +292,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) auto outlinePtsCnt = 0; auto outlineCntrsCnt = 0; - for (size_t i = 0; i < cmdCnt; ++i) { + for (uint32_t i = 0; i < cmdCnt; ++i) { switch(*(cmds + i)) { case PathCommand::Close: { ++outlinePtsCnt; @@ -311,14 +317,9 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) ++outlinePtsCnt; //for close ++outlineCntrsCnt; //for end - SwOutline* outline = sdata.outline; - - if (!outline) { - outline = static_cast(calloc(1, sizeof(SwOutline))); - assert(outline); - } else { - cout << "Outline was already allocated? How?" << endl; - } + auto outline = sdata.outline; + if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); + assert(outline); _growOutlinePoint(*outline, outlinePtsCnt); _growOutlineContour(*outline, outlineCntrsCnt); @@ -360,4 +361,38 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) } +void shapeFree(SwShape* sdata) +{ + assert(sdata); + + shapeDelOutline(*sdata); + _deleteRle(*sdata); + strokeFree(sdata->stroke); + free(sdata); +} + + +void shapeResetStroke(const Shape& shape, SwShape& sdata) +{ + if (!sdata.stroke) sdata.stroke = static_cast(calloc(1, sizeof(SwStroke))); + auto stroke = sdata.stroke; + assert(stroke); + + strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin()); +} + + +bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip) +{ + if (!sdata.outline) { + if (!shapeGenOutline(shape, sdata)) return false; + } + + if (!_checkValid(sdata, clip)) return false; + + if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false; + + return true; +} + #endif /* _TVG_SW_SHAPE_H_ */ diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp new file mode 100644 index 00000000..2f810a1c --- /dev/null +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -0,0 +1,658 @@ +/* + * 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_SW_STROKER_H_ +#define _TVG_SW_STROKER_H_ + +#include "tvgSwCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ +constexpr auto CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 +constexpr static SwFixed ANGLE_PI = (180L << 16); +constexpr static SwFixed ANGLE_2PI = (ANGLE_PI << 1); +constexpr static SwFixed ANGLE_PI2 = (ANGLE_PI >> 1); +constexpr static SwFixed ANGLE_PI4 = (ANGLE_PI >> 2); + +//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees +constexpr static auto ATAN_MAX = 23; +constexpr static SwFixed ATAN_TBL[] = { + 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, + 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L}; + + +static inline SwCoord SATURATE(const SwCoord x) +{ + return (x >> (sizeof(long) * 8 - 1)); +} + + +static inline SwFixed SIDE_TO_ROTATE(int32_t s) +{ + return (ANGLE_PI2 - (s) * ANGLE_PI); +} + + +static int64_t _multiply(int64_t a, int64_t b) +{ + int32_t s = 1; + + //move sign + if (a < 0) { + a = -a; + s = -s; + } + //move sign + if (b < 0) { + b = -b; + s = -s; + } + int64_t c = (a * b + 0x8000L ) >> 16; + return (s > 0) ? c : -c; +} + + +static int64_t _divide(int64_t a, int64_t b) +{ + int32_t s = 1; + + //move sign + if (a < 0) { + a = -a; + s = -s; + } + //move sign + if (b < 0) { + b = -b; + s = -s; + } + int64_t q = b > 0 ? ((a << 16) + (b >> 1)) / b : 0x7FFFFFFFL; + return (s < 0 ? -q : q); +} + + +static SwFixed _angleDiff(SwFixed angle1, SwFixed angle2) +{ + auto delta = angle2 - angle1; + + delta %= ANGLE_2PI; + if (delta < 0) delta += ANGLE_2PI; + if (delta > ANGLE_PI) delta -= ANGLE_2PI; + + return delta; +} + + +static void _trigDownscale(SwPoint& pt) +{ + //multiply a give value by the CORDIC shrink factor + + auto s = pt; + + //abs + if (pt.x < 0) pt.x = -pt.x; + if (pt.y < 0) pt.y = -pt.y; + + int64_t vx = (pt.x * static_cast(CORDIC_FACTOR)) + 0x100000000UL; + int64_t vy = (pt.y * static_cast(CORDIC_FACTOR)) + 0x100000000UL; + + pt.x = static_cast(vx >> 32); + pt.y = static_cast(vy >> 32); + + if (s.x < 0) pt.x = -pt.x; + if (s.y < 0) pt.y = -pt.y; +} + + +static int32_t _trigPrenorm(SwPoint& pt) +{ + /* the highest bit in overflow-safe vector components + MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ + constexpr auto TRIG_SAFE_MSB = 29; + + auto v = pt; + + //High order bit(MSB) + //clz: count leading zero’s + auto shift = 31 - __builtin_clz(abs(v.x) | abs(v.y)); + + if (shift <= TRIG_SAFE_MSB) { + shift = TRIG_SAFE_MSB - shift; + pt.x = static_cast((unsigned long)v.x << shift); + pt.y = static_cast((unsigned long)v.y << shift); + } else { + shift -= TRIG_SAFE_MSB; + pt.x = v.x >> shift; + pt.y = v.y >> shift; + shift = -shift; + } + return shift; +} + + +static void _trigPseudoRotate(SwPoint& pt, SwFixed theta) +{ + auto v = pt; + + //Rotate inside [-PI/4, PI/4] sector + while (theta < -ANGLE_PI4) { + auto temp = v.y; + v.y = -v.x; + v.x = temp; + theta += ANGLE_PI2; + } + + while (theta > ANGLE_PI4) { + auto temp = -v.y; + v.y = v.x; + v.x = temp; + theta -= ANGLE_PI2; + } + + auto atan = ATAN_TBL; + uint32_t i; + SwFixed j; + + for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { + if (theta < 0) { + auto temp = v.x + ((v.y + j) >> i); + v.y = v.y - ((v.x + j) >> i); + v.x = temp; + theta += *atan++; + }else { + auto temp = v.x - ((v.y + j) >> i); + v.y = v.y + ((v.x + j) >> i); + v.x = temp; + theta -= *atan++; + } + } + + pt = v; +} + + +static void _rotate(SwPoint& pt, SwFixed angle) +{ + if (angle == 0 || (pt.x == 0 && pt.y == 0)) return; + + auto v = pt; + auto shift = _trigPrenorm(v); + _trigPseudoRotate(v, angle); + _trigDownscale(v); + + if (shift > 0) { + auto half = static_cast(1L << (shift - 1)); + v.x = (v.x + half + SATURATE(v.x)) >> shift; + v.y = (v.y + half + SATURATE(v.y)) >> shift; + } else { + shift = -shift; + v.x = static_cast((unsigned long)v.x << shift); + v.y = static_cast((unsigned long)v.y << shift); + } +} + + +static SwFixed _tan(SwFixed angle) +{ + SwPoint v = {CORDIC_FACTOR >> 8, 0}; + _rotate(v, angle); + return _divide(v.y, v.x); +} + + +static SwFixed _cos(SwFixed angle) +{ + SwPoint v = {CORDIC_FACTOR >> 8, 0}; + _rotate(v, angle); + return (v.x + 0x80L) >> 8; +} + + +static void _lineTo(SwStroke& stroke, const SwPoint& to) +{ + +} + + +static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) +{ + +} + + +static void _arcTo(SwStroke& stroke, int32_t side) +{ + +} + + +static void _growBorder(SwStrokeBorder* border, uint32_t newPts) +{ + auto maxOld = border->maxPts; + auto maxNew = border->ptsCnt + newPts; + + if (maxNew <= maxOld) return; + + auto maxCur = maxOld; + + while (maxCur < maxNew) + maxCur += (maxCur >> 1) + 16; + + border->pts = static_cast(realloc(border->pts, maxCur * sizeof(SwPoint))); + assert(border->pts); + + border->tags = static_cast(realloc(border->tags, maxCur * sizeof(uint8_t))); + assert(border->tags); + + border->maxPts = maxCur; + + printf("realloc border!!! (%u => %u)\n", maxOld, maxCur); +} + + + +static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) +{ + constexpr SwPoint EPSILON = 2; + + assert(border && border->start >= 0); + + if (border->movable) { + //move last point + border->pts[border->ptsCnt - 1] = to; + } else { + //don't add zero-length line_to + auto diff = border->pts[border->ptsCnt - 1] - to; + if (border->ptsCnt > 0 && abs(diff.x) < EPSILON && abs(diff.y) < EPSILON) return; + + _growBorder(border, 1); + border->pts[border->ptsCnt] = to; + border->tags[border->ptsCnt] = SW_STROKE_TAG_ON; + border->ptsCnt += 1; + } + + border->movable = movable; +} + + +static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) +{ + if (stroke.cap == StrokeCap::Square) { + auto rotate = SIDE_TO_ROTATE(side); + auto border = stroke.borders + side; + + SwPoint delta = {stroke.width, 0}; + _rotate(delta, angle); + + SwPoint delta2 = {stroke.width, 0}; + _rotate(delta2, angle + rotate); + + delta += stroke.center + delta2; + + _borderLineTo(border, delta, false); + + delta = {stroke.width, 0}; + _rotate(delta, angle); + + delta2 = {stroke.width, 0}; + _rotate(delta2, angle - rotate); + + delta += delta2 + stroke.center; + + _borderLineTo(border, delta, false); + + } else if (stroke.cap == StrokeCap::Round) { + + stroke.angleIn = angle; + stroke.angleOut = angle + ANGLE_PI; + _arcTo(stroke, side); + return; + + } else { //Butt + auto rotate = SIDE_TO_ROTATE(side); + auto border = stroke.borders + side; + + SwPoint delta = {stroke.width, 0}; + _rotate(delta, angle + rotate); + + delta += stroke.center; + + _borderLineTo(border, delta, false); + + delta = {stroke.width, 0}; + _rotate(delta, angle - rotate); + + delta += stroke.center; + + _borderLineTo(border, delta, false); + } +} + + +static void _addReverseLeft(SwStroke& stroke, bool opened) +{ + auto right = stroke.borders + 0; + auto left = stroke.borders + 1; + assert(left->start >= 0); + + auto newPts = left->ptsCnt - left->start; + + if (newPts <= 0) return; + + _growBorder(right, newPts); + + auto dstPt = right->pts + right->ptsCnt; + auto dstTag = right->tags + right->ptsCnt; + auto srcPt = left->pts + left->ptsCnt - 1; + auto srcTag = left->tags + left->ptsCnt - 1; + + while (srcPt >= left->pts + left->start) { + *dstPt = *srcPt; + *dstTag = *srcTag; + + if (opened) { + dstTag[0] &= ~(SW_STROKE_TAG_BEGIN | SW_STROKE_TAG_END); + } else { + //switch begin/end tags if necessary + auto ttag = dstTag[0] & (SW_STROKE_TAG_BEGIN | SW_STROKE_TAG_END); + if (ttag == (SW_STROKE_TAG_BEGIN || SW_STROKE_TAG_END)) { + dstTag[0] ^= (SW_STROKE_TAG_BEGIN || SW_STROKE_TAG_END); + } + } + + --srcPt; + --srcTag; + --dstPt; + --dstTag; + } + + left->ptsCnt = left->start; + right->ptsCnt += newPts; + right->movable = false; + left->movable = false; +} + + +static void _closeBorder(SwStrokeBorder* border, bool reverse) +{ + assert(border && border->start >= 0); + + uint32_t start = border->start; + uint32_t count = border->ptsCnt; + + //Don't record empty paths! + if (count <= start + 1U) { + border->ptsCnt = start; + } else { + /* Copy the last point to the start of this sub-path, + since it contains the adjusted starting coordinates */ + border->ptsCnt = --count; + border->pts[start] = border->pts[count]; + + if (reverse) { + //reverse the points + auto pt1 = border->pts + start + 1; + auto pt2 = border->pts + count - 1; + + for (; pt1 < pt2; pt1++, pt2--) { + auto tmp = *pt1; + *pt1 = *pt2; + *pt2 = tmp; + } + + //reverse the tags + auto tag1 = border->tags + start + 1; + auto tag2 = border->tags + count - 1; + + for (; tag1 < tag2; tag1++, tag2++) { + auto tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + } + } + + border->tags[start] |= SW_STROKE_TAG_BEGIN; + border->tags[count - 1] |= SW_STROKE_TAG_END; + } + + border->start = -1; + border->movable = false; +} + + +static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) +{ + auto border = stroke.borders + side; + auto theta = _angleDiff(stroke.angleIn, stroke.angleOut) / 2; + SwPoint delta; + bool intersect; + + /* Only intersect borders if between two line_to's and both + lines are long enough (line length is zero fur curves). */ + if (!border->movable || lineLength == 0) { + intersect = false; + } else { + //compute minimum required length of lines + SwFixed minLength = abs(_multiply(stroke.width, _tan(theta))); + if (stroke.lineLength >= minLength && lineLength >= minLength) intersect = true; + } + + auto rotate = SIDE_TO_ROTATE(side); + + if (!intersect) { + delta = {stroke.width, 0}; + _rotate(delta, stroke.angleOut + rotate); + delta += stroke.center; + border->movable = false; + } else { + //compute median angle + delta = {_divide(stroke.width, _cos(theta)), 0}; + _rotate(delta, stroke.angleIn + theta + rotate); + delta += stroke.center; + } + + _borderLineTo(border, delta, false); +} + + +static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) +{ + cout << "stroke opened? = " << opened << endl; + + /* We cannot process the first point because there is not enought + information regarding its corner/cap. Later, it will be processed + in the _strokeEndSubPath() */ + + stroke.firstPt = true; + stroke.center = to; + stroke.subPathOpen = opened; + + /* Determine if we need to check whether the border radius is greater + than the radius of curvature of a curve, to handle this case specially. + This is only required if bevel joins or butt caps may be created because + round & miter joins and round & square caps cover the nagative sector + created with wide strokes. */ + if ((stroke.join != StrokeJoin::Round) || (stroke.subPathOpen && stroke.cap == StrokeCap::Butt)) + stroke.handleWideStrokes = true; + else + stroke.handleWideStrokes = false; + + stroke.subPathStart = to; + stroke.angleIn = 0; +} + + +static void _endSubPath(SwStroke& stroke) +{ + if (stroke.subPathOpen) { + auto right = stroke.borders; + assert(right); + + /* all right, this is an opened path, we need to add a cap between + right & left, add the reverse of left, then add a final cap + between left & right */ + _addCap(stroke, stroke.angleIn, 0); + + //add reversed points from 'left' to 'right' + _addReverseLeft(stroke, true); + + //now add the final cap + stroke.center = stroke.subPathStart; + _addCap(stroke, stroke.subPathAngle + ANGLE_PI, 0); + + /* now end the right subpath accordingly. The left one is rewind + and deosn't need further processing */ + _closeBorder(right, false); + } else { + + //close the path if needed + if (stroke.center != stroke.subPathStart) + _lineTo(stroke, stroke.subPathStart); + + //process the corner + stroke.angleOut = stroke.subPathAngle; + auto turn = _angleDiff(stroke.angleIn, stroke.angleOut); + + //No specific corner processing is required if the turn is 0 + if (turn != 0) { + + //when we turn to the right, the inside is 0 + auto inside = 0; + + //otherwise, the inside is 1 + if (turn < 0) inside = 1; + + _inside(stroke, inside, stroke.subPathLineLength); //inside + _inside(stroke, 1 - inside, stroke.subPathLineLength); //outside + } + + _closeBorder(stroke.borders + 0, false); + _closeBorder(stroke.borders + 1, true); + } +} + + +static void _deleteRle(SwStroke& stroke) +{ + if (!stroke.rle) return; + if (stroke.rle->spans) free(stroke.rle->spans); + free(stroke.rle); + stroke.rle = nullptr; +} + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +void strokeFree(SwStroke* stroke) +{ + if (!stroke) return; + _deleteRle(*stroke); + free(stroke); +} + + +void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) +{ + _deleteRle(stroke); + +#if 0 + miterLimit = 4 * (1 >> 16); + + /* ensure miter limit has sensible value */ + if ( stroker->miter_limit < 0x10000 ) + stroker->miter_limit = 0x10000; +#endif + + stroke.width = TO_SWCOORD(width * 0.5f); + stroke.cap = cap; + + //Save line join: it can be temporarily changed when stroking curves... + stroke.joinSaved = stroke.join = join; + + stroke.borders[0].ptsCnt = 0; + stroke.borders[0].start = -1; + stroke.borders[0].valid = false; + + stroke.borders[1].ptsCnt = 0; + stroke.borders[1].start = -1; + stroke.borders[1].valid = false; +} + +bool strokeParseOutline(SwStroke& stroke, SwOutline& outline) +{ + uint32_t first = 0; + + for (uint32_t i = 0; i < outline.cntrsCnt; ++i) { + auto last = outline.cntrs[i]; //index of last point in contour + auto limit = outline.pts + last; + assert(limit); + + //Skip empty points + if (last <= first) { + first = last + 1; + continue; + } + + auto start = outline.pts[first]; + + auto pt = outline.pts + first; + assert(pt); + auto types = outline.types + first; + assert(types); + + auto type = types[0]; + + //A contour cannot start with a cubic control point + if (type == SW_CURVE_TYPE_CUBIC) return false; + + _beginSubPath(stroke, start, outline.opened); + + while (pt < limit) { + assert(++pt); + assert(++types); + + //emit a signel line_to + if (types[0] == SW_CURVE_TYPE_POINT) { + _lineTo(stroke, *pt); + //types cubic + } else { + if (pt + 1 > limit || types[1] != SW_CURVE_TYPE_CUBIC) return false; + + pt += 2; + types += 2; + + if (pt <= limit) { + _cubicTo(stroke, pt[-2], pt[-1], pt[0]); + continue; + } + _cubicTo(stroke, pt[-2], pt[-1], start); + goto close; + } + } + + close: + if (!stroke.firstPt) _endSubPath(stroke); + first = last + 1; + } + return true; +} + + +#endif /* _TVG_SW_STROKER_H_ */ diff --git a/test/makefile b/test/makefile index 50710e08..174b93f2 100644 --- a/test/makefile +++ b/test/makefile @@ -1,12 +1,13 @@ 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 testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` +# 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 testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testStroke.cpp b/test/testStroke.cpp index e2ae1bc2..1f865d68 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -7,33 +8,72 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -int main(int argc, char **argv) + +void tvgtest() { //Initialize TizenVG Engine tvg::Engine::init(); - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + //Initialize TizenVG Engine + tvg::Engine::init(); - //Prepare a Shape + //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->rect(0, 0, 400, 400, 0.1); //x, y, w, h, cornerRadius - shape1->fill(0, 255, 0, 255); + 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 //Stroke Style - shape1->strokeColor(0, 0, 0, 255); //r, g, b, a - shape1->strokeWidth(1); //1px - shape1->strokeJoin(tvg::StrokeJoin::Miter); - shape1->strokeLineCap(tvg::StrokeLineCap::Butt); + shape1->stroke(255, 255, 255, 255); //color: r, g, b, a + shape1->stroke(5); //width: 5px +// shape1->strokeJoin(tvg::StrokeJoin::Miter); +// shape1->strokeLineCap(tvg::StrokeLineCap::Butt); - uint32_t dash[] = {3, 1, 5, 1}; //dash pattern - shape1->strokeDash(dash, 4); +// uint32_t dash[] = {3, 1, 5, 1}; //dash pattern +// shape1->strokeDash(dash, 4); - //Draw the Shape onto the Canvas canvas->push(move(shape1)); + canvas->draw(); canvas->sync(); //Terminate TizenVG Engine tvg::Engine::term(); } + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From b4cf6660b749dccb686ac4c7f82fa10f71d041a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 28 May 2020 20:37:25 +0900 Subject: [PATCH 064/244] test: recover sample build. introduced by mistake. Change-Id: I8fd88054da1e86cace02931791a646a182ab6721 --- test/makefile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/makefile b/test/makefile index 174b93f2..3f314e8a 100644 --- a/test/makefile +++ b/test/makefile @@ -1,13 +1,13 @@ 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 testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + 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 testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` From 674483845305bc2fdd862cdd7e188220f0e4d1d7 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 29 May 2020 13:33:46 +0900 Subject: [PATCH 065/244] sw_engine: Fix build error (no match type) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../src/lib/sw_engine/tvgSwStroke.cpp:282:72: error: no match for ‘operator<’ (operand types are ‘long int’ and ‘const SwPoint’) if (border->ptsCnt > 0 && abs(diff.x) < EPSILON && abs(diff.y) < EPSILON) return; Change-Id: I426f8980ba718e3dc908dc32a62fb897b5b5fbbf --- src/lib/sw_engine/tvgSwStroke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 2f810a1c..acaf2c61 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -269,7 +269,7 @@ static void _growBorder(SwStrokeBorder* border, uint32_t newPts) static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) { - constexpr SwPoint EPSILON = 2; + constexpr SwCoord EPSILON = 2; assert(border && border->start >= 0); From 41dbd9774a73d3c04de1f3c86a4444763bb54b1b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 29 May 2020 11:47:55 +0900 Subject: [PATCH 066/244] sw_engine: implement stroke cubicto, arcto, lineto Change-Id: I59e95b1031ebfaf54e966cab334e045613ca3830 --- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwCommon.h | 39 +- src/lib/sw_engine/tvgSwMath.cpp | 407 +++++++++++++++ src/lib/sw_engine/tvgSwRle.cpp | 30 +- src/lib/sw_engine/tvgSwStroke.cpp | 803 ++++++++++++++++++------------ 5 files changed, 931 insertions(+), 349 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwMath.cpp diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index b6664719..f4998f4b 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,5 +1,6 @@ source_file = [ 'tvgSwCommon.h', + 'tvgSwMath.cpp', 'tvgSwRenderer.h', 'tvgSwRaster.cpp', 'tvgSwRenderer.cpp', diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 66d6fe02..b942ca18 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -27,10 +27,6 @@ constexpr auto SW_CURVE_TYPE_CUBIC = 1; constexpr auto SW_OUTLINE_FILL_WINDING = 0; constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; -constexpr auto SW_STROKE_TAG_ON = 1; -constexpr auto SW_STROKE_TAG_BEGIN = 4; -constexpr auto SW_STROKE_TAG_END = 8; - using SwCoord = signed long; using SwFixed = signed long long; @@ -59,6 +55,20 @@ struct SwPoint bool operator!=(const SwPoint& rhs) const { return (x != rhs.x || y != rhs.y); } + + bool zero() + { + if (x == 0 && y == 0) return true; + else return false; + } + + bool small() + { + //2 is epsilon... + if (abs(x) < 2 && abs(y) < 2) return true; + else return false; + } + }; struct SwSize @@ -141,6 +151,13 @@ struct SwShape SwBBox bbox; }; + +constexpr static SwFixed ANGLE_PI = (180L << 16); +constexpr static SwFixed ANGLE_2PI = (ANGLE_PI << 1); +constexpr static SwFixed ANGLE_PI2 = (ANGLE_PI >> 1); +constexpr static SwFixed ANGLE_PI4 = (ANGLE_PI >> 2); + + static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; @@ -153,6 +170,20 @@ static inline SwCoord TO_SWCOORD(float val) } +int64_t mathMultiply(int64_t a, int64_t b); +int64_t mathDivide(int64_t a, int64_t b); +int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); +void mathRotate(SwPoint& pt, SwFixed angle); +SwFixed mathTan(SwFixed angle); +SwFixed mathAtan(const SwPoint& pt); +SwFixed mathCos(SwFixed angle); +SwFixed mathSin(SwFixed angle); +void mathSplitCubic(SwPoint* base); +SwFixed mathDiff(SwFixed angle1, SwFixed angle2); +SwFixed mathLength(SwPoint& pt); +bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); +SwFixed mathMean(SwFixed angle1, SwFixed angle2); + void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp new file mode 100644 index 00000000..919fe1ed --- /dev/null +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -0,0 +1,407 @@ +/* + * 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_SW_MATH_H_ +#define _TVG_SW_MATH_H_ + +#include "tvgSwCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +constexpr auto CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 + +//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees +constexpr static auto ATAN_MAX = 23; +constexpr static SwFixed ATAN_TBL[] = { + 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, + 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L}; + +static inline SwCoord SATURATE(const SwCoord x) +{ + return (x >> (sizeof(SwCoord) * 8 - 1)); +} + + +static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n) +{ + return (((x) + ((n)/2)) & ~((n)-1)); +} + + +static SwCoord _downscale(SwCoord x) +{ + //multiply a give value by the CORDIC shrink factor + + abs(x); + int64_t t = (x * static_cast(CORDIC_FACTOR)) + 0x100000000UL; + x = static_cast(t >> 32); + if (x < 0) x = -x; + return x; +} + + +static int32_t _normalize(SwPoint& pt) +{ + /* the highest bit in overflow-safe vector components + MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ + constexpr auto SAFE_MSB = 29; + + auto v = pt; + + //High order bit(MSB) + //clz: count leading zero’s + auto shift = 31 - __builtin_clz(abs(v.x) | abs(v.y)); + + if (shift <= SAFE_MSB) { + shift = SAFE_MSB - shift; + pt.x = static_cast((unsigned long)v.x << shift); + pt.y = static_cast((unsigned long)v.y << shift); + } else { + shift -= SAFE_MSB; + pt.x = v.x >> shift; + pt.y = v.y >> shift; + shift = -shift; + } + return shift; +} + + +static void _polarize(SwPoint& pt) +{ + auto v = pt; + SwFixed theta; + + //Get the vector into [-PI/4, PI/4] sector + if (v.y > v.x) { + if (v.y > -v.x) { + auto tmp = v.y; + v.y = -v.x; + v.x = tmp; + theta = ANGLE_PI2; + } else { + theta = v.y > 0 ? ANGLE_PI : -ANGLE_PI; + v.x = -v.x; + v.y = -v.y; + } + } else { + if (v.y < -v.x) { + theta = -ANGLE_PI2; + auto tmp = -v.y; + v.y = v.x; + v.x = tmp; + } else { + theta = 0; + } + } + + auto atan = ATAN_TBL; + uint32_t i; + SwFixed j; + + //Pseudorotations. with right shifts + for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { + if (v.y > 0) { + auto tmp = v.x + ((v.y + j) >> i); + v.y = v.y - ((v.x + j) >> i); + v.x = tmp; + theta += *atan++; + } else { + auto tmp = v.x - ((v.y + j) >> i); + v.y = v.y + ((v.x + j) >> i); + v.x = tmp; + theta -= *atan++; + } + } + + //round theta + if (theta >= 0) theta = PAD_ROUND(theta, 32); + else theta = -PAD_ROUND(-theta, 32); + + pt.x = v.x; + pt.y = theta; +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +SwFixed mathMean(SwFixed angle1, SwFixed angle2) +{ + return angle1 + mathDiff(angle1, angle2) / 2; +} + + +bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut) +{ + auto d1 = base[2] - base[3]; + auto d2 = base[1] - base[2]; + auto d3 = base[0] - base[1]; + + if (d1.small()) { + if (d2.small()) { + if (d3.small()) { + //basically a point. + //do nothing to retain original direction + } else { + angleIn = angleMid = angleOut = mathAtan(d3); + } + } else { + if (d3.small()) { + angleIn = angleMid = angleOut = mathAtan(d2); + } else { + angleIn = angleMid = mathAtan(d2); + angleOut = mathAtan(d3); + } + } + } else { + if (d2.small()) { + if (d3.small()) { + angleIn = angleMid = angleOut = mathAtan(d1); + } else { + angleIn = mathAtan(d1); + angleOut = mathAtan(d3); + angleMid = mathMean(angleIn, angleOut); + } + } else { + if (d3.small()) { + angleIn = mathAtan(d1); + angleMid = angleOut = mathAtan(d2); + } else { + angleIn = mathAtan(d1); + angleMid = mathAtan(d2); + angleOut = mathAtan(d3); + } + } + } + + auto theta1 = abs(mathDiff(angleIn, angleMid)); + auto theta2 = abs(mathDiff(angleMid, angleOut)); + + if ((theta1 < (ANGLE_PI / 8)) && (theta2 < (ANGLE_PI / 8))) return true; + else return false; +} + + +int64_t mathMultiply(int64_t a, int64_t b) +{ + int32_t s = 1; + + //move sign + if (a < 0) { + a = -a; + s = -s; + } + if (b < 0) { + b = -b; + s = -s; + } + int64_t c = (a * b + 0x8000L ) >> 16; + return (s > 0) ? c : -c; +} + + +int64_t mathDivide(int64_t a, int64_t b) +{ + int32_t s = 1; + + //move sign + if (a < 0) { + a = -a; + s = -s; + } + if (b < 0) { + b = -b; + s = -s; + } + int64_t q = b > 0 ? ((a << 16) + (b >> 1)) / b : 0x7FFFFFFFL; + return (s < 0 ? -q : q); +} + + +int64_t mathMulDiv(int64_t a, int64_t b, int64_t c) +{ + int32_t s = 1; + + //move sign + if (a < 0) { + a = -a; + s = -s; + } + if (b < 0) { + b = -b; + s = -s; + } + if (c < 0) { + c = -c; + s = -s; + } + int64_t d = c > 0 ? (a * b + (c >> 1)) / c : 0x7FFFFFFFL; + + return (s > 0 ? -d : d); +} + + +void mathRotate(SwPoint& pt, SwFixed angle) +{ + if (angle == 0 || (pt.x == 0 && pt.y == 0)) return; + + auto v = pt; + auto shift = _normalize(v); + auto theta = angle; + + //Rotate inside [-PI/4, PI/4] sector + while (theta < -ANGLE_PI4) { + auto tmp = v.y; + v.y = -v.x; + v.x = tmp; + theta += ANGLE_PI2; + } + + while (theta > ANGLE_PI4) { + auto tmp = -v.y; + v.y = v.x; + v.x = tmp; + theta -= ANGLE_PI2; + } + + auto atan = ATAN_TBL; + uint32_t i; + SwFixed j; + + for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { + if (theta < 0) { + auto tmp = v.x + ((v.y + j) >> i); + v.y = v.y - ((v.x + j) >> i); + v.x = tmp; + theta += *atan++; + }else { + auto tmp = v.x - ((v.y + j) >> i); + v.y = v.y + ((v.x + j) >> i); + v.x = tmp; + theta -= *atan++; + } + } + + v.x = _downscale(v.x); + v.y = _downscale(v.y); + + if (shift > 0) { + auto half = static_cast(1L << (shift - 1)); + v.x = (v.x + half + SATURATE(v.x)) >> shift; + v.y = (v.y + half + SATURATE(v.y)) >> shift; + } else { + shift = -shift; + v.x = static_cast((unsigned long)v.x << shift); + v.y = static_cast((unsigned long)v.y << shift); + } +} + +SwFixed mathTan(SwFixed angle) +{ + SwPoint v = {CORDIC_FACTOR >> 8, 0}; + mathRotate(v, angle); + return mathDivide(v.y, v.x); +} + + +SwFixed mathAtan(const SwPoint& pt) +{ + if (pt.x == 0 && pt.y == 0) return 0; + + auto v = pt; + _normalize(v); + _polarize(v); + + return v.y; +} + + +SwFixed mathSin(SwFixed angle) +{ + return mathCos(ANGLE_PI2 - angle); +} + + +SwFixed mathCos(SwFixed angle) +{ + SwPoint v = {CORDIC_FACTOR >> 8, 0}; + mathRotate(v, angle); + return (v.x + 0x80L) >> 8; +} + + +SwFixed mathLength(SwPoint& pt) +{ + auto v = pt; + + //trivial case + if (v.x == 0) return abs(v.y); + if (v.y == 0) return abs(v.x); + + //general case + auto shift = _normalize(v); + _polarize(v); + v.x = _downscale(v.x); + + if (shift > 0) return (v.x + (1 << (shift -1))) >> shift; + return static_cast((uint32_t)v.x << -shift); +} + + +void mathSplitCubic(SwPoint* base) +{ + assert(base); + + SwCoord a, b, c, d; + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = (base[0].x + c) / 2; + base[5].x = b = (base[3].x + d) / 2; + c = (c + d) / 2; + base[2].x = a = (a + c) / 2; + base[4].x = b = (b + c) / 2; + base[3].x = (a + b) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = (base[0].y + c) / 2; + base[5].y = b = (base[3].y + d) / 2; + c = (c + d) / 2; + base[2].y = a = (a + c) / 2; + base[4].y = b = (b + c) / 2; + base[3].y = (a + b) / 2; +} + + +SwFixed mathDiff(SwFixed angle1, SwFixed angle2) +{ + auto delta = angle2 - angle1; + + delta %= ANGLE_2PI; + if (delta < 0) delta += ANGLE_2PI; + if (delta > ANGLE_PI) delta -= ANGLE_2PI; + + return delta; +} +#endif /* _TVG_SW_MATH_H_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 3a4b8eda..7bbc3265 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -490,34 +490,6 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) } -static void _splitCubic(SwPoint* base) -{ - assert(base); - - SwCoord a, b, c, d; - - base[6].x = base[3].x; - c = base[1].x; - d = base[2].x; - base[1].x = a = (base[0].x + c) / 2; - base[5].x = b = (base[3].x + d) / 2; - c = (c + d) / 2; - base[2].x = a = (a + c) / 2; - base[4].x = b = (b + c) / 2; - base[3].x = (a + b) / 2; - - base[6].y = base[3].y; - c = base[1].y; - d = base[2].y; - base[1].y = a = (base[0].y + c) / 2; - base[5].y = b = (base[3].y + d) / 2; - c = (c + d) / 2; - base[2].y = a = (a + c) / 2; - base[4].y = b = (b + c) / 2; - base[3].y = (a + b) / 2; -} - - static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) { auto arc = rw.bezStack; @@ -579,7 +551,7 @@ static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, goto draw; } split: - _splitCubic(arc); + mathSplitCubic(arc); arc += 3; continue; diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index acaf2c61..a0a25738 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -23,225 +23,17 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -constexpr auto CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 -constexpr static SwFixed ANGLE_PI = (180L << 16); -constexpr static SwFixed ANGLE_2PI = (ANGLE_PI << 1); -constexpr static SwFixed ANGLE_PI2 = (ANGLE_PI >> 1); -constexpr static SwFixed ANGLE_PI4 = (ANGLE_PI >> 2); +static constexpr auto SW_STROKE_TAG_ON = 1; +static constexpr auto SW_STROKE_TAG_CUBIC = 2; +static constexpr auto SW_STROKE_TAG_BEGIN = 4; +static constexpr auto SW_STROKE_TAG_END = 8; -//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees -constexpr static auto ATAN_MAX = 23; -constexpr static SwFixed ATAN_TBL[] = { - 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, - 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, - 57L, 29L, 14L, 7L, 4L, 2L, 1L}; - - -static inline SwCoord SATURATE(const SwCoord x) -{ - return (x >> (sizeof(long) * 8 - 1)); -} - - -static inline SwFixed SIDE_TO_ROTATE(int32_t s) +static inline SwFixed SIDE_TO_ROTATE(const int32_t s) { return (ANGLE_PI2 - (s) * ANGLE_PI); } -static int64_t _multiply(int64_t a, int64_t b) -{ - int32_t s = 1; - - //move sign - if (a < 0) { - a = -a; - s = -s; - } - //move sign - if (b < 0) { - b = -b; - s = -s; - } - int64_t c = (a * b + 0x8000L ) >> 16; - return (s > 0) ? c : -c; -} - - -static int64_t _divide(int64_t a, int64_t b) -{ - int32_t s = 1; - - //move sign - if (a < 0) { - a = -a; - s = -s; - } - //move sign - if (b < 0) { - b = -b; - s = -s; - } - int64_t q = b > 0 ? ((a << 16) + (b >> 1)) / b : 0x7FFFFFFFL; - return (s < 0 ? -q : q); -} - - -static SwFixed _angleDiff(SwFixed angle1, SwFixed angle2) -{ - auto delta = angle2 - angle1; - - delta %= ANGLE_2PI; - if (delta < 0) delta += ANGLE_2PI; - if (delta > ANGLE_PI) delta -= ANGLE_2PI; - - return delta; -} - - -static void _trigDownscale(SwPoint& pt) -{ - //multiply a give value by the CORDIC shrink factor - - auto s = pt; - - //abs - if (pt.x < 0) pt.x = -pt.x; - if (pt.y < 0) pt.y = -pt.y; - - int64_t vx = (pt.x * static_cast(CORDIC_FACTOR)) + 0x100000000UL; - int64_t vy = (pt.y * static_cast(CORDIC_FACTOR)) + 0x100000000UL; - - pt.x = static_cast(vx >> 32); - pt.y = static_cast(vy >> 32); - - if (s.x < 0) pt.x = -pt.x; - if (s.y < 0) pt.y = -pt.y; -} - - -static int32_t _trigPrenorm(SwPoint& pt) -{ - /* the highest bit in overflow-safe vector components - MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ - constexpr auto TRIG_SAFE_MSB = 29; - - auto v = pt; - - //High order bit(MSB) - //clz: count leading zero’s - auto shift = 31 - __builtin_clz(abs(v.x) | abs(v.y)); - - if (shift <= TRIG_SAFE_MSB) { - shift = TRIG_SAFE_MSB - shift; - pt.x = static_cast((unsigned long)v.x << shift); - pt.y = static_cast((unsigned long)v.y << shift); - } else { - shift -= TRIG_SAFE_MSB; - pt.x = v.x >> shift; - pt.y = v.y >> shift; - shift = -shift; - } - return shift; -} - - -static void _trigPseudoRotate(SwPoint& pt, SwFixed theta) -{ - auto v = pt; - - //Rotate inside [-PI/4, PI/4] sector - while (theta < -ANGLE_PI4) { - auto temp = v.y; - v.y = -v.x; - v.x = temp; - theta += ANGLE_PI2; - } - - while (theta > ANGLE_PI4) { - auto temp = -v.y; - v.y = v.x; - v.x = temp; - theta -= ANGLE_PI2; - } - - auto atan = ATAN_TBL; - uint32_t i; - SwFixed j; - - for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { - if (theta < 0) { - auto temp = v.x + ((v.y + j) >> i); - v.y = v.y - ((v.x + j) >> i); - v.x = temp; - theta += *atan++; - }else { - auto temp = v.x - ((v.y + j) >> i); - v.y = v.y + ((v.x + j) >> i); - v.x = temp; - theta -= *atan++; - } - } - - pt = v; -} - - -static void _rotate(SwPoint& pt, SwFixed angle) -{ - if (angle == 0 || (pt.x == 0 && pt.y == 0)) return; - - auto v = pt; - auto shift = _trigPrenorm(v); - _trigPseudoRotate(v, angle); - _trigDownscale(v); - - if (shift > 0) { - auto half = static_cast(1L << (shift - 1)); - v.x = (v.x + half + SATURATE(v.x)) >> shift; - v.y = (v.y + half + SATURATE(v.y)) >> shift; - } else { - shift = -shift; - v.x = static_cast((unsigned long)v.x << shift); - v.y = static_cast((unsigned long)v.y << shift); - } -} - - -static SwFixed _tan(SwFixed angle) -{ - SwPoint v = {CORDIC_FACTOR >> 8, 0}; - _rotate(v, angle); - return _divide(v.y, v.x); -} - - -static SwFixed _cos(SwFixed angle) -{ - SwPoint v = {CORDIC_FACTOR >> 8, 0}; - _rotate(v, angle); - return (v.x + 0x80L) >> 8; -} - - -static void _lineTo(SwStroke& stroke, const SwPoint& to) -{ - -} - - -static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) -{ - -} - - -static void _arcTo(SwStroke& stroke, int32_t side) -{ - -} - - static void _growBorder(SwStrokeBorder* border, uint32_t newPts) { auto maxOld = border->maxPts; @@ -266,11 +58,130 @@ static void _growBorder(SwStrokeBorder* border, uint32_t newPts) } +static void _borderClose(SwStrokeBorder* border, bool reverse) +{ + assert(border && border->start >= 0); + + uint32_t start = border->start; + uint32_t count = border->ptsCnt; + + //Don't record empty paths! + if (count <= start + 1U) { + border->ptsCnt = start; + } else { + /* Copy the last point to the start of this sub-path, + since it contains the adjusted starting coordinates */ + border->ptsCnt = --count; + border->pts[start] = border->pts[count]; + + if (reverse) { + //reverse the points + auto pt1 = border->pts + start + 1; + auto pt2 = border->pts + count - 1; + + while (pt1 < pt2) { + auto tmp = *pt1; + *pt1 = *pt2; + *pt2 = tmp; + ++pt1; + --pt2; + } + + //reverse the tags + auto tag1 = border->tags + start + 1; + auto tag2 = border->tags + count - 1; + + while (tag1 < tag2) { + auto tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + ++tag1; + --tag2; + } + } + + border->tags[start] |= SW_STROKE_TAG_BEGIN; + border->tags[count - 1] |= SW_STROKE_TAG_END; + } + + border->start = -1; + border->movable = false; +} + + +static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) +{ + assert(border->start >= 0); + + _growBorder(border, 3); + + auto pt = border->pts + border->ptsCnt; + auto tag = border->tags + border->ptsCnt; + + pt[0] = ctrl1; + pt[1] = ctrl2; + pt[2] = to; + + tag[0] = SW_STROKE_TAG_CUBIC; + tag[1] = SW_STROKE_TAG_CUBIC; + tag[2] = SW_STROKE_TAG_ON; + + border->ptsCnt += 3; + border->movable = false; +} + + +static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff) +{ + constexpr auto ARC_CUBIC_ANGLE = ANGLE_PI / 2; + SwPoint a = {radius, 0}; + mathRotate(a, angleStart); + a += center; + + auto total = angleDiff; + auto angle = angleStart; + auto rotate = (angleDiff >= 0) ? ANGLE_PI2 : -ANGLE_PI2; + + while (total != 0) { + auto step = total; + if (step > ARC_CUBIC_ANGLE) step = ARC_CUBIC_ANGLE; + else if (step < -ARC_CUBIC_ANGLE) step = -ARC_CUBIC_ANGLE; + + auto next = angle + step; + auto theta = step; + if (theta < 0) theta = -theta; + + theta >>= 1; + + //compute end point + SwPoint b = {radius, 0}; + mathRotate(b, next); + b += center; + + //compute first and second control points + auto length = mathMulDiv(radius, mathSin(theta) * 4, (0x10000L + mathCos(theta)) * 3); + + SwPoint a2 = {length, 0}; + mathRotate(a2, angle + rotate); + a2 += a; + + SwPoint b2 = {length, 0}; + mathRotate(b2, next - rotate); + b2 += b; + + //add cubic arc + _borderCubicTo(border, a2, b2, b); + + //process the rest of the arc? + a = b; + total -= step; + angle = next; + } +} + static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) { - constexpr SwCoord EPSILON = 2; - assert(border && border->start >= 0); if (border->movable) { @@ -279,7 +190,7 @@ static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) } else { //don't add zero-length line_to auto diff = border->pts[border->ptsCnt - 1] - to; - if (border->ptsCnt > 0 && abs(diff.x) < EPSILON && abs(diff.y) < EPSILON) return; + if (border->ptsCnt > 0 && diff.small()) return; _growBorder(border, 1); border->pts[border->ptsCnt] = to; @@ -291,6 +202,356 @@ static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) } +static void _borderMoveTo(SwStrokeBorder* border, SwPoint& to) +{ + assert(border); + + //close current open path if any? + if (border->start >= 0) + _borderClose(border, false); + + border->start = border->ptsCnt; + border->movable = false; + + _borderLineTo(border, to, false); +} + + +static void _arcTo(SwStroke& stroke, int32_t side) +{ + auto border = stroke.borders + side; + auto rotate = SIDE_TO_ROTATE(side); + auto total = mathDiff(stroke.angleIn, stroke.angleOut); + if (total == ANGLE_PI) total = -rotate * 2; + + _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total); + border->movable = false; +} + + +static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) +{ + constexpr SwFixed MITER_LIMIT = 4 * (1 << 16); + + assert(MITER_LIMIT >= 0x10000); + + auto border = stroke.borders + side; + assert(border); + + if (stroke.join == StrokeJoin::Round) { + _arcTo(stroke, side); + } else { + //this is a mitered (pointed) or beveled (truncated) corner + auto rotate = SIDE_TO_ROTATE(side); + auto bevel = (stroke.join == StrokeJoin::Bevel) ? true : false; + SwFixed phi = 0; + SwFixed thcos = 0; + + if (!bevel) { + auto theta = mathDiff(stroke.angleIn, stroke.angleOut); + if (theta == ANGLE_PI) { + theta = rotate; + phi = stroke.angleIn; + } else { + theta /= 2; + phi = stroke.angleIn + theta + rotate; + } + + thcos = mathCos(theta); + auto sigma = mathMultiply(MITER_LIMIT, thcos); + + //is miter limit exceeded? + if (sigma < 0x10000L) bevel = true; + } + + //this is a bevel (broken angle) + if (bevel) { + SwPoint delta = {stroke.width, 0}; + mathRotate(delta, stroke.angleOut + rotate); + delta += stroke.center; + border->movable = false; + _borderLineTo(border, delta, false); + //this is a miter (intersection) + } else { + auto length = mathDivide(stroke.width, thcos); + SwPoint delta = {length, 0}; + mathRotate(delta, phi); + delta += stroke.center; + _borderLineTo(border, delta, false); + + /* Now add and end point + Only needed if not lineto (lineLength is zero for curves) */ + if (lineLength == 0) { + delta = {stroke.width, 0}; + mathRotate(delta, stroke.angleOut + rotate); + delta += stroke.center; + _borderLineTo(border, delta, false); + } + } + } +} + + +static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) +{ + auto border = stroke.borders + side; + auto theta = mathDiff(stroke.angleIn, stroke.angleOut) / 2; + SwPoint delta; + bool intersect; + + /* Only intersect borders if between two line_to's and both + lines are long enough (line length is zero fur curves). */ + if (!border->movable || lineLength == 0) { + intersect = false; + } else { + //compute minimum required length of lines + SwFixed minLength = abs(mathMultiply(stroke.width, mathTan(theta))); + if (stroke.lineLength >= minLength && lineLength >= minLength) intersect = true; + } + + auto rotate = SIDE_TO_ROTATE(side); + + if (!intersect) { + delta = {stroke.width, 0}; + mathRotate(delta, stroke.angleOut + rotate); + delta += stroke.center; + border->movable = false; + } else { + //compute median angle + delta = {mathDivide(stroke.width, mathCos(theta)), 0}; + mathRotate(delta, stroke.angleIn + theta + rotate); + delta += stroke.center; + } + + _borderLineTo(border, delta, false); +} + + +void _processCorner(SwStroke& stroke, SwFixed lineLength) +{ + auto turn = mathDiff(stroke.angleIn, stroke.angleOut); + + //no specific corner processing is required if the turn is 0 + if (turn == 0) return; + + //when we turn to the right, the inside side is 0 + int32_t inside = 0; + + //otherwise, the inside is 1 + if (turn < 0) inside = 1; + + //process the inside + _inside(stroke, inside, lineLength); + + //process the outside + _outside(stroke, 1 - inside, lineLength); +} + + +void _subPathStart(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) +{ + SwPoint delta = {stroke.width, 0}; + mathRotate(delta, startAngle + ANGLE_PI2); + + auto pt = stroke.center + delta; + auto border = stroke.borders; + _borderMoveTo(border, pt); + + pt = stroke.center - delta; + ++border; + _borderMoveTo(border, pt); + + /* Save angle, position and line length for last join + lineLength is zero for curves */ + stroke.subPathAngle = startAngle; + stroke.firstPt = false; + stroke.subPathLineLength = lineLength; +} + + +static void _lineTo(SwStroke& stroke, const SwPoint& to) +{ + auto delta = to - stroke.center; + + //a zero-length lineto is a no-op; avoid creating a spurious corner + if (delta.zero()) return; + + //compute length of line + auto lineLength = mathLength(delta); + auto angle = mathAtan(delta); + + delta = {stroke.width, 0}; + mathRotate(delta, angle + ANGLE_PI2); + + //process corner if necessary + if (stroke.firstPt) { + /* This is the first segment of a subpath. We need to add a point to each border + at their respective starting point locations. */ + _subPathStart(stroke, angle, lineLength); + } else { + //process the current corner + stroke.angleOut = angle; + _processCorner(stroke, lineLength); + } + + //now add a line segment to both the inside and outside paths + auto border = stroke.borders; + auto side = 1; + + while (side >= 0) { + auto pt = to + delta; + + //the ends of lineto borders are movable + _borderLineTo(border, pt, true); + + delta.x = -delta.x; + delta.y = -delta.y; + + --side; + ++border; + } + + stroke.angleIn = angle; + stroke.center = to; + stroke.lineLength = lineLength; +} + + +static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) +{ + /* if all control points are coincident, this is a no-op; + avoid creating a spurious corner */ + if ((stroke.center - ctrl1).small() && (ctrl1 - ctrl2).small() && (ctrl2 - to).small()) { + stroke.center = to; + return; + } + + SwPoint bezStack[37]; //TODO: static? + auto firstArc = true; + auto limit = bezStack + 32; + auto arc = bezStack; + arc[0] = to; + arc[1] = ctrl2; + arc[2] = ctrl1; + arc[3] = stroke.center; + + while (arc >= bezStack) { + SwFixed angleIn, angleOut, angleMid; + + //initialize with current direction + angleIn = angleOut = angleMid = stroke.angleIn; + + if (arc < limit && mathSmallCubic(arc, angleIn, angleMid, angleOut)) { + if (stroke.firstPt) stroke.angleIn = angleIn; + mathSplitCubic(arc); + arc += 3; + continue; + } + + if (firstArc) { + firstArc = false; + //process corner if necessary + if (stroke.firstPt) { + _subPathStart(stroke, angleIn, 0); + } else { + stroke.angleOut = angleIn; + _processCorner(stroke, 0); + } + } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (ANGLE_PI / 8)) { + //if the deviation from one arc to the next is too great add a round corner + stroke.center = arc[3]; + stroke.angleOut = angleIn; + stroke.join = StrokeJoin::Round; + + _processCorner(stroke, 0); + + //reinstate line join style + stroke.join = stroke.joinSaved; + } + + //the arc's angle is small enough; we can add it directly to each border + auto theta1 = mathDiff(angleIn, angleMid) / 2; + auto theta2 = mathDiff(angleMid, angleOut) / 2; + auto phi1 = mathMean(angleIn, angleMid); + auto phi2 = mathMean(angleMid, angleOut); + auto length1 = mathDivide(stroke.width, mathCos(theta1)); + auto length2 = mathDivide(stroke.width, mathCos(theta2)); + SwFixed alpha0 = 0; + + //compute direction of original arc + if (stroke.handleWideStrokes) { + alpha0 = mathAtan(arc[0] - arc[3]); + } + + auto border = stroke.borders; + int32_t side = 0; + + while (side <= 1) + { + auto rotate = SIDE_TO_ROTATE(side); + + //compute control points + SwPoint _ctrl1 = {length1, 0}; + mathRotate(_ctrl1, phi1 + rotate); + _ctrl1 += arc[2]; + + SwPoint _ctrl2 = {length2, 0}; + mathRotate(_ctrl2, phi2 + rotate); + _ctrl2 += arc[1]; + + //compute end point + SwPoint _end = {stroke.width, 0}; + mathRotate(_end, angleOut + rotate); + _end += arc[0]; + + if (stroke.handleWideStrokes) { + + /* determine whether the border radius is greater than the radius of + curvature of the original arc */ + auto _start = border->pts[border->ptsCnt - 1]; + auto alpha1 = mathAtan(_end - _start); + + //is the direction of the border arc opposite to that of the original arc? + if (abs(mathDiff(alpha0, alpha1)) > ANGLE_PI / 2) { + + //use the sine rule to find the intersection point + auto beta = mathAtan(arc[3] - _start); + auto gamma = mathAtan(arc[0] - _end); + auto bvec = _end - _start; + auto blen = mathLength(bvec); + auto sinA = abs(mathSin(alpha1 - gamma)); + auto sinB = abs(mathSin(beta - gamma)); + auto alen = mathMulDiv(blen, sinA, sinB); + + SwPoint delta = {alen, 0}; + mathRotate(delta, beta); + delta += _start; + + //circumnavigate the negative sector backwards + border->movable = false; + _borderLineTo(border, delta, false); + _borderLineTo(border, _end, false); + _borderCubicTo(border, _ctrl2, _ctrl1, _start); + + //and thenmove to the endpoint + _borderLineTo(border, _end, false); + + continue; + } + + //else fall through + } + _borderCubicTo(border, _ctrl1, _ctrl2, _end); + ++side; + ++border; + } + arc -= 3; + stroke.angleIn = angleOut; + } + stroke.center = to; +} + + static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) { if (stroke.cap == StrokeCap::Square) { @@ -298,20 +559,20 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) auto border = stroke.borders + side; SwPoint delta = {stroke.width, 0}; - _rotate(delta, angle); + mathRotate(delta, angle); SwPoint delta2 = {stroke.width, 0}; - _rotate(delta2, angle + rotate); + mathRotate(delta2, angle + rotate); delta += stroke.center + delta2; _borderLineTo(border, delta, false); delta = {stroke.width, 0}; - _rotate(delta, angle); + mathRotate(delta, angle); delta2 = {stroke.width, 0}; - _rotate(delta2, angle - rotate); + mathRotate(delta2, angle - rotate); delta += delta2 + stroke.center; @@ -329,14 +590,14 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) auto border = stroke.borders + side; SwPoint delta = {stroke.width, 0}; - _rotate(delta, angle + rotate); + mathRotate(delta, angle + rotate); delta += stroke.center; _borderLineTo(border, delta, false); delta = {stroke.width, 0}; - _rotate(delta, angle - rotate); + mathRotate(delta, angle - rotate); delta += stroke.center; @@ -389,88 +650,6 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) } -static void _closeBorder(SwStrokeBorder* border, bool reverse) -{ - assert(border && border->start >= 0); - - uint32_t start = border->start; - uint32_t count = border->ptsCnt; - - //Don't record empty paths! - if (count <= start + 1U) { - border->ptsCnt = start; - } else { - /* Copy the last point to the start of this sub-path, - since it contains the adjusted starting coordinates */ - border->ptsCnt = --count; - border->pts[start] = border->pts[count]; - - if (reverse) { - //reverse the points - auto pt1 = border->pts + start + 1; - auto pt2 = border->pts + count - 1; - - for (; pt1 < pt2; pt1++, pt2--) { - auto tmp = *pt1; - *pt1 = *pt2; - *pt2 = tmp; - } - - //reverse the tags - auto tag1 = border->tags + start + 1; - auto tag2 = border->tags + count - 1; - - for (; tag1 < tag2; tag1++, tag2++) { - auto tmp = *tag1; - *tag1 = *tag2; - *tag2 = tmp; - } - } - - border->tags[start] |= SW_STROKE_TAG_BEGIN; - border->tags[count - 1] |= SW_STROKE_TAG_END; - } - - border->start = -1; - border->movable = false; -} - - -static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) -{ - auto border = stroke.borders + side; - auto theta = _angleDiff(stroke.angleIn, stroke.angleOut) / 2; - SwPoint delta; - bool intersect; - - /* Only intersect borders if between two line_to's and both - lines are long enough (line length is zero fur curves). */ - if (!border->movable || lineLength == 0) { - intersect = false; - } else { - //compute minimum required length of lines - SwFixed minLength = abs(_multiply(stroke.width, _tan(theta))); - if (stroke.lineLength >= minLength && lineLength >= minLength) intersect = true; - } - - auto rotate = SIDE_TO_ROTATE(side); - - if (!intersect) { - delta = {stroke.width, 0}; - _rotate(delta, stroke.angleOut + rotate); - delta += stroke.center; - border->movable = false; - } else { - //compute median angle - delta = {_divide(stroke.width, _cos(theta)), 0}; - _rotate(delta, stroke.angleIn + theta + rotate); - delta += stroke.center; - } - - _borderLineTo(border, delta, false); -} - - static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) { cout << "stroke opened? = " << opened << endl; @@ -518,7 +697,7 @@ static void _endSubPath(SwStroke& stroke) /* now end the right subpath accordingly. The left one is rewind and deosn't need further processing */ - _closeBorder(right, false); + _borderClose(right, false); } else { //close the path if needed @@ -527,7 +706,7 @@ static void _endSubPath(SwStroke& stroke) //process the corner stroke.angleOut = stroke.subPathAngle; - auto turn = _angleDiff(stroke.angleIn, stroke.angleOut); + auto turn = mathDiff(stroke.angleIn, stroke.angleOut); //No specific corner processing is required if the turn is 0 if (turn != 0) { @@ -542,8 +721,8 @@ static void _endSubPath(SwStroke& stroke) _inside(stroke, 1 - inside, stroke.subPathLineLength); //outside } - _closeBorder(stroke.borders + 0, false); - _closeBorder(stroke.borders + 1, true); + _borderClose(stroke.borders + 0, false); + _borderClose(stroke.borders + 1, true); } } @@ -572,14 +751,6 @@ void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) { _deleteRle(stroke); -#if 0 - miterLimit = 4 * (1 >> 16); - - /* ensure miter limit has sensible value */ - if ( stroker->miter_limit < 0x10000 ) - stroker->miter_limit = 0x10000; -#endif - stroke.width = TO_SWCOORD(width * 0.5f); stroke.cap = cap; From 1686af7643cdfbe02859ab6323396f439d228756 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 1 Jun 2020 20:27:43 +0900 Subject: [PATCH 067/244] sw_engine: implement stroke rle part Current stroke fails to merged shapes case... you can test with testStroke example Change-Id: I488af728949cba1d01b88723eb1dc4c49bac6c9b --- src/lib/sw_engine/tvgSwCommon.h | 11 +- src/lib/sw_engine/tvgSwMath.cpp | 101 +++++++++--------- src/lib/sw_engine/tvgSwRaster.cpp | 26 +++-- src/lib/sw_engine/tvgSwRenderer.cpp | 12 +-- src/lib/sw_engine/tvgSwRle.cpp | 24 ++--- src/lib/sw_engine/tvgSwShape.cpp | 80 ++++++++------- src/lib/sw_engine/tvgSwStroke.cpp | 153 +++++++++++++++++++++++----- test/testStroke.cpp | 5 +- 8 files changed, 271 insertions(+), 141 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index b942ca18..cfb15bdf 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -121,8 +121,6 @@ struct SwStrokeBorder struct SwStroke { - SwRleData* rle; - SwFixed angleIn; SwFixed angleOut; SwPoint center; @@ -146,8 +144,9 @@ struct SwStroke struct SwShape { SwOutline* outline; - SwRleData* rle; SwStroke* stroke; + SwRleData* rle; + SwRleData* strokeRle; SwBBox bbox; }; @@ -196,11 +195,13 @@ void shapeFree(SwShape* sdata); void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join); bool strokeParseOutline(SwStroke& stroke, SwOutline& outline); +SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); -SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); -SwRleData* rleStrokeRender(const SwShape& sdata); +SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); +void rleFree(SwRleData* rle); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 919fe1ed..d2fcc4ee 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -24,7 +24,7 @@ /* Internal Class Implementation */ /************************************************************************/ -constexpr auto CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 +constexpr SwCoord CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 //this table was generated for SW_FT_PI = 180L << 16, i.e. degrees constexpr static auto ATAN_MAX = 23; @@ -45,15 +45,14 @@ static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n) } -static SwCoord _downscale(SwCoord x) +static SwCoord _downscale(SwFixed x) { //multiply a give value by the CORDIC shrink factor - - abs(x); - int64_t t = (x * static_cast(CORDIC_FACTOR)) + 0x100000000UL; - x = static_cast(t >> 32); - if (x < 0) x = -x; - return x; + auto s = abs(x); + int64_t t = (s * static_cast(CORDIC_FACTOR)) + 0x100000000UL; + s = static_cast(t >> 32); + if (x < 0) s = -s; + return s; } @@ -139,6 +138,47 @@ static void _polarize(SwPoint& pt) } +static void _rotate(SwPoint& pt, SwFixed theta) +{ + auto v = pt; + + //Rotate inside [-PI/4, PI/4] sector + while (theta < -ANGLE_PI4) { + auto tmp = v.y; + v.y = -v.x; + v.x = tmp; + theta += ANGLE_PI2; + } + + while (theta > ANGLE_PI4) { + auto tmp = -v.y; + v.y = v.x; + v.x = tmp; + theta -= ANGLE_PI2; + } + + auto atan = ATAN_TBL; + uint32_t i; + SwFixed j; + + for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { + if (theta < 0) { + auto tmp = v.x + ((v.y + j) >> i); + v.y = v.y - ((v.x + j) >> i); + v.x = tmp; + theta += *atan++; + }else { + auto tmp = v.x - ((v.y + j) >> i); + v.y = v.y + ((v.x + j) >> i); + v.x = tmp; + theta -= *atan++; + } + } + + pt = v; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -267,57 +307,26 @@ void mathRotate(SwPoint& pt, SwFixed angle) auto shift = _normalize(v); auto theta = angle; - //Rotate inside [-PI/4, PI/4] sector - while (theta < -ANGLE_PI4) { - auto tmp = v.y; - v.y = -v.x; - v.x = tmp; - theta += ANGLE_PI2; - } - - while (theta > ANGLE_PI4) { - auto tmp = -v.y; - v.y = v.x; - v.x = tmp; - theta -= ANGLE_PI2; - } - - auto atan = ATAN_TBL; - uint32_t i; - SwFixed j; - - for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { - if (theta < 0) { - auto tmp = v.x + ((v.y + j) >> i); - v.y = v.y - ((v.x + j) >> i); - v.x = tmp; - theta += *atan++; - }else { - auto tmp = v.x - ((v.y + j) >> i); - v.y = v.y + ((v.x + j) >> i); - v.x = tmp; - theta -= *atan++; - } - } + _rotate(v, theta); v.x = _downscale(v.x); v.y = _downscale(v.y); if (shift > 0) { auto half = static_cast(1L << (shift - 1)); - v.x = (v.x + half + SATURATE(v.x)) >> shift; - v.y = (v.y + half + SATURATE(v.y)) >> shift; + pt.x = (v.x + half + SATURATE(v.x)) >> shift; + pt.y = (v.y + half + SATURATE(v.y)) >> shift; } else { shift = -shift; - v.x = static_cast((unsigned long)v.x << shift); - v.y = static_cast((unsigned long)v.y << shift); + pt.x = static_cast((unsigned long)v.x << shift); + pt.y = static_cast((unsigned long)v.y << shift); } } SwFixed mathTan(SwFixed angle) { SwPoint v = {CORDIC_FACTOR >> 8, 0}; - mathRotate(v, angle); + _rotate(v, angle); return mathDivide(v.y, v.x); } @@ -343,7 +352,7 @@ SwFixed mathSin(SwFixed angle) SwFixed mathCos(SwFixed angle) { SwPoint v = {CORDIC_FACTOR >> 8, 0}; - mathRotate(v, angle); + _rotate(v, angle); return (v.x + 0x80L) >> 8; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index ba7c6a35..78d507b5 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -76,18 +76,13 @@ _rasterSolid(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) } -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static bool +_rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a) { - SwRleData* rle = sdata.rle; if (!rle) return false; auto span = rle->spans; auto stride = surface.stride; - auto color = COLOR_ARGB_JOIN(r, g, b, a); for (uint32_t i = 0; i < rle->size; ++i) { assert(span); @@ -103,4 +98,21 @@ bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t return true; } + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return _rasterRle(surface, sdata.rle, COLOR_ARGB_JOIN(r, g, b, a), a); +} + + +bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return _rasterRle(surface, sdata.strokeRle, COLOR_ARGB_JOIN(r, g, b, a), a); +} + + #endif /* _TVG_SW_RASTER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index bf97c9b3..3ec882e2 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -63,16 +63,14 @@ bool SwRenderer::render(const Shape& shape, void *data) if (!sdata) return false; size_t r, g, b, a; + shape.fill(&r, &g, &b, &a); + if (a > 0) rasterShape(surface, *sdata, r, g, b, a); - size_t sa; - shape.strokeColor(nullptr, nullptr, nullptr, &sa); + shape.strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, *sdata, r, g, b, a); - //invisible? - if (a == 0 && sa == 0) return false; - - //TODO: Threading - return rasterShape(surface, *sdata, r, g, b, a); + return true; } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 7bbc3265..b22b2331 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -612,9 +612,7 @@ static bool _decomposeOutline(RleWorker& rw) goto close; } } - - //FIXME: Close the contour with a line segment? - //_lineTo(rw, UPSCALE(outline->pts[first])); + _lineTo(rw, UPSCALE(outline->pts[first])); close: first = last + 1; } @@ -646,13 +644,12 @@ static bool _genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) +SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) { //Please adjust when you out of cell memory (default: 16384L) constexpr auto RENDER_POOL_SIZE = 166641L; constexpr auto BAND_SIZE = 40; - auto outline = sdata.outline; assert(outline); assert(outline->cntrs && outline->pts); assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); @@ -671,11 +668,11 @@ SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) rw.area = 0; rw.cover = 0; rw.invalid = true; - rw.cellMin = sdata.bbox.min; - rw.cellMax = sdata.bbox.max; + rw.cellMin = bbox.min; + rw.cellMax = bbox.max; rw.cellXCnt = rw.cellMax.x - rw.cellMin.x; rw.cellYCnt = rw.cellMax.y - rw.cellMin.y; - rw.outline = outline; + rw.outline = const_cast(outline); rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; rw.clip = clip; @@ -770,12 +767,13 @@ error: } -SwRleData* rleStrokeRender(const SwShape& sdata) +void rleFree(SwRleData* rle) { - auto stroke = sdata.stroke; - assert(stroke); - - return nullptr; + if (!rle) return; + if (rle->spans) free(rle->spans); + free(rle); } + + #endif /* _TVG_SW_RLE_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index f1ab06e0..e8e19965 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -64,6 +64,17 @@ static void _growOutlinePoint(SwOutline& outline, uint32_t n) } +static void _freeOutline(SwOutline* outline) +{ + if (!outline) return; + + if (outline->cntrs) free(outline->cntrs); + if (outline->pts) free(outline->pts); + if (outline->types) free(outline->types); + free(outline); +} + + static void _outlineEnd(SwOutline& outline) { _growOutlineContour(outline, 1); @@ -153,23 +164,22 @@ static void _outlineClose(SwOutline& outline) } -static void _initBBox(SwShape& sdata) +static void _initBBox(SwBBox& bbox) { - sdata.bbox.min.x = sdata.bbox.min.y = 0; - sdata.bbox.max.x = sdata.bbox.max.y = 0; + bbox.min.x = bbox.min.y = 0; + bbox.max.x = bbox.max.y = 0; } -static bool _updateBBox(SwShape& sdata) +static bool _updateBBox(SwOutline* outline, SwBBox& bbox) { - auto outline = sdata.outline; - assert(outline); + if (!outline) return false; auto pt = outline->pts; assert(pt); if (outline->ptsCnt <= 0) { - _initBBox(sdata); + _initBBox(bbox); return false; } @@ -187,10 +197,10 @@ static bool _updateBBox(SwShape& sdata) if (yMin > pt->y) yMin = pt->y; if (yMax < pt->y) yMax = pt->y; } - sdata.bbox.min.x = xMin >> 6; - sdata.bbox.max.x = (xMax + 63) >> 6; - sdata.bbox.min.y = yMin >> 6; - sdata.bbox.max.y = (yMax + 63) >> 6; + bbox.min.x = xMin >> 6; + bbox.max.x = (xMax + 63) >> 6; + bbox.min.y = yMin >> 6; + bbox.max.y = (yMax + 63) >> 6; if (xMax - xMin < 1 || yMax - yMin < 1) return false; @@ -213,16 +223,6 @@ static bool _checkValid(SwShape& sdata, const SwSize& clip) } -static void _deleteRle(SwShape& sdata) -{ - if (!sdata.rle) return; - if (sdata.rle->spans) free(sdata.rle->spans); - free(sdata.rle); - sdata.rle = nullptr; -} - - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -245,10 +245,10 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) { - if (!_updateBBox(sdata)) goto end; + if (!_updateBBox(sdata.outline, sdata.bbox)) goto end; if (!_checkValid(sdata, clip)) goto end; - sdata.rle = rleRender(sdata, clip); + sdata.rle = rleRender(sdata.outline, sdata.bbox, clip); end: if (sdata.rle) return true; @@ -259,12 +259,7 @@ end: void shapeDelOutline(SwShape& sdata) { auto outline = sdata.outline; - if (!outline) return; - - if (outline->cntrs) free(outline->cntrs); - if (outline->pts) free(outline->pts); - if (outline->types) free(outline->types); - free(outline); + _freeOutline(outline); sdata.outline = nullptr; } @@ -272,8 +267,9 @@ void shapeDelOutline(SwShape& sdata) void shapeReset(SwShape& sdata) { shapeDelOutline(sdata); - _deleteRle(sdata); - _initBBox(sdata); + rleFree(sdata.rle); + sdata.rle = nullptr; + _initBBox(sdata.bbox); } @@ -366,8 +362,13 @@ void shapeFree(SwShape* sdata) assert(sdata); shapeDelOutline(*sdata); - _deleteRle(*sdata); - strokeFree(sdata->stroke); + rleFree(sdata->rle); + + if (sdata->stroke) { + rleFree(sdata->strokeRle); + strokeFree(sdata->stroke); + } + free(sdata); } @@ -377,8 +378,9 @@ void shapeResetStroke(const Shape& shape, SwShape& sdata) if (!sdata.stroke) sdata.stroke = static_cast(calloc(1, sizeof(SwStroke))); auto stroke = sdata.stroke; assert(stroke); - strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin()); + rleFree(sdata.strokeRle); + sdata.strokeRle = nullptr; } @@ -392,6 +394,16 @@ bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip) if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false; + auto outline = strokeExportOutline(*sdata.stroke); + if (!outline) return false; + + SwBBox bbox; + _updateBBox(outline, bbox); + + sdata.strokeRle = rleRender(outline, bbox, clip); + + _freeOutline(outline); + return true; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index a0a25738..8477d7cd 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -23,7 +23,7 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static constexpr auto SW_STROKE_TAG_ON = 1; +static constexpr auto SW_STROKE_TAG_POINT = 1; static constexpr auto SW_STROKE_TAG_CUBIC = 2; static constexpr auto SW_STROKE_TAG_BEGIN = 4; static constexpr auto SW_STROKE_TAG_END = 8; @@ -36,6 +36,8 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s) static void _growBorder(SwStrokeBorder* border, uint32_t newPts) { + assert(border); + auto maxOld = border->maxPts; auto maxNew = border->ptsCnt + newPts; @@ -53,8 +55,6 @@ static void _growBorder(SwStrokeBorder* border, uint32_t newPts) assert(border->tags); border->maxPts = maxCur; - - printf("realloc border!!! (%u => %u)\n", maxOld, maxCur); } @@ -111,7 +111,7 @@ static void _borderClose(SwStrokeBorder* border, bool reverse) static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) { - assert(border->start >= 0); + assert(border && border->start >= 0); _growBorder(border, 3); @@ -124,9 +124,10 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl tag[0] = SW_STROKE_TAG_CUBIC; tag[1] = SW_STROKE_TAG_CUBIC; - tag[2] = SW_STROKE_TAG_ON; + tag[2] = SW_STROKE_TAG_POINT; border->ptsCnt += 3; + border->movable = false; } @@ -188,13 +189,13 @@ static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) //move last point border->pts[border->ptsCnt - 1] = to; } else { + //don't add zero-length line_to - auto diff = border->pts[border->ptsCnt - 1] - to; - if (border->ptsCnt > 0 && diff.small()) return; + if (border->ptsCnt > 0 && (border->pts[border->ptsCnt - 1] - to).small()) return; _growBorder(border, 1); border->pts[border->ptsCnt] = to; - border->tags[border->ptsCnt] = SW_STROKE_TAG_ON; + border->tags[border->ptsCnt] = SW_STROKE_TAG_POINT; border->ptsCnt += 1; } @@ -207,8 +208,7 @@ static void _borderMoveTo(SwStrokeBorder* border, SwPoint& to) assert(border); //close current open path if any? - if (border->start >= 0) - _borderClose(border, false); + if (border->start >= 0) _borderClose(border, false); border->start = border->ptsCnt; border->movable = false; @@ -318,8 +318,11 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) border->movable = false; } else { //compute median angle - delta = {mathDivide(stroke.width, mathCos(theta)), 0}; - mathRotate(delta, stroke.angleIn + theta + rotate); + auto phi = stroke.angleIn + theta; + auto thcos = mathCos(theta); + auto length = mathDivide(stroke.width, thcos); + delta = {length, 0}; + mathRotate(delta, phi + rotate); delta += stroke.center; } @@ -652,11 +655,9 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) { - cout << "stroke opened? = " << opened << endl; - /* We cannot process the first point because there is not enought information regarding its corner/cap. Later, it will be processed - in the _strokeEndSubPath() */ + in the _endSubPath() */ stroke.firstPt = true; stroke.center = to; @@ -712,13 +713,13 @@ static void _endSubPath(SwStroke& stroke) if (turn != 0) { //when we turn to the right, the inside is 0 - auto inside = 0; + int32_t inside = 0; //otherwise, the inside is 1 if (turn < 0) inside = 1; _inside(stroke, inside, stroke.subPathLineLength); //inside - _inside(stroke, 1 - inside, stroke.subPathLineLength); //outside + _outside(stroke, 1 - inside, stroke.subPathLineLength); //outside } _borderClose(stroke.borders + 0, false); @@ -727,14 +728,81 @@ static void _endSubPath(SwStroke& stroke) } -static void _deleteRle(SwStroke& stroke) +static void _getCounts(SwStrokeBorder* border, uint32_t& ptsCnt, uint32_t& cntrsCnt) { - if (!stroke.rle) return; - if (stroke.rle->spans) free(stroke.rle->spans); - free(stroke.rle); - stroke.rle = nullptr; + assert(border); + + auto count = border->ptsCnt; + auto tags = border->tags; + uint32_t _ptsCnt = 0; + uint32_t _cntrsCnt = 0; + bool inCntr = false; + + while (count > 0) { + + if (tags[0] & SW_STROKE_TAG_BEGIN) { + if (inCntr) goto fail; + inCntr = true; + } else if (!inCntr) goto fail; + + if (tags[0] & SW_STROKE_TAG_END) { + inCntr = false; + ++_cntrsCnt; + } + --count; + ++_ptsCnt; + ++tags; + } + + if (inCntr) goto fail; + border->valid = true; + ptsCnt = _ptsCnt; + cntrsCnt = _cntrsCnt; + + return; + +fail: + ptsCnt = 0; + cntrsCnt = 0; } + +static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t side) +{ + auto border = stroke.borders + side; + assert(border); + + if (!border->valid) return; + + memcpy(outline->pts + outline->ptsCnt, border->pts, border->ptsCnt * sizeof(SwPoint)); + + auto cnt = border->ptsCnt; + auto src = border->tags; + auto tags = outline->types + outline->ptsCnt; + auto cntrs = outline->cntrs + outline->cntrsCnt; + uint16_t idx = outline->ptsCnt; + + while (cnt > 0) { + + if (*src & SW_STROKE_TAG_POINT) *tags = SW_CURVE_TYPE_POINT; + else if (*src & SW_STROKE_TAG_CUBIC) *tags = SW_CURVE_TYPE_CUBIC; + else cout << "what type of stroke outline??" << endl; + + if (*src & SW_STROKE_TAG_END) { + *cntrs = idx; + ++cntrs; + ++outline->cntrsCnt; + } + + ++src; + ++tags; + ++idx; + --cnt; + } + outline->ptsCnt = outline->ptsCnt + border->ptsCnt; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -742,16 +810,20 @@ static void _deleteRle(SwStroke& stroke) void strokeFree(SwStroke* stroke) { if (!stroke) return; - _deleteRle(*stroke); + + //free borders + if (stroke->borders[0].pts) free(stroke->borders[0].pts); + if (stroke->borders[0].tags) free(stroke->borders[0].tags); + if (stroke->borders[1].pts) free(stroke->borders[1].pts); + if (stroke->borders[1].tags) free(stroke->borders[1].tags); + free(stroke); } void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) { - _deleteRle(stroke); - - stroke.width = TO_SWCOORD(width * 0.5f); + stroke.width = TO_SWCOORD(width * 0.5); stroke.cap = cap; //Save line join: it can be temporarily changed when stroking curves... @@ -826,4 +898,33 @@ bool strokeParseOutline(SwStroke& stroke, SwOutline& outline) } +SwOutline* strokeExportOutline(SwStroke& stroke) +{ + uint32_t count1, count2, count3, count4; + + _getCounts(stroke.borders + 0, count1, count2); + _getCounts(stroke.borders + 1, count3, count4); + + auto ptsCnt = count1 + count3; + auto cntrsCnt = count2 + count4; + + auto outline = static_cast(calloc(1, sizeof(SwOutline))); + assert(outline); + + outline->pts = static_cast(malloc(sizeof(SwPoint) * ptsCnt)); + assert(outline->pts); + + outline->types = static_cast(malloc(sizeof(uint8_t) * ptsCnt)); + assert(outline->types); + + outline->cntrs = static_cast(malloc(sizeof(uint32_t) * cntrsCnt)); + assert(outline->cntrs); + + _exportBorderOutline(stroke, outline, 0); //left + _exportBorderOutline(stroke, outline, 1); //right + + return outline; +} + + #endif /* _TVG_SW_STROKER_H_ */ diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 1f865d68..d978b6fc 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -23,11 +23,10 @@ void tvgtest() //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(50, 50, 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->fill(50, 50, 50, 255); //r, g, b, a //Stroke Style shape1->stroke(255, 255, 255, 255); //color: r, g, b, a From bab258e004505faa25eeec0ba285141ed4716f8d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 2 Jun 2020 20:04:44 +0900 Subject: [PATCH 068/244] test: revise stroke example Change-Id: I92a40e905544fd8fb41df88810eabce7429b1b7f --- test/testStroke.cpp | 68 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/test/testStroke.cpp b/test/testStroke.cpp index d978b6fc..a4678dc5 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -21,24 +21,64 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) + //Shape 1 auto shape1 = tvg::Shape::gen(); - shape1->appendRect(50, 50, 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->fill(50, 50, 50, 255); //r, g, b, a - - //Stroke Style - shape1->stroke(255, 255, 255, 255); //color: r, g, b, a - shape1->stroke(5); //width: 5px -// shape1->strokeJoin(tvg::StrokeJoin::Miter); -// shape1->strokeLineCap(tvg::StrokeLineCap::Butt); - -// uint32_t dash[] = {3, 1, 5, 1}; //dash pattern -// shape1->strokeDash(dash, 4); + shape1->appendRect(50, 50, 200, 200, 0); + shape1->fill(50, 50, 50, 255); + shape1->stroke(255, 255, 255, 255); //color: r, g, b, a + shape1->stroke(tvg::StrokeJoin::Bevel); //default is Bevel + shape1->stroke(10); //width: 10px canvas->push(move(shape1)); + //Shape 2 + auto shape2 = tvg::Shape::gen(); + shape2->appendRect(300, 50, 200, 200, 0); + shape2->fill(50, 50, 50, 255); + shape2->stroke(255, 255, 255, 255); + shape2->stroke(tvg::StrokeJoin::Round); + shape2->stroke(10); + + canvas->push(move(shape2)); + + //Shape 3 + auto shape3 = tvg::Shape::gen(); + shape3->appendRect(550, 50, 200, 200, 0); + shape3->fill(50, 50, 50, 255); + shape3->stroke(255, 255, 255, 255); + shape3->stroke(tvg::StrokeJoin::Miter); + shape3->stroke(10); + + canvas->push(move(shape3)); + + //Shape 4 + auto shape4 = tvg::Shape::gen(); + shape4->appendCircle(150, 450, 100, 100); + shape4->fill(50, 50, 50, 255); + shape4->stroke(255, 255, 255, 255); + shape4->stroke(1); + + canvas->push(move(shape4)); + + //Shape 5 + auto shape5 = tvg::Shape::gen(); + shape5->appendCircle(400, 450, 100, 100); + shape5->fill(50, 50, 50, 255); + shape5->stroke(255, 255, 255, 255); + shape5->stroke(2); + + canvas->push(move(shape5)); + + //Shape 6 + auto shape6 = tvg::Shape::gen(); + shape6->appendCircle(650, 450, 100, 100); + shape6->fill(50, 50, 50, 255); + shape6->stroke(255, 255, 255, 255); + shape6->stroke(4); + + canvas->push(move(shape6)); + + canvas->draw(); canvas->sync(); From 8614a2efee4b8066c819db2c714f11c341254588 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 2 Jun 2020 20:25:54 +0900 Subject: [PATCH 069/244] sw_engine: fix stroke join round result. a trivial reversed value was returned that brought the inverted arc drawing... Change-Id: I928f05b3400772a367d1653496d385354032cbad --- src/lib/sw_engine/tvgSwMath.cpp | 2 +- src/lib/sw_engine/tvgSwStroke.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index d2fcc4ee..80c7f8e0 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -295,7 +295,7 @@ int64_t mathMulDiv(int64_t a, int64_t b, int64_t c) } int64_t d = c > 0 ? (a * b + (c >> 1)) / c : 0x7FFFFFFFL; - return (s > 0 ? -d : d); + return (s > 0 ? d : -d); } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 8477d7cd..e048ff53 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -134,7 +134,7 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff) { - constexpr auto ARC_CUBIC_ANGLE = ANGLE_PI / 2; + constexpr SwFixed ARC_CUBIC_ANGLE = ANGLE_PI / 2; SwPoint a = {radius, 0}; mathRotate(a, angleStart); a += center; From ef9f31577e0fbf94a0135b827e84750be5673f2b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 2 Jun 2020 20:58:50 +0900 Subject: [PATCH 070/244] common stroke: retype the stroke width from size_t to float Change-Id: I812d06d2037d66408c41d50f7c1ff7ba605558bd --- inc/tizenvg.h | 4 ++-- src/lib/tvgShape.cpp | 6 +++--- src/lib/tvgShapeImpl.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 05f19273..c113975b 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -141,7 +141,7 @@ public: int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; //Stroke - int stroke(size_t width) noexcept; + int stroke(float width) noexcept; int stroke(size_t r, size_t g, size_t b, size_t a) noexcept; int stroke(const size_t* dashPattern, size_t cnt) noexcept; int stroke(StrokeCap cap) noexcept; @@ -161,7 +161,7 @@ public: int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; int bounds(float* x, float* y, float* w, float* h) const noexcept override; - size_t strokeWidth() const noexcept; + float strokeWidth() const noexcept; int strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; size_t strokeDash(const size_t** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index a17c53b0..fe95eac2 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -280,7 +280,7 @@ int Shape::bounds(float* x, float* y, float* w, float* h) const noexcept } -int Shape::stroke(size_t width) noexcept +int Shape::stroke(float width) noexcept { auto impl = pImpl.get(); assert(impl); @@ -291,12 +291,12 @@ int Shape::stroke(size_t width) noexcept } -size_t Shape::strokeWidth() const noexcept +float Shape::strokeWidth() const noexcept { auto impl = pImpl.get(); assert(impl); - if (!impl->stroke) return -1; + if (!impl->stroke) return 0; return impl->stroke->width; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 682c29b7..05be16d2 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -30,7 +30,7 @@ struct ShapeFill struct ShapeStroke { - size_t width = 0; + float width = 0; size_t color[4] = {0, 0, 0, 0}; size_t* dashPattern = nullptr; size_t dashCnt = 0; @@ -153,7 +153,7 @@ struct Shape::Impl return 0; } - bool strokeWidth(size_t width) + bool strokeWidth(float width) { //TODO: Size Exception? From 7ee25cd78334a24bb6b465ae5db46bb4dbf403cb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:15:40 +0900 Subject: [PATCH 071/244] sw_engine: fix mistached c style alloc/free these are allocated by c style mem alloc. Thus, they should be freed with free() Change-Id: I320fff4d5a5bce2374ace6495a9f96c3e1034cfc --- src/lib/sw_engine/tvgSwStroke.cpp | 1 + src/lib/tvgShapePath.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index e048ff53..be18e05a 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -838,6 +838,7 @@ void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) stroke.borders[1].valid = false; } + bool strokeParseOutline(SwStroke& stroke, SwOutline& outline) { uint32_t first = 0; diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 68205f48..7e020e8b 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -36,8 +36,8 @@ struct ShapePath ~ShapePath() { - if (cmds) delete(cmds); - if (pts) delete(pts); + if (cmds) free(cmds); + if (pts) free(pts); } void reserveCmd(size_t cmdCnt) From 3bb272877a273c01cde42c35f313128a538642dd Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:27:34 +0900 Subject: [PATCH 072/244] sw_engine: fix a missing of variable initializing. Change-Id: I6451b07709fbc56441363e8f0ee0f4647404ae10 --- src/lib/sw_engine/tvgSwRle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index b22b2331..1d5577bf 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -672,6 +672,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.cellMax = bbox.max; rw.cellXCnt = rw.cellMax.x - rw.cellMin.x; rw.cellYCnt = rw.cellMax.y - rw.cellMin.y; + rw.ySpan = 0; rw.outline = const_cast(outline); rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; From 2b53b8018a0275e55f1caca48ab36db66ad3f291 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:35:03 +0900 Subject: [PATCH 073/244] test stroke: remove duplicated engine initialize call. Change-Id: Ia592a45581eae4fd5c85e6ba4d9d0eef835b14c1 --- test/testStroke.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/testStroke.cpp b/test/testStroke.cpp index a4678dc5..b17c3a10 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -14,9 +14,6 @@ void tvgtest() //Initialize TizenVG Engine tvg::Engine::init(); - //Initialize TizenVG Engine - tvg::Engine::init(); - //Create a Canvas auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); From ad6b74dd1392a2272f71e63e3fba7ede8c5fd83e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:41:40 +0900 Subject: [PATCH 074/244] test scene: remove duplicated engine initialization. Change-Id: I5a2f972544e47578552b0c49367749ce2d01c5f2 --- test/testSceneTransform.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 38bfb0f2..a66996a5 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -13,9 +13,6 @@ tvg::Scene* pScene2 = nullptr; void tvgtest() { - //Initialize TizenVG Engine - tvg::Engine::init(); - //Create a Canvas canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); @@ -96,9 +93,6 @@ void tvgtest() canvas->draw(); canvas->sync(); - - //Terminate TizenVG Engine - tvg::Engine::term(); } void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) From 01b550497c1121d88831d844302ecf6eda1b92d1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 2 Jun 2020 21:00:50 +0900 Subject: [PATCH 075/244] sw_engine: support stroke transformation properly. also updated transform test cases. Yet, this engine is not well optimized, If they are too mch sluggish, you can use ELM_FPS envrionment lowing down the fps when you launch test cases... ex) $ELM_FPS=30 ./testSceneTransform Change-Id: I1871d5bedee010d5d6a3d877d95e257120796e8b --- src/lib/sw_engine/tvgSwRenderer.cpp | 33 +++++++++++++++++------------ test/testDirectUpdate.cpp | 3 +++ test/testSceneTransform.cpp | 12 +++++++---- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 3ec882e2..91c00139 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -93,29 +93,34 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* if (flags == RenderUpdateFlag::None) return sdata; - //invisible? - size_t a, sa; - shape.fill(nullptr, nullptr, nullptr, &a); - shape.strokeColor(nullptr, nullptr, nullptr, &sa); - if (a == 0 && sa == 0) return sdata; - //TODO: Threading SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - shapeReset(*sdata); - if (!shapeGenOutline(shape, *sdata)) return sdata; - if (transform) shapeTransformOutline(shape, *sdata, *transform); - if (!shapeGenRle(shape, *sdata, clip)) return sdata; + + size_t alpha = 0; + shape.fill(nullptr, nullptr, nullptr, &alpha); + + if (alpha > 0) { + shapeReset(*sdata); + if (!shapeGenOutline(shape, *sdata)) return sdata; + if (transform) shapeTransformOutline(shape, *sdata, *transform); + if (!shapeGenRle(shape, *sdata, clip)) return sdata; + } } //Stroke - if (flags & RenderUpdateFlag::Stroke) { - shapeResetStroke(shape, *sdata); - if (shape.strokeWidth() > 0.01) { - if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + + if (shape.strokeWidth() > 0.5) { + shapeResetStroke(shape, *sdata); + size_t alpha = 0; + shape.strokeColor(nullptr, nullptr, nullptr, &alpha); + if (alpha > 0) { + if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + } } } diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 799d1351..e1a4c608 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -27,6 +27,8 @@ void tvgtest() //fill property will be retained shape->fill(127, 255, 255, 255); + shape->stroke(0, 0, 255, 255); + shape->stroke(1); canvas->push(move(shape)); @@ -44,6 +46,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->reset(); //reset path 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); diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index a66996a5..975f4faf 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -25,19 +25,21 @@ void tvgtest() //Prepare Round Rectangle (Scene1) auto shape1 = tvg::Shape::gen(); shape1->appendRect(-235, -250, 400, 400, 50); //x, y, w, h, cornerRadius - shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->stroke(5); //width + shape1->stroke(255, 255, 255, 255); //r, g, b, a scene->push(move(shape1)); //Prepare Circle (Scene1) auto shape2 = tvg::Shape::gen(); shape2->appendCircle(-165, -150, 200, 200); //cx, cy, radiusW, radiusH - shape2->fill(255, 255, 0, 255); //r, g, b, a + shape2->fill(255, 255, 0, 255); //r, g, b, a scene->push(move(shape2)); //Prepare Ellipse (Scene1) auto shape3 = tvg::Shape::gen(); - shape3->appendCircle(265, 250, 150, 100); //cx, cy, radiusW, radiusH - shape3->fill(0, 255, 255, 255); //r, g, b, a + shape3->appendCircle(265, 250, 150, 100); //cx, cy, radiusW, radiusH + shape3->fill(0, 255, 255, 255); //r, g, b, a scene->push(move(shape3)); scene->translate(350, 350); @@ -64,6 +66,8 @@ void tvgtest() shape4->lineTo(-53, -5.5); shape4->close(); shape4->fill(0, 0, 127, 127); + shape4->stroke(3); //width + shape4->stroke(0, 0, 255, 255); //r, g, b, a scene2->push(move(shape4)); //Circle (Scene2) From f335779ce52f39755828fe70d6996fa087803b06 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 19:08:18 +0900 Subject: [PATCH 076/244] sw_engine stroke: stabilizing line drawing. Also added StrokeLine test Change-Id: I91143039823d744bf9287534227927556a2f51e1 --- .gitignore | 1 + src/lib/sw_engine/tvgSwRle.cpp | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 1 + src/lib/sw_engine/tvgSwStroke.cpp | 9 ++- test/makefile | 1 + test/testStrokeLine.cpp | 101 ++++++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 test/testStrokeLine.cpp diff --git a/.gitignore b/.gitignore index 1353d089..ba439cbd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ testScene testTransform testSceneTransform testStroke +testStrokeLine diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 1d5577bf..2757c0da 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -612,7 +612,7 @@ static bool _decomposeOutline(RleWorker& rw) goto close; } } - _lineTo(rw, UPSCALE(outline->pts[first])); + _lineTo(rw, start); close: first = last + 1; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index e8e19965..a4fa7fbf 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -316,6 +316,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) auto outline = sdata.outline; if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); assert(outline); + outline->opened = true; _growOutlinePoint(*outline, outlinePtsCnt); _growOutlineContour(*outline, outlineCntrsCnt); diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index be18e05a..06ec989d 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -635,15 +635,14 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) } else { //switch begin/end tags if necessary auto ttag = dstTag[0] & (SW_STROKE_TAG_BEGIN | SW_STROKE_TAG_END); - if (ttag == (SW_STROKE_TAG_BEGIN || SW_STROKE_TAG_END)) { - dstTag[0] ^= (SW_STROKE_TAG_BEGIN || SW_STROKE_TAG_END); - } + if (ttag == SW_STROKE_TAG_BEGIN || ttag == SW_STROKE_TAG_END) + dstTag[0] ^= (SW_STROKE_TAG_BEGIN | SW_STROKE_TAG_END); } --srcPt; --srcTag; - --dstPt; - --dstTag; + ++dstPt; + ++dstTag; } left->ptsCnt = left->start; diff --git a/test/makefile b/test/makefile index 3f314e8a..2aba05df 100644 --- a/test/makefile +++ b/test/makefile @@ -11,3 +11,4 @@ all: gcc -o testTransform testTransform.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` diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp new file mode 100644 index 00000000..8687b850 --- /dev/null +++ b/test/testStrokeLine.cpp @@ -0,0 +1,101 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + for (int i = 0; i < 10; ++i) { + auto shape = tvg::Shape::gen(); + shape->moveTo(50, 50 + (25 * i)); + shape->lineTo(750, 50 + (25 * i)); + 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)); + } + + auto shape1 = tvg::Shape::gen(); + shape1->moveTo(20, 350); + shape1->lineTo(250, 350); + shape1->lineTo(220, 500); + shape1->lineTo(70, 470); + shape1->lineTo(70, 330); + shape1->stroke(255, 0, 0, 255); + shape1->stroke(10); + shape1->stroke(tvg::StrokeJoin::Round); + shape1->stroke(tvg::StrokeCap::Round); + canvas->push(move(shape1)); + + auto shape2 = tvg::Shape::gen(); + shape2->moveTo(270, 350); + shape2->lineTo(500, 350); + shape2->lineTo(470, 500); + shape2->lineTo(320, 470); + shape2->lineTo(320, 330); + shape2->stroke(255, 255, 0, 255); + shape2->stroke(10); + shape2->stroke(tvg::StrokeJoin::Bevel); + shape2->stroke(tvg::StrokeCap::Square); + canvas->push(move(shape2)); + + auto shape3 = tvg::Shape::gen(); + shape3->moveTo(520, 350); + shape3->lineTo(750, 350); + shape3->lineTo(720, 500); + shape3->lineTo(570, 470); + shape3->lineTo(570, 330); + shape3->stroke(0, 255, 0, 255); + shape3->stroke(10); + shape3->stroke(tvg::StrokeJoin::Miter); + shape3->stroke(tvg::StrokeCap::Butt); + canvas->push(move(shape3)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 98edb4112bf586a66f9bb095360eae1e9836adc8 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 19:16:44 +0900 Subject: [PATCH 077/244] sw_engine shape: ++ comment for later optimization Change-Id: Ie6cd622748b88e2bce0c9d9a79cc4528a95c9c5c --- src/lib/sw_engine/tvgSwShape.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index a4fa7fbf..30b79c86 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -245,6 +245,8 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) { + /* OPTIMIZE ME: We may avoid this bounding box calculation in this stage + if this shape has stroke and stroke bbox can be used here... */ if (!_updateBBox(sdata.outline, sdata.bbox)) goto end; if (!_checkValid(sdata, clip)) goto end; From dc5f9f7430df751f8f65755afe020d24149b74a9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 4 Jun 2020 17:49:10 +0900 Subject: [PATCH 078/244] common: retyped the color value size_t -> uint8_t since it's range is 0 - 255. Change-Id: I16e0569341c4a94acab9488d076f235bf90ff4db --- inc/tizenvg.h | 8 ++++---- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +++--- src/lib/tvgShape.cpp | 8 ++++---- src/lib/tvgShapeImpl.h | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c113975b..905c3f08 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -142,13 +142,13 @@ public: //Stroke int stroke(float width) noexcept; - int stroke(size_t r, size_t g, size_t b, size_t a) noexcept; + int stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; int stroke(const size_t* dashPattern, size_t cnt) noexcept; int stroke(StrokeCap cap) noexcept; int stroke(StrokeJoin join) noexcept; //Fill - int fill(size_t r, size_t g, size_t b, size_t a) noexcept; + int fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; //Transform int rotate(float degree) noexcept override; @@ -158,11 +158,11 @@ public: //Getters size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; - int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + int fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; int bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; - int strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + int strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; size_t strokeDash(const size_t** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 91c00139..38ac6744 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -62,7 +62,7 @@ bool SwRenderer::render(const Shape& shape, void *data) SwShape* sdata = static_cast(data); if (!sdata) return false; - size_t r, g, b, a; + uint8_t r, g, b, a; shape.fill(&r, &g, &b, &a); if (a > 0) rasterShape(surface, *sdata, r, g, b, a); @@ -100,7 +100,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - size_t alpha = 0; + uint8_t alpha = 0; shape.fill(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { @@ -116,7 +116,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* if (shape.strokeWidth() > 0.5) { shapeResetStroke(shape, *sdata); - size_t alpha = 0; + uint8_t alpha = 0; shape.strokeColor(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index fe95eac2..828e251e 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -213,7 +213,7 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no } -int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept +int Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -228,7 +228,7 @@ int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept } -int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); @@ -301,7 +301,7 @@ float Shape::strokeWidth() const noexcept } -int Shape::stroke(size_t r, size_t g, size_t b, size_t a) noexcept +int Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -312,7 +312,7 @@ int Shape::stroke(size_t r, size_t g, size_t b, size_t a) noexcept } -int Shape::strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 05be16d2..e1a4e9f7 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -31,7 +31,7 @@ struct ShapeFill struct ShapeStroke { float width = 0; - size_t color[4] = {0, 0, 0, 0}; + uint8_t color[4] = {0, 0, 0, 0}; size_t* dashPattern = nullptr; size_t dashCnt = 0; StrokeCap cap = StrokeCap::Square; @@ -188,7 +188,7 @@ struct Shape::Impl return 0; } - bool strokeColor(size_t r, size_t g, size_t b, size_t a) + bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { if (!stroke) stroke = new ShapeStroke(); assert(stroke); From 9aa2566b45f57c742f134a6e7f4597c7011406fc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 20:50:13 +0900 Subject: [PATCH 079/244] sw_engine: support stroke dash feature Change-Id: Ibed8bcb6a07952a059bb9a7355f7c43db97aa672 --- inc/tizenvg.h | 4 +- src/lib/sw_engine/tvgSwCommon.h | 38 ++- src/lib/sw_engine/tvgSwMath.cpp | 33 +- src/lib/sw_engine/tvgSwRenderer.cpp | 37 +-- src/lib/sw_engine/tvgSwShape.cpp | 492 +++++++++++++++++++++++----- src/lib/sw_engine/tvgSwStroke.cpp | 33 +- src/lib/tvgShape.cpp | 4 +- src/lib/tvgShapeImpl.h | 11 +- test/testStrokeLine.cpp | 49 +++ 9 files changed, 537 insertions(+), 164 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 905c3f08..18db8427 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -143,7 +143,7 @@ public: //Stroke int stroke(float width) noexcept; int stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; - int stroke(const size_t* dashPattern, size_t cnt) noexcept; + int stroke(const float* dashPattern, size_t cnt) noexcept; int stroke(StrokeCap cap) noexcept; int stroke(StrokeJoin join) noexcept; @@ -163,7 +163,7 @@ public: float strokeWidth() const noexcept; int strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; - size_t strokeDash(const size_t** dashPattern) const noexcept; + size_t strokeDash(const float** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index cfb15bdf..16d4c1e0 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -125,7 +125,8 @@ struct SwStroke SwFixed angleOut; SwPoint center; SwFixed lineLength; - SwPoint subPathStart; + SwFixed subPathAngle; + SwPoint ptStartSubPath; SwFixed subPathLineLength; SwFixed width; @@ -136,11 +137,22 @@ struct SwStroke SwStrokeBorder borders[2]; bool firstPt; - bool subPathOpen; - bool subPathAngle; + bool openSubPath; bool handleWideStrokes; }; +struct SwDashStroke +{ + SwOutline* outline; + int32_t curLen; + int32_t curIdx; + Point ptStart; + Point ptCur; + float* pattern; + size_t cnt; + bool curOpGap; +}; + struct SwShape { SwOutline* outline; @@ -183,18 +195,16 @@ SwFixed mathLength(SwPoint& pt); bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); -void shapeReset(SwShape& sdata); -bool shapeGenOutline(const Shape& shape, SwShape& sdata); -bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -void shapeDelOutline(SwShape& sdata); -void shapeResetStroke(const Shape& shape, SwShape& sdata); -bool shapeGenStrokeOutline(const Shape& shape, SwShape& sdata); -bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); -void shapeFree(SwShape* sdata); +void shapeReset(SwShape& shape); +bool shapeGenOutline(SwShape& shape, const Shape& sdata); +bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform); +void shapeDelOutline(SwShape& shape); +void shapeResetStroke(SwShape& shape, const Shape& sdata); +bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); +void shapeFree(SwShape* shape); -void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join); -bool strokeParseOutline(SwStroke& stroke, SwOutline& outline); +void strokeReset(SwStroke& stroke, const Shape& shape); +bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 80c7f8e0..a0a0ea16 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -140,20 +140,21 @@ static void _polarize(SwPoint& pt) static void _rotate(SwPoint& pt, SwFixed theta) { - auto v = pt; + SwFixed x = pt.x; + SwFixed y = pt.y; //Rotate inside [-PI/4, PI/4] sector while (theta < -ANGLE_PI4) { - auto tmp = v.y; - v.y = -v.x; - v.x = tmp; + auto tmp = y; + y = -x; + x = tmp; theta += ANGLE_PI2; } while (theta > ANGLE_PI4) { - auto tmp = -v.y; - v.y = v.x; - v.x = tmp; + auto tmp = -y; + y = x; + x = tmp; theta -= ANGLE_PI2; } @@ -163,19 +164,19 @@ static void _rotate(SwPoint& pt, SwFixed theta) for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { if (theta < 0) { - auto tmp = v.x + ((v.y + j) >> i); - v.y = v.y - ((v.x + j) >> i); - v.x = tmp; + auto tmp = x + ((y + j) >> i); + y = y - ((x + j) >> i); + x = tmp; theta += *atan++; }else { - auto tmp = v.x - ((v.y + j) >> i); - v.y = v.y + ((v.x + j) >> i); - v.x = tmp; + auto tmp = x - ((y + j) >> i); + y = y + ((x + j) >> i); + x = tmp; theta -= *atan++; } } - pt = v; + pt = {x, y}; } @@ -305,9 +306,9 @@ void mathRotate(SwPoint& pt, SwFixed angle) auto v = pt; auto shift = _normalize(v); - auto theta = angle; - _rotate(v, theta); + auto theta = angle; + _rotate(v, theta); v.x = _downscale(v.x); v.y = _downscale(v.y); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 38ac6744..5461abea 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -82,16 +82,16 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) +void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data - SwShape* sdata = static_cast(data); - if (!sdata) { - sdata = static_cast(calloc(1, sizeof(SwShape))); - assert(sdata); + auto shape = static_cast(data); + if (!shape) { + shape = static_cast(calloc(1, sizeof(SwShape))); + assert(shape); } - if (flags == RenderUpdateFlag::None) return sdata; + if (flags == RenderUpdateFlag::None) return shape; //TODO: Threading @@ -99,34 +99,29 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - + shapeReset(*shape); uint8_t alpha = 0; - shape.fill(nullptr, nullptr, nullptr, &alpha); - + sdata.fill(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { - shapeReset(*sdata); - if (!shapeGenOutline(shape, *sdata)) return sdata; - if (transform) shapeTransformOutline(shape, *sdata, *transform); - if (!shapeGenRle(shape, *sdata, clip)) return sdata; + if (!shapeGenRle(*shape, sdata, clip, transform)) return shape; } } //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - - if (shape.strokeWidth() > 0.5) { - shapeResetStroke(shape, *sdata); + if (sdata.strokeWidth() > 0.5) { + shapeResetStroke(*shape, sdata); uint8_t alpha = 0; - shape.strokeColor(nullptr, nullptr, nullptr, &alpha); + sdata.strokeColor(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { - if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + if (!shapeGenStrokeRle(*shape, sdata, clip)) return shape; } } } - shapeDelOutline(*sdata); + shapeDelOutline(*shape); - return sdata; + return shape; } @@ -159,4 +154,4 @@ SwRenderer* SwRenderer::inst() return dynamic_cast(RenderInitializer::inst(renderInit)); } -#endif /* _TVG_SW_RENDERER_CPP_ */ \ No newline at end of file +#endif /* _TVG_SW_RENDERER_CPP_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 30b79c86..dcb57c71 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -23,48 +23,164 @@ /* Internal Class Implementation */ /************************************************************************/ +struct Line +{ + Point pt1; + Point pt2; +}; + + +struct Bezier +{ + Point start; + Point ctrl1; + Point ctrl2; + Point end; +}; + + +static float _lineLength(const Point& pt1, const Point& pt2) +{ + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + if (diff.x < 0) diff.x = -diff.x; + if (diff.y < 0) diff.y = -diff.y; + return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); +} + + +static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right) +{ + auto len = _lineLength(cur.pt1, cur.pt2); + auto dx = ((cur.pt2.x - cur.pt1.x) / len) * at; + auto dy = ((cur.pt2.y - cur.pt1.y) / len) * at; + left.pt1 = cur.pt1; + left.pt2.x = left.pt1.x + dx; + left.pt2.y = left.pt1.y + dy; + right.pt1 = left.pt2; + right.pt2 = cur.pt2; +} + + +static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +{ + auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; + left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; + right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; + left.start.x = cur.start.x; + right.end.x = cur.end.x; + left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; + right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; + left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; + + c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; + left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; + right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; + left.start.y = cur.start.y; + right.end.y = cur.end.y; + left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; + right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; + left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; +} + + +static float _bezLength(const Bezier& cur) +{ + Bezier left, right; + auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); + auto chord = _lineLength(cur.start, cur.end); + + if (fabs(len - chord) > FLT_EPSILON) { + _bezSplit(cur, left, right); + return _bezLength(left) + _bezLength(right); + } + return len; +} + + +static void _bezSplitLeft(Bezier& cur, float at, Bezier& left) +{ + left.start = cur.start; + + left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); + left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); + + left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot + left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot + + cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); + cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); + + cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); + cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); + + left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); + left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); + + left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); + left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); +} + + +static float _bezAt(const Bezier& bz, float at) +{ + auto len = _bezLength(bz); + auto biggest = 1.0f; + + if (at >= len) return 1.0f; + + at *= 0.5f; + + while (true) { + auto right = bz; + Bezier left; + _bezSplitLeft(right, at, left); + auto len2 = _bezLength(left); + + if (fabs(len2 - len) < FLT_EPSILON) break; + + if (len2 < len) { + at += (biggest - at) * 0.5f; + } else { + biggest = at; + at -= (at * 0.5f); + } + } + return at; +} + + +static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) +{ + right = cur; + auto t = _bezAt(right, at); + _bezSplitLeft(right, t, left); +} + + static void _growOutlineContour(SwOutline& outline, uint32_t n) { - if (n == 0) { - free(outline.cntrs); - outline.cntrs = nullptr; - outline.cntrsCnt = 0; - outline.reservedCntrsCnt = 0; - return; - } if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; - - //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;; - outline.reservedCntrsCnt = n; - outline.cntrs = static_cast(realloc(outline.cntrs, n * sizeof(uint32_t))); + outline.reservedCntrsCnt = outline.cntrsCnt + n; + outline.cntrs = static_cast(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t))); assert(outline.cntrs); } static void _growOutlinePoint(SwOutline& outline, uint32_t n) { - if (n == 0) { - free(outline.pts); - outline.pts = nullptr; - free(outline.types); - outline.types = nullptr; - outline.reservedPtsCnt = 0; - outline.ptsCnt = 0; - return; - } - if (outline.reservedPtsCnt >= outline.ptsCnt + n) return; - - //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl; - outline.reservedPtsCnt = n; - outline.pts = static_cast(realloc(outline.pts, n * sizeof(SwPoint))); + outline.reservedPtsCnt = outline.ptsCnt + n; + outline.pts = static_cast(realloc(outline.pts, outline.reservedPtsCnt * sizeof(SwPoint))); assert(outline.pts); - outline.types = static_cast(realloc(outline.types, n * sizeof(uint8_t))); + outline.types = static_cast(realloc(outline.types, outline.reservedPtsCnt * sizeof(uint8_t))); assert(outline.types); } -static void _freeOutline(SwOutline* outline) +static void _delOutline(SwOutline* outline) { if (!outline) return; @@ -112,7 +228,6 @@ static void _outlineLineTo(SwOutline& outline, const Point* to) outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; - ++outline.ptsCnt; } @@ -208,80 +323,271 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) } -static bool _checkValid(SwShape& sdata, const SwSize& clip) +static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) { - assert(sdata.outline); + assert(outline); - if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) return false; + if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; //Check boundary - if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) || - (sdata.bbox.min.x + sdata.bbox.max.x < 0) || - (sdata.bbox.min.y + sdata.bbox.max.y < 0)) return false; + if ((bbox.min.x > clip.w || bbox.min.y > clip.h) || + (bbox.min.x + bbox.max.x < 0) || + (bbox.min.y + bbox.max.y < 0)) return false; return true; } +static void _transformOutline(SwOutline* outline, const RenderTransform* transform) +{ + assert(outline); + + if (!transform) return; + + for(uint32_t i = 0; i < outline->ptsCnt; ++i) { + auto dx = static_cast(outline->pts[i].x >> 6); + auto dy = static_cast(outline->pts[i].y >> 6); + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23; + auto pt = Point{tx + transform->e31, ty + transform->e32}; + outline->pts[i] = TO_SWPOINT(&pt); + } +} + + +static void _dashLineTo(SwDashStroke& dash, const Point* to) +{ + _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); + _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); + + Line cur = {dash.ptCur, *to}; + auto len = _lineLength(cur.pt1, cur.pt2); + + if (len < dash.curLen) { + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &dash.ptCur); + _outlineLineTo(*dash.outline, to); + } + } else { + while (len > dash.curLen) { + len -= dash.curLen; + Line left, right; + _lineSplitAt(cur, dash.curLen, left, right);; + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &left.pt1); + _outlineLineTo(*dash.outline, &left.pt2); + } + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + cur = right; + dash.ptCur = cur.pt1; + } + //leftovers + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &cur.pt1); + _outlineLineTo(*dash.outline, &cur.pt2); + } + if (dash.curLen < 1) { + //move to next dash + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + } + } + dash.ptCur = *to; +} + + +static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to) +{ + _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); + _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); + + Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to}; + auto len = _bezLength(cur); + + if (len < dash.curLen) { + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &dash.ptCur); + _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to); + } + } else { + while (len > dash.curLen) { + Bezier left, right; + len -= dash.curLen; + _bezSplitAt(cur, dash.curLen, left, right); + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &left.start); + _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end); + } + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + cur = right; + dash.ptCur = right.start; + } + //leftovers + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &cur.start); + _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end); + } + if (dash.curLen < 1) { + //move to next dash + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + } + } + dash.ptCur = *to; +} + + +SwOutline* _genDashOutline(const Shape& shape) +{ + const PathCommand* cmds = nullptr; + auto cmdCnt = shape.pathCommands(&cmds); + + const Point* pts = nullptr; + auto ptsCnt = shape.pathCoords(&pts); + + //No actual shape data + if (cmdCnt == 0 || ptsCnt == 0) return nullptr; + + SwDashStroke dash; + dash.curIdx = 0; + dash.curLen = 0; + dash.ptStart = {0, 0}; + dash.ptCur = {0, 0}; + dash.curOpGap = false; + + const float* pattern; + dash.cnt = shape.strokeDash(&pattern); + assert(dash.cnt > 0 && pattern); + + //Is it safe to mutual exclusive? + dash.pattern = const_cast(pattern); + dash.outline = static_cast(calloc(1, sizeof(SwOutline))); + assert(dash.outline); + dash.outline->opened = true; + + //smart reservation + auto outlinePtsCnt = 0; + auto outlineCntrsCnt = 0; + + for (uint32_t i = 0; i < cmdCnt; ++i) { + switch(*(cmds + i)) { + case PathCommand::Close: { + ++outlinePtsCnt; + break; + } + case PathCommand::MoveTo: { + ++outlineCntrsCnt; + ++outlinePtsCnt; + break; + } + case PathCommand::LineTo: { + ++outlinePtsCnt; + break; + } + case PathCommand::CubicTo: { + outlinePtsCnt += 3; + break; + } + } + } + + ++outlinePtsCnt; //for close + ++outlineCntrsCnt; //for end + + //Reserve Approximitely 20x... + _growOutlinePoint(*dash.outline, outlinePtsCnt * 20); + _growOutlineContour(*dash.outline, outlineCntrsCnt * 20); + + while (cmdCnt-- > 0) { + switch(*cmds) { + case PathCommand::Close: { + _dashLineTo(dash, &dash.ptStart); + break; + } + case PathCommand::MoveTo: { + //reset the dash + dash.curIdx = 0; + dash.curLen = *dash.pattern; + dash.curOpGap = false; + dash.ptStart = dash.ptCur = *pts; + ++pts; + break; + } + case PathCommand::LineTo: { + _dashLineTo(dash, pts); + ++pts; + break; + } + case PathCommand::CubicTo: { + _dashCubicTo(dash, pts, pts + 1, pts + 2); + pts += 3; + break; + } + } + ++cmds; + } + + _outlineEnd(*dash.outline); + + return dash.outline; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform) +bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform) { - auto outline = sdata.outline; - assert(outline); + if (!shapeGenOutline(shape, sdata)) return false; - for(uint32_t i = 0; i < outline->ptsCnt; ++i) { - auto dx = static_cast(outline->pts[i].x >> 6); - auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13; - auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23; - auto pt = Point{tx + transform.e31, ty + transform.e32}; - outline->pts[i] = TO_SWPOINT(&pt); - } -} + _transformOutline(shape.outline, transform); + if (!_updateBBox(shape.outline, shape.bbox)) goto end; -bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) -{ - /* OPTIMIZE ME: We may avoid this bounding box calculation in this stage - if this shape has stroke and stroke bbox can be used here... */ - if (!_updateBBox(sdata.outline, sdata.bbox)) goto end; - if (!_checkValid(sdata, clip)) goto end; - - sdata.rle = rleRender(sdata.outline, sdata.bbox, clip); + if (!_checkValid(shape.outline, shape.bbox, clip)) goto end; + shape.rle = rleRender(shape.outline, shape.bbox, clip); end: - if (sdata.rle) return true; + if (shape.rle) return true; return false; } -void shapeDelOutline(SwShape& sdata) +void shapeDelOutline(SwShape& shape) { - auto outline = sdata.outline; - _freeOutline(outline); - sdata.outline = nullptr; + auto outline = shape.outline; + _delOutline(outline); + shape.outline = nullptr; } -void shapeReset(SwShape& sdata) +void shapeReset(SwShape& shape) { - shapeDelOutline(sdata); - rleFree(sdata.rle); - sdata.rle = nullptr; - _initBBox(sdata.bbox); + shapeDelOutline(shape); + rleFree(shape.rle); + shape.rle = nullptr; + _initBBox(shape.bbox); } -bool shapeGenOutline(const Shape& shape, SwShape& sdata) +bool shapeGenOutline(SwShape& shape, const Shape& sdata) { const PathCommand* cmds = nullptr; - auto cmdCnt = shape.pathCommands(&cmds); + auto cmdCnt = sdata.pathCommands(&cmds); const Point* pts = nullptr; - auto ptsCnt = shape.pathCoords(&pts); + auto ptsCnt = sdata.pathCoords(&pts); //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return false; @@ -315,7 +621,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) ++outlinePtsCnt; //for close ++outlineCntrsCnt; //for end - auto outline = sdata.outline; + auto outline = shape.outline; if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); assert(outline); outline->opened = true; @@ -354,7 +660,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) //FIXME: //outline->flags = SwOutline::FillRule::Winding; - sdata.outline = outline; + shape.outline = outline; return true; } @@ -376,38 +682,52 @@ void shapeFree(SwShape* sdata) } -void shapeResetStroke(const Shape& shape, SwShape& sdata) +void shapeResetStroke(SwShape& shape, const Shape& sdata) { - if (!sdata.stroke) sdata.stroke = static_cast(calloc(1, sizeof(SwStroke))); - auto stroke = sdata.stroke; + if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); + auto stroke = shape.stroke; assert(stroke); - strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin()); - rleFree(sdata.strokeRle); - sdata.strokeRle = nullptr; + + strokeReset(*stroke, sdata); + + rleFree(shape.strokeRle); + shape.strokeRle = nullptr; } -bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip) +bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) { - if (!sdata.outline) { - if (!shapeGenOutline(shape, sdata)) return false; + SwOutline* shapeOutline = nullptr; + + //Dash Style Stroke + if (sdata.strokeDash(nullptr) > 0) { + shapeOutline = _genDashOutline(sdata); + if (!shapeOutline) return false; + + //Normal Style stroke + } else { + if (!shape.outline) { + if (!shapeGenOutline(shape, sdata)) return false; + } + shapeOutline = shape.outline; } - if (!_checkValid(sdata, clip)) return false; + if (!strokeParseOutline(*shape.stroke, *shapeOutline)) return false; - if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false; - - auto outline = strokeExportOutline(*sdata.stroke); - if (!outline) return false; + auto strokeOutline = strokeExportOutline(*shape.stroke); + if (!strokeOutline) return false; SwBBox bbox; - _updateBBox(outline, bbox); + _updateBBox(strokeOutline, bbox); - sdata.strokeRle = rleRender(outline, bbox, clip); + if (!_checkValid(strokeOutline, bbox, clip)) return false; - _freeOutline(outline); + shape.strokeRle = rleRender(strokeOutline, bbox, clip); + + _delOutline(strokeOutline); return true; } + #endif /* _TVG_SW_SHAPE_H_ */ diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 06ec989d..fdc8caef 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -351,7 +351,7 @@ void _processCorner(SwStroke& stroke, SwFixed lineLength) } -void _subPathStart(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) +void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { SwPoint delta = {stroke.width, 0}; mathRotate(delta, startAngle + ANGLE_PI2); @@ -390,7 +390,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) if (stroke.firstPt) { /* This is the first segment of a subpath. We need to add a point to each border at their respective starting point locations. */ - _subPathStart(stroke, angle, lineLength); + _firstSubPath(stroke, angle, lineLength); } else { //process the current corner stroke.angleOut = angle; @@ -455,7 +455,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl firstArc = false; //process corner if necessary if (stroke.firstPt) { - _subPathStart(stroke, angleIn, 0); + _firstSubPath(stroke, angleIn, 0); } else { stroke.angleOut = angleIn; _processCorner(stroke, 0); @@ -566,7 +566,6 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) SwPoint delta2 = {stroke.width, 0}; mathRotate(delta2, angle + rotate); - delta += stroke.center + delta2; _borderLineTo(border, delta, false); @@ -660,26 +659,26 @@ static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) stroke.firstPt = true; stroke.center = to; - stroke.subPathOpen = opened; + stroke.openSubPath = opened; /* Determine if we need to check whether the border radius is greater than the radius of curvature of a curve, to handle this case specially. This is only required if bevel joins or butt caps may be created because round & miter joins and round & square caps cover the nagative sector created with wide strokes. */ - if ((stroke.join != StrokeJoin::Round) || (stroke.subPathOpen && stroke.cap == StrokeCap::Butt)) + if ((stroke.join != StrokeJoin::Round) || (stroke.openSubPath && stroke.cap == StrokeCap::Butt)) stroke.handleWideStrokes = true; else stroke.handleWideStrokes = false; - stroke.subPathStart = to; + stroke.ptStartSubPath = to; stroke.angleIn = 0; } static void _endSubPath(SwStroke& stroke) { - if (stroke.subPathOpen) { + if (stroke.openSubPath) { auto right = stroke.borders; assert(right); @@ -692,7 +691,7 @@ static void _endSubPath(SwStroke& stroke) _addReverseLeft(stroke, true); //now add the final cap - stroke.center = stroke.subPathStart; + stroke.center = stroke.ptStartSubPath; _addCap(stroke, stroke.subPathAngle + ANGLE_PI, 0); /* now end the right subpath accordingly. The left one is rewind @@ -701,8 +700,8 @@ static void _endSubPath(SwStroke& stroke) } else { //close the path if needed - if (stroke.center != stroke.subPathStart) - _lineTo(stroke, stroke.subPathStart); + if (stroke.center != stroke.ptStartSubPath) + _lineTo(stroke, stroke.ptStartSubPath); //process the corner stroke.angleOut = stroke.subPathAngle; @@ -792,7 +791,6 @@ static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t ++cntrs; ++outline->cntrsCnt; } - ++src; ++tags; ++idx; @@ -820,13 +818,13 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) +void strokeReset(SwStroke& stroke, const Shape& shape) { - stroke.width = TO_SWCOORD(width * 0.5); - stroke.cap = cap; + stroke.width = TO_SWCOORD(shape.strokeWidth() * 0.5); + stroke.cap = shape.strokeCap(); //Save line join: it can be temporarily changed when stroking curves... - stroke.joinSaved = stroke.join = join; + stroke.joinSaved = stroke.join = shape.strokeJoin(); stroke.borders[0].ptsCnt = 0; stroke.borders[0].start = -1; @@ -838,7 +836,7 @@ void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) } -bool strokeParseOutline(SwStroke& stroke, SwOutline& outline) +bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) { uint32_t first = 0; @@ -926,5 +924,4 @@ SwOutline* strokeExportOutline(SwStroke& stroke) return outline; } - #endif /* _TVG_SW_STROKER_H_ */ diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 828e251e..67d5ab78 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -328,7 +328,7 @@ int Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noe } -int Shape::stroke(const size_t* dashPattern, size_t cnt) noexcept +int Shape::stroke(const float* dashPattern, size_t cnt) noexcept { if (cnt < 2 || !dashPattern) return -1; @@ -341,7 +341,7 @@ int Shape::stroke(const size_t* dashPattern, size_t cnt) noexcept } -size_t Shape::strokeDash(const size_t** dashPattern) const noexcept +size_t Shape::strokeDash(const float** dashPattern) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index e1a4e9f7..09956be9 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -32,7 +32,7 @@ struct ShapeStroke { float width = 0; uint8_t color[4] = {0, 0, 0, 0}; - size_t* dashPattern = nullptr; + float* dashPattern = nullptr; size_t dashCnt = 0; StrokeCap cap = StrokeCap::Square; StrokeJoin join = StrokeJoin::Bevel; @@ -203,7 +203,7 @@ struct Shape::Impl return 0; } - bool strokeDash(const size_t* pattern, size_t cnt) + bool strokeDash(const float* pattern, size_t cnt) { assert(pattern); @@ -215,12 +215,13 @@ struct Shape::Impl stroke->dashPattern = nullptr; } - if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(size_t) * cnt)); + if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); assert(stroke->dashPattern); - memcpy(stroke->dashPattern, pattern, cnt); - stroke->dashCnt = cnt; + for (size_t i = 0; i < cnt; ++i) + stroke->dashPattern[i] = pattern[i]; + stroke->dashCnt = cnt; flag |= RenderUpdateFlag::Stroke; return 0; diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 8687b850..1288c075 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -17,6 +17,7 @@ void tvgtest() 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(); shape->moveTo(50, 50 + (25 * i)); @@ -27,6 +28,8 @@ void tvgtest() canvas->push(move(shape)); } + + //Test for StrokeJoin & StrokeCap auto shape1 = tvg::Shape::gen(); shape1->moveTo(20, 350); shape1->lineTo(250, 350); @@ -63,6 +66,52 @@ void tvgtest() shape3->stroke(tvg::StrokeCap::Butt); canvas->push(move(shape3)); + //Test for Stroke Dash + auto shape4 = tvg::Shape::gen(); + shape4->moveTo(20, 600); + shape4->lineTo(250, 600); + shape4->lineTo(220, 750); + shape4->lineTo(70, 720); + shape4->lineTo(70, 580); + shape4->stroke(255, 0, 0, 255); + shape4->stroke(5); + shape4->stroke(tvg::StrokeJoin::Round); + shape4->stroke(tvg::StrokeCap::Round); + + float dashPattern1[2] = {10, 10}; + shape4->stroke(dashPattern1, 2); + canvas->push(move(shape4)); + + auto shape5 = tvg::Shape::gen(); + shape5->moveTo(270, 600); + shape5->lineTo(500, 600); + shape5->lineTo(470, 750); + shape5->lineTo(320, 720); + shape5->lineTo(320, 580); + shape5->stroke(255, 255, 0, 255); + shape5->stroke(5); + shape5->stroke(tvg::StrokeJoin::Bevel); + shape5->stroke(tvg::StrokeCap::Butt); + + float dashPattern2[4] = {10, 10}; + shape5->stroke(dashPattern2, 4); + canvas->push(move(shape5)); + + auto shape6 = tvg::Shape::gen(); + shape6->moveTo(520, 600); + shape6->lineTo(750, 600); + shape6->lineTo(720, 750); + shape6->lineTo(570, 720); + shape6->lineTo(570, 580); + shape6->stroke(255, 255, 255, 255); + shape6->stroke(5); + shape6->stroke(tvg::StrokeJoin::Miter); + shape6->stroke(tvg::StrokeCap::Square); + + float dashPattern3[2] = {10, 10}; + shape6->stroke(dashPattern3, 2); + canvas->push(move(shape6)); + canvas->draw(); canvas->sync(); From 4e3f8284e8c02ba83587f16385e93ccce5a5439f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 11:02:51 +0900 Subject: [PATCH 080/244] sw_engine: grow cell memory buffer up to allow larger shapes Change-Id: I7a8feaa11d3dad81dd1004782e07a8ac4a768d91 --- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 2757c0da..cab54631 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -633,7 +633,7 @@ static bool _genRle(RleWorker& rw) ret = _decomposeOutline(rw); if (!rw.invalid) _recordCell(rw); } else { - cout << "Memory Overflow" << endl; + cout << "Lack of Cell Memory" << endl; } return ret; } @@ -647,7 +647,7 @@ static bool _genRle(RleWorker& rw) SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) { //Please adjust when you out of cell memory (default: 16384L) - constexpr auto RENDER_POOL_SIZE = 166641L; + constexpr auto RENDER_POOL_SIZE = 163840L * 2; constexpr auto BAND_SIZE = 40; assert(outline); From 33e1d4b170a52e07517d6e95791da5c30eb59044 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 14:18:58 +0900 Subject: [PATCH 081/244] common interface: concrete return type. Introduce Result type for notifying caller more detailed info. We should implement the result values for each apis, with practical values. Change-Id: Ia47abcb56a8efca7094ac3eed0178aeac8aa2910 --- inc/tizenvg.h | 87 ++++++++-------- src/lib/sw_engine/tvgSwRenderer.cpp | 4 +- src/lib/tvgCanvas.cpp | 27 +++-- src/lib/tvgCanvasImpl.h | 36 +++---- src/lib/tvgEngine.cpp | 8 +- src/lib/tvgGlCanvas.cpp | 12 +-- src/lib/tvgScene.cpp | 46 +++++---- src/lib/tvgSceneImpl.h | 26 ++--- src/lib/tvgShape.cpp | 155 +++++++++++++++------------- src/lib/tvgShapeImpl.h | 49 +++++---- src/lib/tvgSwCanvas.cpp | 12 +-- 11 files changed, 238 insertions(+), 224 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 18db8427..16e60f0f 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -53,6 +53,7 @@ protected: \ namespace tvg { +enum class TIZENVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; @@ -79,11 +80,11 @@ class TIZENVG_EXPORT Paint public: virtual ~Paint() {} - virtual int rotate(float degree) = 0; - virtual int scale(float factor) = 0; - virtual int translate(float x, float y) = 0; + virtual Result rotate(float degree) = 0; + virtual Result scale(float factor) = 0; + virtual Result translate(float x, float y) = 0; - virtual int bounds(float* x, float* y, float* w, float* h) const = 0; + virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; }; @@ -101,13 +102,13 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); - int reserve(size_t n) noexcept; - virtual int push(std::unique_ptr paint) noexcept; - virtual int clear() noexcept; - virtual int update() noexcept; - virtual int update(Paint* paint) noexcept; - virtual int draw(bool async = true) noexcept; - virtual int sync() = 0; + Result reserve(size_t n) noexcept; + virtual Result push(std::unique_ptr paint) noexcept; + virtual Result clear() noexcept; + virtual Result update() noexcept; + virtual Result update(Paint* paint) noexcept; + virtual Result draw(bool async = true) noexcept; + virtual Result sync() = 0; _TIZENVG_DECLARE_ACCESSOR(Scene); _TIZENVG_DECLARE_PRIVATE(Canvas); @@ -127,42 +128,42 @@ class TIZENVG_EXPORT Shape final : public Paint public: ~Shape(); - int reset() noexcept; + Result reset() noexcept; //Path - int moveTo(float x, float y) noexcept; - int lineTo(float x, float y) noexcept; - int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; - int close() noexcept; + Result moveTo(float x, float y) noexcept; + Result lineTo(float x, float y) noexcept; + Result cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; + Result close() noexcept; //Shape - int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; - int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; - int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; + Result appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; + Result appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; + Result appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; //Stroke - int stroke(float width) noexcept; - int stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; - int stroke(const float* dashPattern, size_t cnt) noexcept; - int stroke(StrokeCap cap) noexcept; - int stroke(StrokeJoin join) noexcept; + Result stroke(float width) noexcept; + Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + Result stroke(const float* dashPattern, size_t cnt) noexcept; + Result stroke(StrokeCap cap) noexcept; + Result stroke(StrokeJoin join) noexcept; //Fill - int fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + Result fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; //Transform - int rotate(float degree) noexcept override; - int scale(float factor) noexcept override; - int translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept override; + Result scale(float factor) noexcept override; + Result translate(float x, float y) noexcept override; //Getters size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; - int fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; - int bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; + Result bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; - int strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; + Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; size_t strokeDash(const float** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; @@ -188,14 +189,14 @@ class TIZENVG_EXPORT Scene final : public Paint public: ~Scene(); - int push(std::unique_ptr shape) noexcept; - int reserve(size_t size) noexcept; + Result push(std::unique_ptr shape) noexcept; + Result reserve(size_t size) noexcept; - int rotate(float degree) noexcept override; - int scale(float factor) noexcept override; - int translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept override; + Result scale(float factor) noexcept override; + Result translate(float x, float y) noexcept override; - int bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result bounds(float* x, float* y, float* w, float* h) const noexcept override; static std::unique_ptr gen() noexcept; @@ -217,8 +218,8 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; - int sync() noexcept override; + Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result sync() noexcept override; static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(SwCanvas); @@ -240,8 +241,8 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. - int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; - int sync() noexcept override; + Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result sync() noexcept override; static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(GlCanvas); @@ -270,8 +271,8 @@ public: * * @see ... */ - static int init() noexcept; - static int term() noexcept; + static Result init() noexcept; + static Result term() noexcept; _TIZENVG_DISABLE_CTOR(Engine); }; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 5461abea..60c3a6d7 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -47,7 +47,7 @@ bool SwRenderer::clear() bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) { - assert(buffer && stride > 0 && w > 0 && h > 0); + if (!buffer || stride == 0 || w == 0 || h == 0) return false; surface.buffer = buffer; surface.stride = stride; @@ -77,7 +77,7 @@ bool SwRenderer::render(const Shape& shape, void *data) bool SwRenderer::dispose(const Shape& shape, void *data) { auto sdata = static_cast(data); - if (!sdata) return false; + if (!sdata) return true; shapeFree(sdata); return true; } diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index f31373e4..79057c77 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -34,52 +34,51 @@ Canvas::~Canvas() } -int Canvas::reserve(size_t n) noexcept +Result Canvas::reserve(size_t n) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; impl->paints.reserve(n); - return 0; + return Result::Success; } -int Canvas::push(unique_ptr paint) noexcept +Result Canvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); - assert(impl); - + if (!impl) return Result::MemoryCorruption; return impl->push(move(paint)); } -int Canvas::clear() noexcept +Result Canvas::clear() noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->clear(); } -int Canvas::draw(bool async) noexcept +Result Canvas::draw(bool async) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->draw(); } -int Canvas::update() noexcept +Result Canvas::update() noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->update(); } -int Canvas::update(Paint* paint) noexcept +Result Canvas::update(Paint* paint) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->update(paint); } diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index afa2a0b1..782dd94a 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -39,7 +39,7 @@ struct Canvas::Impl renderer->unref(); } - int push(unique_ptr paint) + Result push(unique_ptr paint) { auto p = paint.release(); assert(p); @@ -48,64 +48,64 @@ struct Canvas::Impl return update(p); } - int clear() + Result clear() { assert(renderer); for (auto paint : paints) { if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->clear(*renderer)) return -1; + if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->dispose(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->dispose(*shape, *renderer)) return Result::InsufficientCondition; } delete(paint); } paints.clear(); - return 0; + return Result::Success; } - int update() + Result update() { assert(renderer); for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->update(*renderer, nullptr)) return -1; + if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return Result::InsufficientCondition; } } - return 0; + return Result::Success; } - int update(Paint* paint) + Result update(Paint* paint) { assert(renderer); if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->update(*renderer)) return -1; + if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->update(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer)) return Result::InsufficientCondition; } - return 0; + return Result::Success; } - int draw() + Result draw() { assert(renderer); //Clear render target before drawing - if (!renderer->clear()) return -1; + if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - if(!SCENE_IMPL->render(*renderer)) return -1; + if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if(!SHAPE_IMPL->render(*shape, *renderer)) return -1; + if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; } } - return 0; + return Result::Success; } }; diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index fa005dc0..40b13081 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -30,7 +30,7 @@ /* External Class Implementation */ /************************************************************************/ -int Engine::init() noexcept +Result Engine::init() noexcept { //TODO: Initialize Raster engines by configuration. @@ -38,17 +38,17 @@ int Engine::init() noexcept ret |= SwRenderer::init(); ret |= GlRenderer::init(); - return ret; + return Result::Success; } -int Engine::term() noexcept +Result Engine::term() noexcept { int ret = 0; ret |= SwRenderer::term(); ret |= GlRenderer::term(); - return ret; + return Result::Success; } #endif /* _TVG_ENGINE_CPP_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index c1b7aeb5..2bf38688 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -45,20 +45,20 @@ GlCanvas::~GlCanvas() } -int GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); - assert(renderer); + if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return -1; + if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; - return 0; + return Result::Success; } -int GlCanvas::sync() noexcept +Result GlCanvas::sync() noexcept { - return 0; + return Result::Success; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 93a64b1c..12b96ec2 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -40,65 +40,71 @@ unique_ptr Scene::gen() noexcept } -int Scene::push(unique_ptr paint) noexcept +Result Scene::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; auto p = paint.release(); - assert(p); + if (!p) return Result::MemoryCorruption; impl->paints.push_back(p); - return 0; + return Result::Success; } -int Scene::reserve(size_t size) noexcept +Result Scene::reserve(size_t size) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; impl->paints.reserve(size); - return 0; + return Result::Success; } -int Scene::scale(float factor) noexcept +Result Scene::scale(float factor) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->scale(factor); + if (!impl->scale(factor)) return Result::FailedAllocation; + + return Result::Success; } -int Scene::rotate(float degree) noexcept +Result Scene::rotate(float degree) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->rotate(degree); + if (!impl->rotate(degree)) return Result::FailedAllocation; + + return Result::Success; } -int Scene::translate(float x, float y) noexcept +Result Scene::translate(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->translate(x, y); + if (!impl->translate(x, y)) return Result::FailedAllocation; + + return Result::Success; } -int Scene::bounds(float* x, float* y, float* w, float* h) const noexcept +Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->bounds(x, y, w, h)) return -1; + if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - return 0; + return Result::Success; } #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 9064b533..a08afc64 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -66,7 +66,7 @@ struct Scene::Impl bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { - assert(transform); + if (!transform) return false; if (!transform->update()) { delete(transform); transform = nullptr; @@ -137,47 +137,47 @@ struct Scene::Impl bool scale(float factor) { if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1; + if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; } else { - if (fabsf(factor) <= FLT_EPSILON) return -1; + if (fabsf(factor) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->factor = factor; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool rotate(float degree) { if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1; + if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; } else { - if (fabsf(degree) <= FLT_EPSILON) return -1; + if (fabsf(degree) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->degree = degree; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool translate(float x, float y) { if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1; + if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1; + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->x = x; transform->y = y; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } }; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 67d5ab78..c41c6b12 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -46,23 +46,25 @@ unique_ptr Shape::gen() noexcept } -int Shape::reset() noexcept +Result Shape::reset() noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->reset(); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } size_t Shape::pathCommands(const PathCommand** cmds) const noexcept { + if (!cmds) return 0; + auto impl = pImpl.get(); - assert(impl && impl->path && cmds); + if (!impl || !impl->path) return 0; *cmds = impl->path->cmds; @@ -72,8 +74,10 @@ size_t Shape::pathCommands(const PathCommand** cmds) const noexcept size_t Shape::pathCoords(const Point** pts) const noexcept { + if (!pts) return 0; + auto impl = pImpl.get(); - assert(impl && impl->path && pts); + if (!impl || !impl->path) return 0; *pts = impl->path->pts; @@ -81,79 +85,78 @@ size_t Shape::pathCoords(const Point** pts) const noexcept } -int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +Result Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept { - if (cmdCnt < 0 || ptsCnt < 0) return -1; - assert(cmds && pts); + if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments; auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::moveTo(float x, float y) noexcept +Result Shape::moveTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->moveTo(x, y); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::lineTo(float x, float y) noexcept +Result Shape::lineTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->lineTo(x, y); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept +Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::close() noexcept +Result Shape::close() noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->close(); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept +Result Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; auto halfKappaW = radiusW * PATH_KAPPA; auto halfKappaH = radiusH * PATH_KAPPA; @@ -168,14 +171,14 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept +Result Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; //clamping cornerRadius by minimum size auto min = (w < h ? w : h) * 0.5f; @@ -209,14 +212,14 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept +Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; impl->color[0] = r; impl->color[1] = g; @@ -224,120 +227,126 @@ int Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept impl->color[3] = a; impl->flag |= RenderUpdateFlag::Fill; - return 0; + return Result::Success; } -int Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept +Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; if (r) *r = impl->color[0]; if (g) *g = impl->color[1]; if (b) *b = impl->color[2]; if (a) *a = impl->color[3]; - return 0; + return Result::Success; } -int Shape::scale(float factor) noexcept +Result Shape::scale(float factor) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->scale(factor); + if (!impl->scale(factor)) return Result::FailedAllocation; + + return Result::Success; } -int Shape::rotate(float degree) noexcept +Result Shape::rotate(float degree) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->rotate(degree); + if (!impl->rotate(degree)) return Result::FailedAllocation; + + return Result::Success; } -int Shape::translate(float x, float y) noexcept +Result Shape::translate(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->translate(x, y); + impl->translate(x, y); + + return Result::Success; } -int Shape::bounds(float* x, float* y, float* w, float* h) const noexcept +Result Shape::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->bounds(x, y, w, h)) return -1; + if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - return 0; + return Result::Success; } -int Shape::stroke(float width) noexcept +Result Shape::stroke(float width) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeWidth(width)) return -1; + if (!impl->strokeWidth(width)) return Result::FailedAllocation; - return 0; + return Result::Success; } float Shape::strokeWidth() const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return 0; if (!impl->stroke) return 0; return impl->stroke->width; } -int Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept +Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeColor(r, g, b, a)) return -1; + if (!impl->strokeColor(r, g, b, a)) return Result::FailedAllocation; - return 0; + return Result::Success; } -int Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept +Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->stroke) return -1; + if (!impl->stroke) return Result::InsufficientCondition; if (r) *r = impl->stroke->color[0]; if (g) *g = impl->stroke->color[1]; if (b) *b = impl->stroke->color[2]; if (a) *a = impl->stroke->color[3]; - return 0; + return Result::Success; } -int Shape::stroke(const float* dashPattern, size_t cnt) noexcept +Result Shape::stroke(const float* dashPattern, size_t cnt) noexcept { - if (cnt < 2 || !dashPattern) return -1; + if (cnt < 2 || !dashPattern) return Result::InvalidArguments; auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeDash(dashPattern, cnt)) return -1; + if (!impl->strokeDash(dashPattern, cnt)) return Result::FailedAllocation; - return 0; + return Result::Success; } @@ -353,25 +362,25 @@ size_t Shape::strokeDash(const float** dashPattern) const noexcept } -int Shape::stroke(StrokeCap cap) noexcept +Result Shape::stroke(StrokeCap cap) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeCap(cap)) return -1; + if (!impl->strokeCap(cap)) return Result::FailedAllocation; - return 0; + return Result::Success; } -int Shape::stroke(StrokeJoin join) noexcept +Result Shape::stroke(StrokeJoin join) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeJoin(join)) return -1; + if (!impl->strokeJoin(join)) return Result::FailedAllocation; - return 0; + return Result::Success; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 09956be9..92184171 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -80,7 +80,7 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { - assert(transform); + if (!transform) return false; if (!transform->update()) { delete(transform); transform = nullptr; @@ -103,54 +103,54 @@ struct Shape::Impl bool bounds(float* x, float* y, float* w, float* h) { - assert(path); + if (!path) return false; return path->bounds(x, y, w, h); } bool scale(float factor) { if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1; + if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; } else { - if (fabsf(factor) <= FLT_EPSILON) return -1; + if (fabsf(factor) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->factor = factor; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool rotate(float degree) { if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1; + if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; } else { - if (fabsf(degree) <= FLT_EPSILON) return -1; + if (fabsf(degree) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->degree = degree; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool translate(float x, float y) { if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1; + if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1; + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->x = x; transform->y = y; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool strokeWidth(float width) @@ -158,40 +158,40 @@ struct Shape::Impl //TODO: Size Exception? if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->width = width; flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeCap(StrokeCap cap) { if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->cap = cap; flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeJoin(StrokeJoin join) { if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->join = join; flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->color[0] = r; stroke->color[1] = g; @@ -200,7 +200,7 @@ struct Shape::Impl flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeDash(const float* pattern, size_t cnt) @@ -208,7 +208,7 @@ struct Shape::Impl assert(pattern); if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; if (stroke->dashCnt != cnt) { if (stroke->dashPattern) free(stroke->dashPattern); @@ -224,8 +224,7 @@ struct Shape::Impl stroke->dashCnt = cnt; flag |= RenderUpdateFlag::Stroke; - return 0; - + return true; } }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index ea95e987..ec18dbf5 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,20 +45,20 @@ SwCanvas::~SwCanvas() { } -int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); - assert(renderer); + if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return -1; + if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; - return 0; + return Result::Success; } -int SwCanvas::sync() noexcept +Result SwCanvas::sync() noexcept { - return 0; + return Result::Success; } From 58de99aea32d76242e4f875918c0608848aac233 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 15:22:33 +0900 Subject: [PATCH 082/244] common interface: replace arguements size_t to uint32_t We prefer to build up a tiny compact engine at memory rather than compatibility, this engine is not considerd for end-users but designed for middle-level framework and some low-level users. Thus, we won't consider 64bits data size, use explicit 32 bits data until coming next upgrade... Change-Id: I0704d5f1e0eb909cccc10922bc5972e115fbbcc0 --- inc/tizenvg.h | 18 +++++++++--------- src/lib/gl_engine/tvgGlGpuBuffer.h | 4 ++-- src/lib/gl_engine/tvgGlRenderer.cpp | 4 ++-- src/lib/gl_engine/tvgGlRenderer.h | 6 +++--- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +++--- src/lib/sw_engine/tvgSwRenderer.h | 6 +++--- src/lib/tvgCanvas.cpp | 2 +- src/lib/tvgGlCanvas.cpp | 2 +- src/lib/tvgRenderCommon.h | 14 +++++++------- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 6 +++--- src/lib/tvgShape.cpp | 10 +++++----- src/lib/tvgShapeImpl.h | 10 +++++----- src/lib/tvgShapePath.h | 18 +++++++++--------- src/lib/tvgSwCanvas.cpp | 2 +- 16 files changed, 56 insertions(+), 56 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 16e60f0f..88abfddd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -102,7 +102,7 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); - Result reserve(size_t n) noexcept; + Result reserve(uint32_t n) noexcept; virtual Result push(std::unique_ptr paint) noexcept; virtual Result clear() noexcept; virtual Result update() noexcept; @@ -139,12 +139,12 @@ public: //Shape Result appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; Result appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; - Result appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; + Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept; //Stroke Result stroke(float width) noexcept; Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; - Result stroke(const float* dashPattern, size_t cnt) noexcept; + Result stroke(const float* dashPattern, uint32_t cnt) noexcept; Result stroke(StrokeCap cap) noexcept; Result stroke(StrokeJoin join) noexcept; @@ -157,14 +157,14 @@ public: Result translate(float x, float y) noexcept override; //Getters - size_t pathCommands(const PathCommand** cmds) const noexcept; - size_t pathCoords(const Point** pts) const noexcept; + uint32_t pathCommands(const PathCommand** cmds) const noexcept; + uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; Result bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; - size_t strokeDash(const float** dashPattern) const noexcept; + uint32_t strokeDash(const float** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; @@ -190,7 +190,7 @@ public: ~Scene(); Result push(std::unique_ptr shape) noexcept; - Result reserve(size_t size) noexcept; + Result reserve(uint32_t size) noexcept; Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; @@ -218,7 +218,7 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; static std::unique_ptr gen() noexcept; @@ -241,7 +241,7 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. - Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h index fd7086a6..79dd26d6 100644 --- a/src/lib/gl_engine/tvgGlGpuBuffer.h +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -2,7 +2,7 @@ #define _TVG_GL_GPU_BUFFER_H_ #include -#include +#include class GlGpuBuffer { @@ -15,7 +15,7 @@ public: GlGpuBuffer(); ~GlGpuBuffer(); - void updateBufferData(Target target, size_t size, void* data); + void updateBufferData(Target target, uint32_t size, void* data); private: uint32_t mGlBufferId = 0; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 0eb9bebc..14bdbaa3 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -95,13 +95,13 @@ int GlRenderer::term() } -size_t GlRenderer::unref() +uint32_t GlRenderer::unref() { return RenderInitializer::unref(renderInit); } -size_t GlRenderer::ref() +uint32_t GlRenderer::ref() { return RenderInitializer::ref(renderInit); } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index fcde08f1..3ef0ee97 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -30,13 +30,13 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, size_t stride, size_t w, size_t h) + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { return 0; }; bool clear() override; - size_t ref() override; - size_t unref() override; + uint32_t ref() override; + uint32_t unref() override; static GlRenderer* inst(); static int init(); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 16d4c1e0..e6f432df 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -149,7 +149,7 @@ struct SwDashStroke Point ptStart; Point ptCur; float* pattern; - size_t cnt; + uint32_t cnt; bool curOpGap; }; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 60c3a6d7..d2143fe7 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -45,7 +45,7 @@ bool SwRenderer::clear() return true; } -bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) +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; @@ -137,13 +137,13 @@ int SwRenderer::term() } -size_t SwRenderer::unref() +uint32_t SwRenderer::unref() { return RenderInitializer::unref(renderInit); } -size_t SwRenderer::ref() +uint32_t SwRenderer::ref() { return RenderInitializer::ref(renderInit); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 3dfb076c..4a4fafdb 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -25,10 +25,10 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool clear() override; - size_t ref() override; - size_t unref() override; + uint32_t ref() override; + uint32_t unref() override; static SwRenderer* inst(); static int init(); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 79057c77..dc05d666 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -34,7 +34,7 @@ Canvas::~Canvas() } -Result Canvas::reserve(size_t n) noexcept +Result Canvas::reserve(uint32_t n) noexcept { auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 2bf38688..024fed50 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -45,7 +45,7 @@ GlCanvas::~GlCanvas() } -Result GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 61cd6556..0e98e170 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -24,8 +24,8 @@ struct Surface { //TODO: Union for multiple types uint32_t* buffer; - size_t stride; - size_t w, h; + uint32_t stride; + uint32_t w, h; }; enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Stroke = 4, Transform = 8, All = 16}; @@ -126,14 +126,14 @@ public: virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; - virtual size_t ref() = 0; - virtual size_t unref() = 0; + virtual uint32_t ref() = 0; + virtual uint32_t unref() = 0; }; struct RenderInitializer { RenderMethod* pInst = nullptr; - size_t refCnt = 0; + uint32_t refCnt = 0; bool initialized = false; static int init(RenderInitializer& renderInit, RenderMethod* engine) @@ -160,7 +160,7 @@ struct RenderInitializer return 0; } - static size_t unref(RenderInitializer& renderInit) + static uint32_t unref(RenderInitializer& renderInit) { assert(renderInit.refCnt > 0); --renderInit.refCnt; @@ -181,7 +181,7 @@ struct RenderInitializer return renderInit.pInst; } - static size_t ref(RenderInitializer& renderInit) + static uint32_t ref(RenderInitializer& renderInit) { return ++renderInit.refCnt; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 12b96ec2..75e27207 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -53,7 +53,7 @@ Result Scene::push(unique_ptr paint) noexcept } -Result Scene::reserve(size_t size) noexcept +Result Scene::reserve(uint32_t size) noexcept { auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index a08afc64..edaa6d8b 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -27,7 +27,7 @@ struct Scene::Impl { vector paints; RenderTransform *transform = nullptr; - size_t flag = RenderUpdateFlag::None; + uint32_t flag = RenderUpdateFlag::None; ~Impl() { @@ -51,7 +51,7 @@ struct Scene::Impl return true; } - bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, size_t flag) + bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { @@ -63,7 +63,7 @@ struct Scene::Impl return true; } - bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) + bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index c41c6b12..ad1736b1 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -59,7 +59,7 @@ Result Shape::reset() noexcept } -size_t Shape::pathCommands(const PathCommand** cmds) const noexcept +uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { if (!cmds) return 0; @@ -72,7 +72,7 @@ size_t Shape::pathCommands(const PathCommand** cmds) const noexcept } -size_t Shape::pathCoords(const Point** pts) const noexcept +uint32_t Shape::pathCoords(const Point** pts) const noexcept { if (!pts) return 0; @@ -85,7 +85,7 @@ size_t Shape::pathCoords(const Point** pts) const noexcept } -Result Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept { if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments; @@ -337,7 +337,7 @@ Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const } -Result Shape::stroke(const float* dashPattern, size_t cnt) noexcept +Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept { if (cnt < 2 || !dashPattern) return Result::InvalidArguments; @@ -350,7 +350,7 @@ Result Shape::stroke(const float* dashPattern, size_t cnt) noexcept } -size_t Shape::strokeDash(const float** dashPattern) const noexcept +uint32_t Shape::strokeDash(const float** dashPattern) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 92184171..08acb362 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -33,7 +33,7 @@ struct ShapeStroke float width = 0; uint8_t color[4] = {0, 0, 0, 0}; float* dashPattern = nullptr; - size_t dashCnt = 0; + uint32_t dashCnt = 0; StrokeCap cap = StrokeCap::Square; StrokeJoin join = StrokeJoin::Bevel; @@ -51,7 +51,7 @@ struct Shape::Impl ShapePath *path = nullptr; RenderTransform *transform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a - size_t flag = RenderUpdateFlag::None; + uint32_t flag = RenderUpdateFlag::None; void *edata = nullptr; //engine data @@ -77,7 +77,7 @@ struct Shape::Impl return renderer.render(shape, edata); } - bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) + bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; @@ -203,7 +203,7 @@ struct Shape::Impl return true; } - bool strokeDash(const float* pattern, size_t cnt) + bool strokeDash(const float* pattern, uint32_t cnt) { assert(pattern); @@ -218,7 +218,7 @@ struct Shape::Impl if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); assert(stroke->dashPattern); - for (size_t i = 0; i < cnt; ++i) + for (uint32_t i = 0; i < cnt; ++i) stroke->dashPattern[i] = pattern[i]; stroke->dashCnt = cnt; diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 7e020e8b..38ed3eb7 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -26,12 +26,12 @@ struct ShapePath { PathCommand* cmds = nullptr; - size_t cmdCnt = 0; - size_t reservedCmdCnt = 0; + uint32_t cmdCnt = 0; + uint32_t reservedCmdCnt = 0; Point *pts = nullptr; - size_t ptsCnt = 0; - size_t reservedPtsCnt = 0; + uint32_t ptsCnt = 0; + uint32_t reservedPtsCnt = 0; ~ShapePath() @@ -40,7 +40,7 @@ struct ShapePath if (pts) free(pts); } - void reserveCmd(size_t cmdCnt) + void reserveCmd(uint32_t cmdCnt) { if (cmdCnt <= reservedCmdCnt) return; reservedCmdCnt = cmdCnt; @@ -48,7 +48,7 @@ struct ShapePath assert(cmds); } - void reservePts(size_t ptsCnt) + void reservePts(uint32_t ptsCnt) { if (ptsCnt <= reservedPtsCnt) return; reservedPtsCnt = ptsCnt; @@ -56,7 +56,7 @@ struct ShapePath assert(pts); } - void grow(size_t cmdCnt, size_t ptsCnt) + void grow(uint32_t cmdCnt, uint32_t ptsCnt) { reserveCmd(this->cmdCnt + cmdCnt); reservePts(this->ptsCnt + ptsCnt); @@ -68,7 +68,7 @@ struct ShapePath ptsCnt = 0; } - void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) + void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) { memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); @@ -120,7 +120,7 @@ struct ShapePath Point min = { pts[0].x, pts[0].y }; Point max = { pts[0].x, pts[0].y }; - for(size_t i = 1; i < ptsCnt; ++i) { + for(uint32_t i = 1; i < ptsCnt; ++i) { if (pts[i].x < min.x) min.x = pts[i].x; if (pts[i].y < min.y) min.y = pts[i].y; if (pts[i].x > max.x) max.x = pts[i].x; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index ec18dbf5..560a975b 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,7 +45,7 @@ SwCanvas::~SwCanvas() { } -Result SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; From 498a024df8a48ea5caf96722a7781906909310be Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 20:17:39 +0900 Subject: [PATCH 083/244] common: ++optimization replace dynamic_cast to static_cast, This can be a controversial choice between optmization and clean code. Obviously we know the converting types, try avoiding a bit heavier casting some cases. Change-Id: Id763e6d1db449a229a492ab5b1a901a195936152 --- inc/tizenvg.h | 15 +++++++++++++-- src/lib/gl_engine/tvgGlRenderer.cpp | 3 ++- src/lib/sw_engine/tvgSwRenderer.cpp | 3 ++- src/lib/tvgCanvasImpl.h | 28 ++++++++++++++++++++-------- src/lib/tvgCommon.h | 3 +++ src/lib/tvgGlCanvas.cpp | 3 ++- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 28 ++++++++++++++++++++-------- src/lib/tvgShape.cpp | 1 + src/lib/tvgSwCanvas.cpp | 3 ++- 10 files changed, 66 insertions(+), 23 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 88abfddd..309badd6 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -50,16 +50,23 @@ protected: \ A() = delete; \ ~A() = delete +#define _TIZENVG_IDENTIFIER(A) \ +protected: \ + unsigned A##_Id + namespace tvg { +class RenderMethod; +class Scene; +class Canvas; + + enum class TIZENVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; -class RenderMethod; -class Scene; struct Point { @@ -85,6 +92,10 @@ public: virtual Result translate(float x, float y) = 0; virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; + + _TIZENVG_IDENTIFIER(Paint); + _TIZENVG_DECLARE_ACCESSOR(Scene); + _TIZENVG_DECLARE_ACCESSOR(Canvas); }; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 14bdbaa3..1ca9588b 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -109,7 +109,8 @@ uint32_t GlRenderer::ref() GlRenderer* GlRenderer::inst() { - return dynamic_cast(RenderInitializer::inst(renderInit)); + //We know renderer type, avoid dynamic_cast for performance. + return static_cast(RenderInitializer::inst(renderInit)); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index d2143fe7..59c49105 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -151,7 +151,8 @@ uint32_t SwRenderer::ref() SwRenderer* SwRenderer::inst() { - return dynamic_cast(RenderInitializer::inst(renderInit)); + //We know renderer type, avoid dynamic_cast for performance. + return static_cast(RenderInitializer::inst(renderInit)); } #endif /* _TVG_SW_RENDERER_CPP_ */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 782dd94a..078385a3 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -53,9 +53,12 @@ struct Canvas::Impl assert(renderer); for (auto paint : paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->dispose(*shape, *renderer)) return Result::InsufficientCondition; } delete(paint); @@ -70,9 +73,12 @@ struct Canvas::Impl assert(renderer); for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return Result::InsufficientCondition; } } @@ -83,9 +89,12 @@ struct Canvas::Impl { assert(renderer); - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*shape, *renderer)) return Result::InsufficientCondition; } return Result::Success; @@ -99,9 +108,12 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; } } diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index c404f1fa..ca18cca6 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -31,6 +31,9 @@ using namespace tvg; #define SCENE_IMPL scene->pImpl.get() #define SHAPE_IMPL shape->pImpl.get() +#define PAINT_ID_SHAPE 0 +#define PAINT_ID_SCENE 1 + #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 024fed50..7d3903c2 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -47,7 +47,8 @@ GlCanvas::~GlCanvas() Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { - auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + //We know renderer type, avoid dynamic_cast for performance. + auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 75e27207..a1c7a7f7 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - + Paint_Id = PAINT_ID_SCENE; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index edaa6d8b..1f1fa14e 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -39,9 +39,12 @@ struct Scene::Impl bool clear(RenderMethod& renderer) { for (auto paint : paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->clear(renderer)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->dispose(*shape, renderer)) return false; } delete(paint); @@ -54,9 +57,12 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->update(renderer, transform, flag)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*shape, renderer, transform, flag)) return false; } } @@ -91,9 +97,12 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if(!SCENE_IMPL->render(renderer)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if(!SHAPE_IMPL->render(*shape, renderer)) return false; } } @@ -113,9 +122,12 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; } diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index ad1736b1..5119ac8e 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,6 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { + Paint_Id = PAINT_ID_SHAPE; } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 560a975b..780e4636 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -47,7 +47,8 @@ SwCanvas::~SwCanvas() Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { - auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + //We know renderer type, avoid dynamic_cast for performance. + auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; From c75cca5a134116f374edcb6375f9319db14e62e6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 20:43:38 +0900 Subject: [PATCH 084/244] common: code refacatoring. shorter prefix for better neat code. it's just a preference. Change-Id: I30998476a92bc971193e9a5b4436687e48e4d19a --- inc/tizenvg.h | 64 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 309badd6..a2d245d3 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -19,23 +19,23 @@ #include -#ifdef TIZENVG_BUILD - #define TIZENVG_EXPORT __attribute__ ((visibility ("default"))) +#ifdef TVG_BUILD + #define TVG_EXPORT __attribute__ ((visibility ("default"))) #else - #define TIZENVG_EXPORT + #define TVG_EXPORT #endif #ifdef LOG_TAG #undef LOG_TAG #endif -#define LOG_TAG "TIZENVG" +#define LOG_TAG "TVG" #ifdef __cplusplus extern "C" { #endif -#define _TIZENVG_DECLARE_PRIVATE(A) \ +#define _TVG_DECLARE_PRIVATE(A) \ protected: \ struct Impl; \ std::unique_ptr pImpl; \ @@ -43,14 +43,14 @@ protected: \ const A& operator=(const A&) = delete; \ A() -#define _TIZENVG_DECLARE_ACCESSOR(A) \ +#define _TVG_DECLARE_ACCESSOR(A) \ friend A -#define _TIZENVG_DISABLE_CTOR(A) \ +#define _TVG_DISABLE_CTOR(A) \ A() = delete; \ ~A() = delete -#define _TIZENVG_IDENTIFIER(A) \ +#define _TVG_DECALRE_IDENTIFIER(A) \ protected: \ unsigned A##_Id @@ -62,10 +62,10 @@ class Scene; class Canvas; -enum class TIZENVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; -enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; -enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; -enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; +enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; +enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; +enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; +enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; struct Point @@ -82,7 +82,7 @@ struct Point * @brief description... * */ -class TIZENVG_EXPORT Paint +class TVG_EXPORT Paint { public: virtual ~Paint() {} @@ -93,9 +93,9 @@ public: virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; - _TIZENVG_IDENTIFIER(Paint); - _TIZENVG_DECLARE_ACCESSOR(Scene); - _TIZENVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECALRE_IDENTIFIER(Paint); + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_ACCESSOR(Canvas); }; @@ -107,7 +107,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Canvas +class TVG_EXPORT Canvas { public: Canvas(RenderMethod*); @@ -121,8 +121,8 @@ public: virtual Result draw(bool async = true) noexcept; virtual Result sync() = 0; - _TIZENVG_DECLARE_ACCESSOR(Scene); - _TIZENVG_DECLARE_PRIVATE(Canvas); + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_PRIVATE(Canvas); }; @@ -134,7 +134,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Shape final : public Paint +class TVG_EXPORT Shape final : public Paint { public: ~Shape(); @@ -181,9 +181,9 @@ public: static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_ACCESSOR(Scene); - _TIZENVG_DECLARE_ACCESSOR(Canvas); - _TIZENVG_DECLARE_PRIVATE(Shape); + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_PRIVATE(Shape); }; @@ -195,7 +195,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Scene final : public Paint +class TVG_EXPORT Scene final : public Paint { public: ~Scene(); @@ -211,8 +211,8 @@ public: static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(Scene); - _TIZENVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_PRIVATE(Scene); + _TVG_DECLARE_ACCESSOR(Canvas); }; @@ -224,7 +224,7 @@ public: @brief description... * */ -class TIZENVG_EXPORT SwCanvas final : public Canvas +class TVG_EXPORT SwCanvas final : public Canvas { public: ~SwCanvas(); @@ -233,7 +233,7 @@ public: Result sync() noexcept override; static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(SwCanvas); + _TVG_DECLARE_PRIVATE(SwCanvas); }; @@ -245,7 +245,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT GlCanvas final : public Canvas +class TVG_EXPORT GlCanvas final : public Canvas { public: ~GlCanvas(); @@ -256,7 +256,7 @@ public: Result sync() noexcept override; static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(GlCanvas); + _TVG_DECLARE_PRIVATE(GlCanvas); }; @@ -268,7 +268,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Engine final +class TVG_EXPORT Engine final { public: /** @@ -285,7 +285,7 @@ public: static Result init() noexcept; static Result term() noexcept; - _TIZENVG_DISABLE_CTOR(Engine); + _TVG_DISABLE_CTOR(Engine); }; } //namespace From c36f23e80d243946bed1010f3ef7b36b67fda080 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 15:40:13 +0900 Subject: [PATCH 085/244] common gradient: implement linear/radial gradient interfaces. Change-Id: Ica9c54e662e73592d3fddcabed09b1605b3a5a4f --- .gitignore | 1 + inc/tizenvg.h | 101 ++++++++++++++++++++++++++++---- src/lib/gl_engine/meson.build | 6 +- src/lib/meson.build | 13 +++-- src/lib/tvgCanvasImpl.h | 8 +-- src/lib/tvgCommon.h | 3 + src/lib/tvgFill.cpp | 88 ++++++++++++++++++++++++++++ src/lib/tvgLinearGradient.cpp | 86 +++++++++++++++++++++++++++ src/lib/tvgRadialGradient.cpp | 84 ++++++++++++++++++++++++++ src/lib/tvgRenderCommon.h | 2 +- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 8 +-- src/lib/tvgShape.cpp | 34 ++++++++++- src/lib/tvgShapeImpl.h | 11 +--- src/meson.build | 2 +- test/makefile | 1 + test/testLinearGradient.cpp | 107 ++++++++++++++++++++++++++++++++++ 17 files changed, 517 insertions(+), 40 deletions(-) create mode 100644 src/lib/tvgFill.cpp create mode 100644 src/lib/tvgLinearGradient.cpp create mode 100644 src/lib/tvgRadialGradient.cpp create mode 100644 test/testLinearGradient.cpp diff --git a/.gitignore b/.gitignore index ba439cbd..b9cdf24b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ testTransform testSceneTransform testStroke testStrokeLine +testLinearGradient diff --git a/inc/tizenvg.h b/inc/tizenvg.h index a2d245d3..b089387b 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -35,6 +35,7 @@ extern "C" { #endif + #define _TVG_DECLARE_PRIVATE(A) \ protected: \ struct Impl; \ @@ -43,16 +44,21 @@ protected: \ const A& operator=(const A&) = delete; \ A() -#define _TVG_DECLARE_ACCESSOR(A) \ - friend A - #define _TVG_DISABLE_CTOR(A) \ A() = delete; \ ~A() = delete -#define _TVG_DECALRE_IDENTIFIER(A) \ +#define _TVG_DECLARE_ACCESSOR(A) \ + friend A + +#define _TVG_DECLARE_ACCESSORS(A, B) \ + friend A; \ + friend B + +#define _TVG_DECALRE_IDENTIFIER() \ protected: \ - unsigned A##_Id + unsigned id + namespace tvg { @@ -93,9 +99,79 @@ public: virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; - _TVG_DECALRE_IDENTIFIER(Paint); - _TVG_DECLARE_ACCESSOR(Scene); - _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECALRE_IDENTIFIER(); + _TVG_DECLARE_ACCESSORS(Canvas, Scene); +}; + + +/** + * @class Fill + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT Fill +{ +public: + struct ColorStop + { + float pos; + uint8_t r, g, b, a; + }; + + virtual ~Fill(); + + Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept; + uint32_t colorStops(const ColorStop** colorStops) const noexcept; + + _TVG_DECALRE_IDENTIFIER(); + _TVG_DECLARE_PRIVATE(Fill); +}; + + +/** + * @class LinearGradient + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT LinearGradient final : public Fill +{ +public: + ~LinearGradient(); + + Result linear(float x1, float y1, float x2, float y2) noexcept; + Result linear(float* x1, float* y1, float* x2, float* y2) const noexcept; + + static std::unique_ptr gen() noexcept; + + _TVG_DECLARE_PRIVATE(LinearGradient); +}; + + +/** + * @class RadialGradient + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT RadialGradient final : public Fill +{ +public: + ~RadialGradient(); + + Result radial(float cx, float cy, float radius) noexcept; + Result radial(float* cx, float* cy, float* radius) const noexcept; + + static std::unique_ptr gen() noexcept; + + _TVG_DECLARE_PRIVATE(RadialGradient); }; @@ -161,6 +237,7 @@ public: //Fill Result fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + Result fill(std::unique_ptr f) noexcept; //Transform Result rotate(float degree) noexcept override; @@ -171,6 +248,7 @@ public: uint32_t pathCommands(const PathCommand** cmds) const noexcept; uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; + const Fill* fill() const noexcept; Result bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; @@ -181,9 +259,8 @@ public: static std::unique_ptr gen() noexcept; - _TVG_DECLARE_ACCESSOR(Scene); - _TVG_DECLARE_ACCESSOR(Canvas); _TVG_DECLARE_PRIVATE(Shape); + _TVG_DECLARE_ACCESSORS(Canvas, Scene); }; @@ -211,8 +288,8 @@ public: static std::unique_ptr gen() noexcept; - _TVG_DECLARE_PRIVATE(Scene); _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_PRIVATE(Scene); }; @@ -231,6 +308,7 @@ public: Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; + static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(SwCanvas); @@ -254,6 +332,7 @@ public: Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; + static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(GlCanvas); diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 41a25e00..5494f692 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -1,12 +1,12 @@ source_file = [ 'tvgGlCommon.h', + 'tvgGlGeometry.h', 'tvgGlGpuBuffer.h', 'tvgGlProgram.h', - 'tvgGlRenderer.cpp', 'tvgGlRenderer.h', 'tvgGlShader.h', - 'tvgGlGeometry.h', - ] + 'tvgGlRenderer.cpp', +] glraster_dep = declare_dependency( include_directories : include_directories('.'), diff --git a/src/lib/meson.build b/src/lib/meson.build index 0a56f0dd..5aba9bb1 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -2,18 +2,21 @@ subdir('sw_engine') subdir('gl_engine') source_file = [ + 'tvgCanvasImpl.h', 'tvgCommon.h', 'tvgRenderCommon.h', + 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', - 'tvgCanvasImpl.h', - 'tvgSceneImpl.h', - 'tvgEngine.cpp', 'tvgCanvas.cpp', - 'tvgSwCanvas.cpp', + 'tvgEngine.cpp', + 'tvgFill.cpp', 'tvgGlCanvas.cpp', + 'tvgLinearGradient.cpp', + 'tvgRadialGradient.cpp', 'tvgScene.cpp', - 'tvgShape.cpp' + 'tvgShape.cpp', + 'tvgSwCanvas.cpp', ] src_dep = declare_dependency( diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 078385a3..c6dc0736 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -53,7 +53,7 @@ struct Canvas::Impl assert(renderer); for (auto paint : paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; @@ -73,7 +73,7 @@ struct Canvas::Impl assert(renderer); for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; @@ -89,7 +89,7 @@ struct Canvas::Impl { assert(renderer); - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; @@ -108,7 +108,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index ca18cca6..49c3f968 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -34,6 +34,9 @@ using namespace tvg; #define PAINT_ID_SHAPE 0 #define PAINT_ID_SCENE 1 +#define FILL_ID_LINEAR 0 +#define FILL_ID_RADIAL 1 + #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp new file mode 100644 index 00000000..13001c83 --- /dev/null +++ b/src/lib/tvgFill.cpp @@ -0,0 +1,88 @@ +/* + * 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_FILL_CPP_ +#define _TVG_FILL_CPP_ + +#include "tvgCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct Fill::Impl +{ + ColorStop* colorStops = nullptr; + uint32_t cnt = 0; + + ~Impl() + { + if (colorStops) free(colorStops); + } +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +Fill::Fill():pImpl(make_unique()) +{ +} + + +Fill::~Fill() +{ +} + + +Result Fill::colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (cnt == 0) { + if (impl->colorStops) { + free(impl->colorStops); + impl->colorStops = nullptr; + impl->cnt = cnt; + } + return Result::Success; + } + + if (impl->cnt != cnt) { + impl->colorStops = static_cast(realloc(impl->colorStops, cnt * sizeof(ColorStop))); + } + + impl->cnt = cnt; + memcpy(impl->colorStops, colorStops, cnt * sizeof(ColorStop)); + + return Result::Success; +} + + +uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return 0; + + if (colorStops) *colorStops = impl->colorStops; + + return impl->cnt; +} + +#endif /* _TVG_FILL_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp new file mode 100644 index 00000000..9ea803de --- /dev/null +++ b/src/lib/tvgLinearGradient.cpp @@ -0,0 +1,86 @@ +/* + * 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_LINEAR_GRADIENT_CPP_ +#define _TVG_LINEAR_GRADIENT_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct LinearGradient::Impl +{ + float x1, y1, x2, y2; +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +LinearGradient::LinearGradient():pImpl(make_unique()) +{ + id = FILL_ID_LINEAR; +} + + +LinearGradient::~LinearGradient() +{ +} + + +Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept +{ + if (fabsf(x2 - x1) < FLT_EPSILON && fabsf(y2 - y1) < FLT_EPSILON) + return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + impl->x1 = x1; + impl->y1 = y1; + impl->x2 = x2; + impl->y2 = y2; + + return Result::Success; +} + + +Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (x1) *x1 = impl->x1; + if (x2) *x2 = impl->x2; + if (y1) *y1 = impl->y1; + if (y2) *y2 = impl->y2; + + return Result::Success; +} + + +unique_ptr LinearGradient::gen() noexcept +{ + auto fill = unique_ptr(new LinearGradient); + assert(fill); + + return fill; +} + +#endif /* _TVG_LINEAR_GRADIENT_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp new file mode 100644 index 00000000..2447e6f1 --- /dev/null +++ b/src/lib/tvgRadialGradient.cpp @@ -0,0 +1,84 @@ +/* + * 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_RADIAL_GRADIENT_CPP_ +#define _TVG_RADIAL_GRADIENT_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct RadialGradient::Impl +{ + float cx, cy, radius; +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +RadialGradient::RadialGradient():pImpl(make_unique()) +{ + id = FILL_ID_RADIAL; +} + + +RadialGradient::~RadialGradient() +{ +} + + +Result RadialGradient::radial(float cx, float cy, float radius) noexcept +{ + if (radius < FLT_EPSILON) + return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + impl->cx = cx; + impl->cy = cy; + impl->radius = radius; + + return Result::Success; +} + + +Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (cx) *cx = impl->cx; + if (cy) *cy = impl->cy; + if (radius) *radius = impl->radius; + + return Result::Success; +} + + +unique_ptr RadialGradient::gen() noexcept +{ + auto fill = unique_ptr(new RadialGradient); + assert(fill); + + return fill; +} + +#endif /* _TVG_RADIAL_GRADIENT_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 0e98e170..f89d9492 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -28,7 +28,7 @@ struct Surface uint32_t w, h; }; -enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Stroke = 4, Transform = 8, All = 16}; +enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32}; struct RenderTransform { diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index a1c7a7f7..ac2ae82b 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - Paint_Id = PAINT_ID_SCENE; + id = PAINT_ID_SCENE; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 1f1fa14e..85962921 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -39,7 +39,7 @@ struct Scene::Impl bool clear(RenderMethod& renderer) { for (auto paint : paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(renderer)) return false; @@ -57,7 +57,7 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(renderer, transform, flag)) return false; @@ -97,7 +97,7 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(renderer)) return false; @@ -122,7 +122,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 5119ac8e..012fcb14 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,7 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { - Paint_Id = PAINT_ID_SHAPE; + id = PAINT_ID_SHAPE; } @@ -226,7 +226,29 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept impl->color[1] = g; impl->color[2] = b; impl->color[3] = a; - impl->flag |= RenderUpdateFlag::Fill; + impl->flag |= RenderUpdateFlag::Color; + + if (impl->fill) { + delete(impl->fill); + impl->fill = nullptr; + impl->flag |= RenderUpdateFlag::Gradient; + } + + return Result::Success; +} + + +Result Shape::fill(unique_ptr f) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + auto p = f.release(); + if (!p) return Result::MemoryCorruption; + + if (impl->fill) delete(impl->fill); + impl->fill = p; + impl->flag |= RenderUpdateFlag::Gradient; return Result::Success; } @@ -245,6 +267,14 @@ Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcep return Result::Success; } +const Fill* Shape::fill() const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return nullptr; + + return impl->fill; +} + Result Shape::scale(float factor) noexcept { diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 08acb362..4cce022d 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -23,11 +23,6 @@ /* Internal Class Implementation */ /************************************************************************/ -struct ShapeFill -{ -}; - - struct ShapeStroke { float width = 0; @@ -46,9 +41,9 @@ struct ShapeStroke struct Shape::Impl { - ShapeFill *fill = nullptr; - ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; + Fill *fill = nullptr; + ShapeStroke *stroke = nullptr; RenderTransform *transform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a uint32_t flag = RenderUpdateFlag::None; @@ -62,8 +57,8 @@ struct Shape::Impl ~Impl() { if (path) delete(path); - if (stroke) delete(stroke); if (fill) delete(fill); + if (stroke) delete(stroke); if (transform) delete(transform); } diff --git a/src/meson.build b/src/meson.build index aded0018..a0ef37db 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,4 +1,4 @@ -compiler_flags = ['-DTIZENVG_BUILD'] +compiler_flags = ['-DTVG_BUILD'] subdir('lib') subdir('examples') diff --git a/test/makefile b/test/makefile index 2aba05df..353d7b8b 100644 --- a/test/makefile +++ b/test/makefile @@ -12,3 +12,4 @@ all: 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` diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp new file mode 100644 index 00000000..4f87cad2 --- /dev/null +++ b/test/testLinearGradient.cpp @@ -0,0 +1,107 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + canvas->reserve(3); //reserve 3 shape nodes (optional) + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, 255, 0, 0, 255}; + colorStops[1] = {0.5, 255, 255, 255, 255}; + colorStops[2] = {1, 0, 0, 255, 255}; + + //Prepare Round Rectangle + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->stroke(255, 255, 255, 255); + shape1->stroke(2); + + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(0, 0, 400, 400); + fill->colorStops(colorStops, 3); + + shape1->fill(move(fill)); + canvas->push(move(shape1)); + + + //Prepare Circle + auto shape2 = tvg::Shape::gen(); + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH + shape2->stroke(255, 255, 255, 255); + shape2->stroke(2); + + //LinearGradient + auto fill2 = tvg::LinearGradient::gen(); + fill2->linear(400, 200, 400, 600); + fill2->colorStops(colorStops, 3); + + shape2->fill(move(fill2)); + canvas->push(move(shape2)); + + + //Prepare Ellipse + auto shape3 = tvg::Shape::gen(); + shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH + shape3->stroke(255, 255, 255, 255); + shape3->stroke(2); + + //LinearGradient + auto fill3 = tvg::LinearGradient::gen(); + fill3->linear(450, 600, 750, 600); + fill3->colorStops(colorStops, 3); + + shape3->fill(move(fill3)); + canvas->push(move(shape3)); + + //Draw the Shapes onto the Canvas + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From f3afd2a636f48dacbd369d5d4976cced1ec25d7f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 11 Jun 2020 14:27:20 +0900 Subject: [PATCH 086/244] common fill: added spread mode. Change-Id: I95d47bc492d5a22326a745a591d243e56a26bae4 --- inc/tizenvg.h | 6 +++++- src/lib/sw_engine/tvgSwRenderer.cpp | 1 + src/lib/tvgFill.cpp | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index b089387b..85d8e27c 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -72,6 +72,7 @@ enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondit enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; +enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; struct Point @@ -117,14 +118,17 @@ class TVG_EXPORT Fill public: struct ColorStop { - float pos; + float offset; uint8_t r, g, b, a; }; virtual ~Fill(); Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept; + Result spread(FillSpread s) noexcept; + uint32_t colorStops(const ColorStop** colorStops) const noexcept; + FillSpread spread() const noexcept; _TVG_DECALRE_IDENTIFIER(); _TVG_DECLARE_PRIVATE(Fill); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 59c49105..43c2628c 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -82,6 +82,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } + void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp index 13001c83..bfef7a6d 100644 --- a/src/lib/tvgFill.cpp +++ b/src/lib/tvgFill.cpp @@ -28,6 +28,7 @@ struct Fill::Impl { ColorStop* colorStops = nullptr; uint32_t cnt = 0; + FillSpread spread; ~Impl() { @@ -85,4 +86,24 @@ uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept return impl->cnt; } + +Result Fill::spread(FillSpread s) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + impl->spread = s; + + return Result::Success; +} + + +FillSpread Fill::spread() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->spread; +} + #endif /* _TVG_FILL_CPP_ */ \ No newline at end of file From 5c988d01a5f4c2568673eb33087730c5a15946c0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 11 Jun 2020 15:06:17 +0900 Subject: [PATCH 087/244] sw_engine: implement linear gradient feature also added testLinearGradient Change-Id: I9cce74b9fc40c4ebd978939ee50955e44e7f44f2 --- inc/tizenvg.h | 12 +- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwCommon.h | 72 ++++++-- src/lib/sw_engine/tvgSwFill.cpp | 262 ++++++++++++++++++++++++++++ src/lib/sw_engine/tvgSwMath.cpp | 24 +-- src/lib/sw_engine/tvgSwRaster.cpp | 140 +++++++++------ src/lib/sw_engine/tvgSwRenderer.cpp | 41 +++-- src/lib/sw_engine/tvgSwShape.cpp | 54 +++++- src/lib/sw_engine/tvgSwStroke.cpp | 22 +-- src/lib/tvgCanvasImpl.h | 8 +- src/lib/tvgLinearGradient.cpp | 2 +- src/lib/tvgRadialGradient.cpp | 2 +- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 8 +- src/lib/tvgShape.cpp | 2 +- test/testLinearGradient.cpp | 42 +++-- 16 files changed, 544 insertions(+), 150 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwFill.cpp diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 85d8e27c..044cdfeb 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -51,14 +51,10 @@ protected: \ #define _TVG_DECLARE_ACCESSOR(A) \ friend A -#define _TVG_DECLARE_ACCESSORS(A, B) \ - friend A; \ - friend B - #define _TVG_DECALRE_IDENTIFIER() \ + auto id() const { return _id; } \ protected: \ - unsigned id - + unsigned _id namespace tvg { @@ -101,7 +97,6 @@ public: virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; _TVG_DECALRE_IDENTIFIER(); - _TVG_DECLARE_ACCESSORS(Canvas, Scene); }; @@ -264,7 +259,8 @@ public: static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(Shape); - _TVG_DECLARE_ACCESSORS(Canvas, Scene); + _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_ACCESSOR(Scene); }; diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index f4998f4b..f96fe970 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,5 +1,6 @@ source_file = [ 'tvgSwCommon.h', + 'tvgSwFill.cpp', 'tvgSwMath.cpp', 'tvgSwRenderer.h', 'tvgSwRaster.cpp', diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index e6f432df..7a0bd417 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -21,11 +21,14 @@ using namespace tvg; -constexpr auto SW_CURVE_TYPE_POINT = 0; -constexpr auto SW_CURVE_TYPE_CUBIC = 1; - -constexpr auto SW_OUTLINE_FILL_WINDING = 0; -constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; +#define SW_CURVE_TYPE_POINT 0 +#define SW_CURVE_TYPE_CUBIC 1 +#define SW_OUTLINE_FILL_WINDING 0 +#define SW_OUTLINE_FILL_EVEN_ODD 1 +#define SW_ANGLE_PI (180L << 16) +#define SW_ANGLE_2PI (SW_ANGLE_PI << 1) +#define SW_ANGLE_PI2 (SW_ANGLE_PI >> 1) +#define SW_ANGLE_PI4 (SW_ANGLE_PI >> 2) using SwCoord = signed long; using SwFixed = signed long long; @@ -153,22 +156,28 @@ struct SwDashStroke bool curOpGap; }; +struct SwFill +{ + uint32_t* ctable; + float x1, y1, x2, y2; + float dx, dy; + float len; + float offset; + FillSpread spread; + bool translucent; +}; + struct SwShape { SwOutline* outline; SwStroke* stroke; + SwFill* fill; SwRleData* rle; SwRleData* strokeRle; SwBBox bbox; }; -constexpr static SwFixed ANGLE_PI = (180L << 16); -constexpr static SwFixed ANGLE_2PI = (ANGLE_PI << 1); -constexpr static SwFixed ANGLE_PI2 = (ANGLE_PI >> 1); -constexpr static SwFixed ANGLE_PI4 = (ANGLE_PI >> 2); - - static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; @@ -181,6 +190,33 @@ static inline SwCoord TO_SWCOORD(float val) } +static inline uint32_t COLOR_ALPHA(uint32_t rgba) +{ + return (rgba >> 24) & 0xff; +} + + +static inline uint32_t COLOR_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) +{ + return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + + ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); +} + + +static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) +{ + auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; + rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; + return (rgba1 |= t); +} + + +static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (a << 24 | r << 16 | g << 8 | b); +} + + int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -202,16 +238,26 @@ void shapeDelOutline(SwShape& shape); void shapeResetStroke(SwShape& shape, const Shape& sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); void shapeFree(SwShape* shape); +void shapeDelStroke(SwShape& shape); +bool shapeGenFillColors(SwShape& shape, const Fill* fill); +void shapeResetFill(SwShape& shape, const Fill* fill); +void shapeDelFill(SwShape& shape); void strokeReset(SwStroke& stroke, const Shape& shape); bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); +bool fillGenColorTable(SwFill* fill, const Fill* fdata); +void fillReset(SwFill* fill, const Fill* fdata); +void fillFree(SwFill* fill); +void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); + SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); void rleFree(SwRleData* rle); -bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterGradientShape(Surface& surface, SwShape& shape); +bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp new file mode 100644 index 00000000..9c4927b6 --- /dev/null +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -0,0 +1,262 @@ +/* + * 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_SW_FILL_CPP_ +#define _TVG_SW_FILL_CPP_ + +#include "tvgSwCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +#define GRADIENT_STOP_SIZE 1024 +#define FIXPT_BITS 8 +#define FIXPT_SIZE (1<ctable) { + fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); + assert(fill->ctable); + } + + const Fill::ColorStop* colors; + auto cnt = linear->colorStops(&colors); + if (cnt == 0 || !colors) return false; + + auto pColors = colors; + + if (pColors->a < 255) fill->translucent = true; + + auto rgba = COLOR_ARGB_JOIN(pColors->r, pColors->g, pColors->b, pColors->a); + auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); + auto pos = 1.5f * inc; + uint32_t i = 0; + + fill->ctable[i++] = rgba; + + while (pos <= pColors->offset) { + fill->ctable[i] = fill->ctable[i - 1]; + ++i; + pos += inc; + } + + for (uint32_t j = 0; j < cnt - 1; ++j) { + auto curr = colors + j; + auto next = curr + 1; + assert(curr && next); + auto delta = 1.0f / (next->offset - curr->offset); + if (next->a < 255) fill->translucent = true; + auto rgba2 = COLOR_ARGB_JOIN(next->r, next->g, next->b, next->a); + + while (pos < next->offset && i < GRADIENT_STOP_SIZE) { + auto t = (pos - curr->offset) * delta; + auto dist = static_cast(256 * t); + auto dist2 = 256 - dist; + fill->ctable[i] = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); + ++i; + pos += inc; + } + rgba = rgba2; + } + + for (; i < GRADIENT_STOP_SIZE; ++i) + fill->ctable[i] = rgba; + + //Make sure the lat color stop is represented at the end of the table + fill->ctable[GRADIENT_STOP_SIZE - 1] = rgba; + + return true; +} + + +bool _prepareLinear(SwFill* fill, const LinearGradient* linear) +{ + assert(fill && linear); + + if (linear->linear(&fill->x1, &fill->y1, &fill->x2, &fill->y2) != Result::Success) return false; + + fill->dx = fill->x2 - fill->x1; + fill->dy = fill->y2 - fill->y1; + fill->len = fill->dx * fill->dx + fill->dy * fill->dy; + fill->offset = 0; + + if (fill->len < FLT_EPSILON) return true; + + fill->dx /= fill->len; + fill->dy /= fill->len; + fill->offset = -fill->dx * fill->x1 - fill->dy * fill->y1; + + return _updateColorTable(fill, linear); +} + + +bool _prepareRadial(SwFill* fill, const RadialGradient* radial) +{ + assert(fill && radial); + + return true; +} + + +static inline uint32_t _clamp(const SwFill* fill, uint32_t pos) +{ + switch (fill->spread) { + case FillSpread::Pad: { + if (pos >= GRADIENT_STOP_SIZE) pos = GRADIENT_STOP_SIZE - 1; + break; + } + case FillSpread::Repeat: { + pos = pos % GRADIENT_STOP_SIZE; + break; + } + case FillSpread::Reflect: { + auto limit = GRADIENT_STOP_SIZE * 2; + pos = pos % limit; + if (pos >= GRADIENT_STOP_SIZE) pos = (limit - pos - 1); + break; + } + } + return pos; +} + + +static inline uint32_t _fixedPixel(const SwFill* fill, uint32_t pos) +{ + auto i = (pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; + return fill->ctable[_clamp(fill, i)]; +} + + +static inline uint32_t _pixel(const SwFill* fill, float pos) +{ + auto i = static_cast(pos * (GRADIENT_STOP_SIZE - 1) + 0.5f); + return fill->ctable[_clamp(fill, i)]; +} + + +static inline void _write(uint32_t *dst, uint32_t val, uint32_t len) +{ + if (len <= 0) return; + + // Cute hack to align future memcopy operation + // and do unroll the loop a bit. Not sure it is + // the most efficient, but will do for now. + auto n = (len + 7) / 8; + + switch (len & 0x07) { + case 0: do { *dst++ = val; + case 7: *dst++ = val; + case 6: *dst++ = val; + case 5: *dst++ = val; + case 4: *dst++ = val; + case 3: *dst++ = val; + case 2: *dst++ = val; + case 1: *dst++ = val; + } while (--n > 0); + } +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +{ + assert(fill->len > 0); + + //TODO: Rotation??? + auto rx = x + 0.5f; + auto ry = y + 0.5f; + auto t = (fill->dx * rx + fill->dy * ry + fill->offset) * (GRADIENT_STOP_SIZE - 1); + auto inc = (fill->dx) * (GRADIENT_STOP_SIZE - 1); + + if (fabsf(inc) < FLT_EPSILON) { + auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); + _write(dst, color, len); + return; + } + + auto vMax = static_cast(INT32_MAX >> (FIXPT_BITS + 1)); + auto vMin = -vMax; + auto v = t + (inc * len); + + //we can use fixed point math + if (v < vMax && v > vMin) { + auto t2 = static_cast(t * FIXPT_SIZE); + auto inc2 = static_cast(inc * FIXPT_SIZE); + for (uint32_t j = 0; j < len; ++j) { + *dst = _fixedPixel(fill, t2); + ++dst; + t2 += inc2; + } + //we have to fallback to float math + } else { + while (dst < dst + len) { + *dst = _pixel(fill, t / GRADIENT_STOP_SIZE); + ++dst; + t += inc; + } + } +} + + +bool fillGenColorTable(SwFill* fill, const Fill* fdata) +{ + if (!fill) return false; + + assert(fdata); + + fill->spread = fdata->spread(); + + if (fdata->id() == FILL_ID_LINEAR) { + return _prepareLinear(fill, static_cast(fdata)); + } else if (fdata->id() == FILL_ID_RADIAL) { + return _prepareRadial(fill, static_cast(fdata)); + } + + cout << "What type of gradient?!" << endl; + + return false; +} + + +void fillReset(SwFill* fill, const Fill* fdata) +{ + if (fill->ctable) { + free(fill->ctable); + fill->ctable = nullptr; + } + fill->translucent = false; +} + + +void fillFree(SwFill* fill) +{ + if (!fill) return; + + if (fill->ctable) free(fill->ctable); + + free(fill); +} + +#endif /* _TVG_SW_FILL_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index a0a0ea16..53cc8ce1 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -93,15 +93,15 @@ static void _polarize(SwPoint& pt) auto tmp = v.y; v.y = -v.x; v.x = tmp; - theta = ANGLE_PI2; + theta = SW_ANGLE_PI2; } else { - theta = v.y > 0 ? ANGLE_PI : -ANGLE_PI; + theta = v.y > 0 ? SW_ANGLE_PI : -SW_ANGLE_PI; v.x = -v.x; v.y = -v.y; } } else { if (v.y < -v.x) { - theta = -ANGLE_PI2; + theta = -SW_ANGLE_PI2; auto tmp = -v.y; v.y = v.x; v.x = tmp; @@ -144,18 +144,18 @@ static void _rotate(SwPoint& pt, SwFixed theta) SwFixed y = pt.y; //Rotate inside [-PI/4, PI/4] sector - while (theta < -ANGLE_PI4) { + while (theta < -SW_ANGLE_PI4) { auto tmp = y; y = -x; x = tmp; - theta += ANGLE_PI2; + theta += SW_ANGLE_PI2; } - while (theta > ANGLE_PI4) { + while (theta > SW_ANGLE_PI4) { auto tmp = -y; y = x; x = tmp; - theta -= ANGLE_PI2; + theta -= SW_ANGLE_PI2; } auto atan = ATAN_TBL; @@ -236,7 +236,7 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& auto theta1 = abs(mathDiff(angleIn, angleMid)); auto theta2 = abs(mathDiff(angleMid, angleOut)); - if ((theta1 < (ANGLE_PI / 8)) && (theta2 < (ANGLE_PI / 8))) return true; + if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return true; else return false; } @@ -346,7 +346,7 @@ SwFixed mathAtan(const SwPoint& pt) SwFixed mathSin(SwFixed angle) { - return mathCos(ANGLE_PI2 - angle); + return mathCos(SW_ANGLE_PI2 - angle); } @@ -408,9 +408,9 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2) { auto delta = angle2 - angle1; - delta %= ANGLE_2PI; - if (delta < 0) delta += ANGLE_2PI; - if (delta > ANGLE_PI) delta -= ANGLE_2PI; + delta %= SW_ANGLE_2PI; + if (delta < 0) delta += SW_ANGLE_2PI; + if (delta > SW_ANGLE_PI) delta -= SW_ANGLE_2PI; return delta; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 78d507b5..581f8b7e 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,60 +24,28 @@ /* Internal Class Implementation */ /************************************************************************/ -static inline uint32_t COLOR_ALPHA(uint32_t color) +static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color) { - return (color >> 24) & 0xff; -} + if (!rle) return false; + auto span = rle->spans; + auto stride = surface.stride; + uint32_t tmp; -static inline uint32_t COLOR_ALPHA_BLEND(uint32_t color, uint32_t alpha) -{ - return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + - ((((color & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); -} - - -static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (a << 24 | r << 16 | g << 8 | b); -} - - -static void -_rasterTranslucent(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) -{ - //OPTIMIZE ME: SIMD - - if (cov < 255) color = COLOR_ALPHA_BLEND(color, cov); - auto ialpha = 255 - COLOR_ALPHA(color); - - for (uint32_t i = 0; i < len; ++i) { - dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); - } -} - - -static void -_rasterSolid(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) -{ - //OPTIMIZE ME: SIMD - - //Fully Opaque - if (cov == 255) { - for (uint32_t i = 0; i < len; ++i) { - dst[i] = color; + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage < 255) tmp = COLOR_ALPHA_BLEND(color, span->coverage); + else tmp = color; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + } + ++span; } - } else { - auto ialpha = 255 - cov; - for (uint32_t i = 0; i < len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(color, cov) + COLOR_ALPHA_BLEND(dst[i], ialpha); - } - } + return true; } -static bool -_rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a) +static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) { if (!rle) return false; @@ -85,16 +53,66 @@ _rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a) auto stride = surface.stride; for (uint32_t i = 0; i < rle->size; ++i) { - assert(span); - auto dst = &surface.buffer[span->y * stride + span->x]; - - if (a == 255) _rasterSolid(dst, span->len, color, span->coverage); - else _rasterTranslucent(dst, span->len, color, span->coverage); - + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = color; + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(color, span->coverage) + COLOR_ALPHA_BLEND(dst[i], 255 - span->coverage); + } + } ++span; } + return true; +} + +static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +{ + if (!rle || !fill) return false; + + auto buf = static_cast(alloca(surface.w * sizeof(uint32_t))); + if (!buf) return false; + + auto span = rle->spans; + auto stride = surface.stride; + + //Translucent Gradient + if (fill->translucent) { + uint32_t tmp; + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + fillFetch(fill, buf, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + } + } + ++span; + } + //Opaque Gradient + } else { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage == 255) { + fillFetch(fill, dst, span->y, span->x, span->len); + } else { + fillFetch(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + } + } + ++span; + } + } return true; } @@ -103,15 +121,23 @@ _rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a) /* External Class Implementation */ /************************************************************************/ -bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterGradientShape(Surface& surface, SwShape& shape) { - return _rasterRle(surface, sdata.rle, COLOR_ARGB_JOIN(r, g, b, a), a); + return _rasterGradientRle(surface, shape.rle, shape.fill); } -bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return _rasterRle(surface, sdata.strokeRle, COLOR_ARGB_JOIN(r, g, b, a), a); + if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); +} + + +bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + if (a == 255) return _rasterSolidRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 43c2628c..e99bf387 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -57,28 +57,32 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t return true; } -bool SwRenderer::render(const Shape& shape, void *data) +bool SwRenderer::render(const Shape& sdata, void *data) { - SwShape* sdata = static_cast(data); - if (!sdata) return false; + SwShape* shape = static_cast(data); + if (!shape) return false; uint8_t r, g, b, a; - shape.fill(&r, &g, &b, &a); - if (a > 0) rasterShape(surface, *sdata, r, g, b, a); + if (sdata.fill()) { + rasterGradientShape(surface, *shape); + } else { + sdata.fill(&r, &g, &b, &a); + if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a); + } - shape.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, *sdata, r, g, b, a); + sdata.strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, *shape, r, g, b, a); return true; } -bool SwRenderer::dispose(const Shape& shape, void *data) +bool SwRenderer::dispose(const Shape& sdata, void *data) { - auto sdata = static_cast(data); - if (!sdata) return true; - shapeFree(sdata); + auto shape = static_cast(data); + if (!shape) return true; + shapeFree(shape); return true; } @@ -103,11 +107,22 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* shapeReset(*shape); uint8_t alpha = 0; sdata.fill(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0) { + if (alpha > 0 || sdata.fill()) { if (!shapeGenRle(*shape, sdata, clip, transform)) return shape; } } + //Fill + if (flags & (RenderUpdateFlag::Gradient)) { + auto fill = sdata.fill(); + if (fill) { + shapeResetFill(*shape, fill); + if (!shapeGenFillColors(*shape, fill)) return shape; + } else { + shapeDelFill(*shape); + } + } + //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (sdata.strokeWidth() > 0.5) { @@ -117,6 +132,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (alpha > 0) { if (!shapeGenStrokeRle(*shape, sdata, clip)) return shape; } + } else { + shapeDelStroke(*shape); } } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index dcb57c71..4dcf2109 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -666,19 +666,29 @@ bool shapeGenOutline(SwShape& shape, const Shape& sdata) } -void shapeFree(SwShape* sdata) +void shapeFree(SwShape* shape) { - assert(sdata); + assert(shape); - shapeDelOutline(*sdata); - rleFree(sdata->rle); + shapeDelOutline(*shape); + rleFree(shape->rle); - if (sdata->stroke) { - rleFree(sdata->strokeRle); - strokeFree(sdata->stroke); + if (shape->stroke) { + rleFree(shape->strokeRle); + strokeFree(shape->stroke); } - free(sdata); + free(shape); +} + + +void shapeDelStroke(SwShape& shape) +{ + if (!shape.stroke) return; + rleFree(shape.strokeRle); + shape.strokeRle = nullptr; + strokeFree(shape.stroke); + shape.stroke = nullptr; } @@ -730,4 +740,32 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) } +bool shapeGenFillColors(SwShape& shape, const Fill* fill) +{ + assert(fill); + + fillGenColorTable(shape.fill, fill); + return true; +} + + +void shapeResetFill(SwShape& shape, const Fill* fill) +{ + assert(fill); + + if (!shape.fill) shape.fill = static_cast(calloc(1, sizeof(SwFill))); + assert(shape.fill); + + fillReset(shape.fill, fill); +} + + +void shapeDelFill(SwShape& shape) +{ + if (!shape.fill) return; + fillFree(shape.fill); + shape.fill = nullptr; +} + + #endif /* _TVG_SW_SHAPE_H_ */ diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index fdc8caef..8b6f1ce4 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -30,7 +30,7 @@ static constexpr auto SW_STROKE_TAG_END = 8; static inline SwFixed SIDE_TO_ROTATE(const int32_t s) { - return (ANGLE_PI2 - (s) * ANGLE_PI); + return (SW_ANGLE_PI2 - (s) * SW_ANGLE_PI); } @@ -134,14 +134,14 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff) { - constexpr SwFixed ARC_CUBIC_ANGLE = ANGLE_PI / 2; + constexpr SwFixed ARC_CUBIC_ANGLE = SW_ANGLE_PI / 2; SwPoint a = {radius, 0}; mathRotate(a, angleStart); a += center; auto total = angleDiff; auto angle = angleStart; - auto rotate = (angleDiff >= 0) ? ANGLE_PI2 : -ANGLE_PI2; + auto rotate = (angleDiff >= 0) ? SW_ANGLE_PI2 : -SW_ANGLE_PI2; while (total != 0) { auto step = total; @@ -222,7 +222,7 @@ static void _arcTo(SwStroke& stroke, int32_t side) auto border = stroke.borders + side; auto rotate = SIDE_TO_ROTATE(side); auto total = mathDiff(stroke.angleIn, stroke.angleOut); - if (total == ANGLE_PI) total = -rotate * 2; + if (total == SW_ANGLE_PI) total = -rotate * 2; _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total); border->movable = false; @@ -249,7 +249,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (!bevel) { auto theta = mathDiff(stroke.angleIn, stroke.angleOut); - if (theta == ANGLE_PI) { + if (theta == SW_ANGLE_PI) { theta = rotate; phi = stroke.angleIn; } else { @@ -354,7 +354,7 @@ void _processCorner(SwStroke& stroke, SwFixed lineLength) void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { SwPoint delta = {stroke.width, 0}; - mathRotate(delta, startAngle + ANGLE_PI2); + mathRotate(delta, startAngle + SW_ANGLE_PI2); auto pt = stroke.center + delta; auto border = stroke.borders; @@ -384,7 +384,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) auto angle = mathAtan(delta); delta = {stroke.width, 0}; - mathRotate(delta, angle + ANGLE_PI2); + mathRotate(delta, angle + SW_ANGLE_PI2); //process corner if necessary if (stroke.firstPt) { @@ -460,7 +460,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl stroke.angleOut = angleIn; _processCorner(stroke, 0); } - } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (ANGLE_PI / 8)) { + } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (SW_ANGLE_PI / 8)) { //if the deviation from one arc to the next is too great add a round corner stroke.center = arc[3]; stroke.angleOut = angleIn; @@ -515,7 +515,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl auto alpha1 = mathAtan(_end - _start); //is the direction of the border arc opposite to that of the original arc? - if (abs(mathDiff(alpha0, alpha1)) > ANGLE_PI / 2) { + if (abs(mathDiff(alpha0, alpha1)) > SW_ANGLE_PI / 2) { //use the sine rule to find the intersection point auto beta = mathAtan(arc[3] - _start); @@ -583,7 +583,7 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) } else if (stroke.cap == StrokeCap::Round) { stroke.angleIn = angle; - stroke.angleOut = angle + ANGLE_PI; + stroke.angleOut = angle + SW_ANGLE_PI; _arcTo(stroke, side); return; @@ -692,7 +692,7 @@ static void _endSubPath(SwStroke& stroke) //now add the final cap stroke.center = stroke.ptStartSubPath; - _addCap(stroke, stroke.subPathAngle + ANGLE_PI, 0); + _addCap(stroke, stroke.subPathAngle + SW_ANGLE_PI, 0); /* now end the right subpath accordingly. The left one is rewind and deosn't need further processing */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index c6dc0736..42cf4707 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -53,7 +53,7 @@ struct Canvas::Impl assert(renderer); for (auto paint : paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; @@ -73,7 +73,7 @@ struct Canvas::Impl assert(renderer); for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; @@ -89,7 +89,7 @@ struct Canvas::Impl { assert(renderer); - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; @@ -108,7 +108,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp index 9ea803de..4499454f 100644 --- a/src/lib/tvgLinearGradient.cpp +++ b/src/lib/tvgLinearGradient.cpp @@ -35,7 +35,7 @@ struct LinearGradient::Impl LinearGradient::LinearGradient():pImpl(make_unique()) { - id = FILL_ID_LINEAR; + _id = FILL_ID_LINEAR; } diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp index 2447e6f1..895cccb2 100644 --- a/src/lib/tvgRadialGradient.cpp +++ b/src/lib/tvgRadialGradient.cpp @@ -35,7 +35,7 @@ struct RadialGradient::Impl RadialGradient::RadialGradient():pImpl(make_unique()) { - id = FILL_ID_RADIAL; + _id = FILL_ID_RADIAL; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index ac2ae82b..1ce0ada4 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - id = PAINT_ID_SCENE; + _id = PAINT_ID_SCENE; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 85962921..2c92d5b5 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -39,7 +39,7 @@ struct Scene::Impl bool clear(RenderMethod& renderer) { for (auto paint : paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(renderer)) return false; @@ -57,7 +57,7 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(renderer, transform, flag)) return false; @@ -97,7 +97,7 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(renderer)) return false; @@ -122,7 +122,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 012fcb14..aabd5bd2 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,7 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { - id = PAINT_ID_SHAPE; + _id = PAINT_ID_SHAPE; } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 4f87cad2..33536c41 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -18,37 +18,39 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) - //Linear Gradient Color Stops - tvg::Fill::ColorStop colorStops[3]; - colorStops[0] = {0, 255, 0, 0, 255}; - colorStops[1] = {0.5, 255, 255, 255, 255}; - colorStops[2] = {1, 0, 0, 255, 255}; - //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius - shape1->stroke(255, 255, 255, 255); - shape1->stroke(2); + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius //LinearGradient auto fill = tvg::LinearGradient::gen(); fill->linear(0, 0, 400, 400); - fill->colorStops(colorStops, 3); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops[2]; + colorStops[0] = {0, 0, 0, 0, 255}; + colorStops[1] = {1, 255, 255, 255, 255}; + + fill->colorStops(colorStops, 2); shape1->fill(move(fill)); canvas->push(move(shape1)); - //Prepare Circle auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH - shape2->stroke(255, 255, 255, 255); - shape2->stroke(2); //LinearGradient auto fill2 = tvg::LinearGradient::gen(); fill2->linear(400, 200, 400, 600); - fill2->colorStops(colorStops, 3); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops2[3]; + colorStops2[0] = {0, 255, 0, 0, 255}; + colorStops2[1] = {0.5, 255, 255, 0, 255}; + colorStops2[2] = {1, 255, 255, 255, 255}; + + fill2->colorStops(colorStops2, 3); shape2->fill(move(fill2)); canvas->push(move(shape2)); @@ -57,13 +59,19 @@ void tvgtest() //Prepare Ellipse auto shape3 = tvg::Shape::gen(); shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH - shape3->stroke(255, 255, 255, 255); - shape3->stroke(2); //LinearGradient auto fill3 = tvg::LinearGradient::gen(); fill3->linear(450, 600, 750, 600); - fill3->colorStops(colorStops, 3); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops3[4]; + colorStops3[0] = {0, 0, 127, 0, 127}; + colorStops3[1] = {0.25, 0, 170, 170, 170}; + colorStops3[2] = {0.5, 200, 0, 200, 200}; + colorStops3[3] = {1, 255, 255, 255, 255}; + + fill3->colorStops(colorStops3, 4); shape3->fill(move(fill3)); canvas->push(move(shape3)); From 7366e8949bbae8a4cb201ef2dbc2df2b84e232dc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 14 Jun 2020 17:53:29 +0900 Subject: [PATCH 088/244] sw_engine: implement gradial gradient feature also added testRadialGradient Change-Id: If4a278cb4667c38c7842ad30edf5aa2fdd56fff7 --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 26 +++++-- src/lib/sw_engine/tvgSwFill.cpp | 65 ++++++++++++---- src/lib/sw_engine/tvgSwRaster.cpp | 63 +++++++++++++-- src/lib/sw_engine/tvgSwRenderer.cpp | 4 +- test/makefile | 1 + test/testRadialGradient.cpp | 115 ++++++++++++++++++++++++++++ 7 files changed, 242 insertions(+), 33 deletions(-) create mode 100644 test/testRadialGradient.cpp diff --git a/.gitignore b/.gitignore index b9cdf24b..f1083577 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ testSceneTransform testStroke testStrokeLine testLinearGradient +testRadialGradient diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 7a0bd417..21a17059 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -158,11 +158,24 @@ struct SwDashStroke struct SwFill { + struct SwLinear { + float dx, dy; + float len; + float offset; + }; + + struct SwRadial { + float cx, cy; + float a; + float inv2a; + }; + + union { + SwLinear linear; + SwRadial radial; + }; + uint32_t* ctable; - float x1, y1, x2, y2; - float dx, dy; - float len; - float offset; FillSpread spread; bool translucent; }; @@ -251,12 +264,13 @@ void strokeFree(SwStroke* stroke); bool fillGenColorTable(SwFill* fill, const Fill* fdata); void fillReset(SwFill* fill, const Fill* fdata); void fillFree(SwFill* fill); -void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); +void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); void rleFree(SwRleData* rle); -bool rasterGradientShape(Surface& surface, SwShape& shape); +bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 9c4927b6..1fcafa38 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -29,9 +29,9 @@ #define FIXPT_SIZE (1<ctable) { fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); @@ -39,7 +39,7 @@ static bool _updateColorTable(SwFill* fill, const LinearGradient* linear) } const Fill::ColorStop* colors; - auto cnt = linear->colorStops(&colors); + auto cnt = fdata->colorStops(&colors); if (cnt == 0 || !colors) return false; auto pColors = colors; @@ -92,18 +92,18 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear) { assert(fill && linear); - if (linear->linear(&fill->x1, &fill->y1, &fill->x2, &fill->y2) != Result::Success) return false; + float x1, x2, y1, y2; + if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; - fill->dx = fill->x2 - fill->x1; - fill->dy = fill->y2 - fill->y1; - fill->len = fill->dx * fill->dx + fill->dy * fill->dy; - fill->offset = 0; + fill->linear.dx = x2 - x1; + fill->linear.dy = y2 - y1; + fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; - if (fill->len < FLT_EPSILON) return true; + if (fill->linear.len < FLT_EPSILON) return true; - fill->dx /= fill->len; - fill->dy /= fill->len; - fill->offset = -fill->dx * fill->x1 - fill->dy * fill->y1; + fill->linear.dx /= fill->linear.len; + fill->linear.dy /= fill->linear.len; + fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; return _updateColorTable(fill, linear); } @@ -113,7 +113,14 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial) { assert(fill && radial); - return true; + float radius; + if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; + if (radius < FLT_EPSILON) return true; + + fill->radial.a = radius * radius; + fill->radial.inv2a = pow(1 / (2 * fill->radial.a), 2); + + return _updateColorTable(fill, radial); } @@ -180,15 +187,39 @@ static inline void _write(uint32_t *dst, uint32_t val, uint32_t len) /* External Class Implementation */ /************************************************************************/ -void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) { - assert(fill->len > 0); + if (fill->radial.a < FLT_EPSILON) return; + + //TODO: Rotation??? + auto rx = x + 0.5f - fill->radial.cx; + auto ry = y + 0.5f - fill->radial.cy; + auto inv2a = fill->radial.inv2a; + auto rxy = rx * rx + ry * ry; + auto rxryPlus = 2 * rx; + auto det = (-4 * fill->radial.a * -rxy) * inv2a; + auto detDelta = (4 * fill->radial.a * (rxryPlus + 1.0f)) * inv2a; + auto detDelta2 = (4 * fill->radial.a * 2.0f) * inv2a; + + for (uint32_t i = 0 ; i < len ; ++i) + { + *dst = _pixel(fill, sqrt(det)); + ++dst; + det += detDelta; + detDelta += detDelta2; + } +} + + +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +{ + if (fill->linear.len < FLT_EPSILON) return; //TODO: Rotation??? auto rx = x + 0.5f; auto ry = y + 0.5f; - auto t = (fill->dx * rx + fill->dy * ry + fill->offset) * (GRADIENT_STOP_SIZE - 1); - auto inc = (fill->dx) * (GRADIENT_STOP_SIZE - 1); + auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); + auto inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 581f8b7e..05f23e61 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -69,7 +69,7 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) } -static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) { if (!rle || !fill) return false; @@ -81,17 +81,16 @@ static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* f //Translucent Gradient if (fill->translucent) { - uint32_t tmp; for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; - fillFetch(fill, buf, span->y, span->x, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); } } else { for (uint32_t i = 0; i < span->len; ++i) { - tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); + auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); } } @@ -102,9 +101,56 @@ static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* f for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; if (span->coverage == 255) { - fillFetch(fill, dst, span->y, span->x, span->len); + fillFetchLinear(fill, dst, span->y, span->x, span->len); } else { - fillFetch(fill, buf, span->y, span->x, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + } + } + ++span; + } + } + return true; +} + + +static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +{ + if (!rle || !fill) return false; + + auto buf = static_cast(alloca(surface.w * sizeof(uint32_t))); + if (!buf) return false; + + auto span = rle->spans; + auto stride = surface.stride; + + //Translucent Gradient + if (fill->translucent) { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + fillFetchRadial(fill, buf, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + } + } + ++span; + } + //Opaque Gradient + } else { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage == 255) { + fillFetchRadial(fill, dst, span->y, span->x, span->len); + } else { + fillFetchRadial(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); @@ -121,9 +167,10 @@ static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* f /* External Class Implementation */ /************************************************************************/ -bool rasterGradientShape(Surface& surface, SwShape& shape) +bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id) { - return _rasterGradientRle(surface, shape.rle, shape.fill); + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill); + return _rasterRadialGradientRle(surface, shape.rle, shape.fill); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index e99bf387..35a3122e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -64,8 +64,8 @@ bool SwRenderer::render(const Shape& sdata, void *data) uint8_t r, g, b, a; - if (sdata.fill()) { - rasterGradientShape(surface, *shape); + if (auto fill = sdata.fill()) { + rasterGradientShape(surface, *shape, fill->id()); } else { sdata.fill(&r, &g, &b, &a); if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a); diff --git a/test/makefile b/test/makefile index 353d7b8b..b041e6de 100644 --- a/test/makefile +++ b/test/makefile @@ -13,3 +13,4 @@ all: 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` diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp new file mode 100644 index 00000000..e3e7e6ef --- /dev/null +++ b/test/testRadialGradient.cpp @@ -0,0 +1,115 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //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 + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + + //RadialGradient + auto fill = tvg::RadialGradient::gen(); + fill->radial(200, 200, 200); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops[2]; + colorStops[0] = {0, 255, 255, 255, 255}; + colorStops[1] = {1, 0, 0, 0, 255}; + + fill->colorStops(colorStops, 2); + + shape1->fill(move(fill)); + canvas->push(move(shape1)); + + //Prepare Circle + auto shape2 = tvg::Shape::gen(); + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH + + //RadialGradient + auto fill2 = tvg::RadialGradient::gen(); + fill2->radial(400, 400, 200); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops2[3]; + colorStops2[0] = {0, 255, 0, 0, 255}; + colorStops2[1] = {0.5, 255, 255, 0, 255}; + colorStops2[2] = {1, 255, 255, 255, 255}; + + fill2->colorStops(colorStops2, 3); + + shape2->fill(move(fill2)); + canvas->push(move(shape2)); + + + //Prepare Ellipse + auto shape3 = tvg::Shape::gen(); + shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH + + //RadialGradient + auto fill3 = tvg::RadialGradient::gen(); + fill3->radial(600, 600, 150); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops3[4]; + colorStops3[0] = {0, 0, 127, 0, 127}; + colorStops3[1] = {0.25, 0, 170, 170, 170}; + colorStops3[2] = {0.5, 200, 0, 200, 200}; + colorStops3[3] = {1, 255, 255, 255, 255}; + + fill3->colorStops(colorStops3, 4); + + shape3->fill(move(fill3)); + canvas->push(move(shape3)); + + //Draw the Shapes onto the Canvas + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From 81de016492014538c58e1ef3a6d57136a71e12d5 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 18:10:24 +0900 Subject: [PATCH 089/244] test: updated trivial comments. Change-Id: If44643d51d9acd3e3042118e39ca3e8f07c148da --- test/testLinearGradient.cpp | 6 +++--- test/testRadialGradient.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 33536c41..08cdb667 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -26,7 +26,7 @@ void tvgtest() auto fill = tvg::LinearGradient::gen(); fill->linear(0, 0, 400, 400); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops[2]; colorStops[0] = {0, 0, 0, 0, 255}; colorStops[1] = {1, 255, 255, 255, 255}; @@ -44,7 +44,7 @@ void tvgtest() auto fill2 = tvg::LinearGradient::gen(); fill2->linear(400, 200, 400, 600); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops2[3]; colorStops2[0] = {0, 255, 0, 0, 255}; colorStops2[1] = {0.5, 255, 255, 0, 255}; @@ -64,7 +64,7 @@ void tvgtest() auto fill3 = tvg::LinearGradient::gen(); fill3->linear(450, 600, 750, 600); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops3[4]; colorStops3[0] = {0, 0, 127, 0, 127}; colorStops3[1] = {0.25, 0, 170, 170, 170}; diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index e3e7e6ef..f9ed87d5 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -26,7 +26,7 @@ void tvgtest() auto fill = tvg::RadialGradient::gen(); fill->radial(200, 200, 200); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops[2]; colorStops[0] = {0, 255, 255, 255, 255}; colorStops[1] = {1, 0, 0, 0, 255}; @@ -44,7 +44,7 @@ void tvgtest() auto fill2 = tvg::RadialGradient::gen(); fill2->radial(400, 400, 200); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops2[3]; colorStops2[0] = {0, 255, 0, 0, 255}; colorStops2[1] = {0.5, 255, 255, 0, 255}; @@ -64,7 +64,7 @@ void tvgtest() auto fill3 = tvg::RadialGradient::gen(); fill3->radial(600, 600, 150); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops3[4]; colorStops3[0] = {0, 0, 127, 0, 127}; colorStops3[1] = {0.25, 0, 170, 170, 170}; From 7435b5b414f2dd2f098bf8998cc9fa88c738e6d7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 19:54:52 +0900 Subject: [PATCH 090/244] sw_engine: support gradient transformation properly added testGradientTransform Change-Id: I29037d08ce951e5ceb2eef31cb414efc25296417 --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 4 +- src/lib/sw_engine/tvgSwFill.cpp | 39 +++++-- src/lib/sw_engine/tvgSwRenderer.cpp | 7 +- src/lib/sw_engine/tvgSwShape.cpp | 10 +- test/makefile | 1 + test/testGradientTransform.cpp | 170 ++++++++++++++++++++++++++++ 7 files changed, 215 insertions(+), 17 deletions(-) create mode 100644 test/testGradientTransform.cpp diff --git a/.gitignore b/.gitignore index f1083577..bc115012 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ testStroke testStrokeLine testLinearGradient testRadialGradient +testGradientTransform diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 21a17059..eedaf9d9 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -252,7 +252,7 @@ void shapeResetStroke(SwShape& shape, const Shape& sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape& shape); -bool shapeGenFillColors(SwShape& shape, const Fill* fill); +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable); void shapeResetFill(SwShape& shape, const Fill* fill); void shapeDelFill(SwShape& shape); @@ -261,7 +261,7 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable); void fillReset(SwFill* fill, const Fill* fdata); void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 1fcafa38..f6091837 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -88,13 +88,26 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) } -bool _prepareLinear(SwFill* fill, const LinearGradient* linear) +bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTransform* transform) { assert(fill && linear); float x1, x2, y1, y2; if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; + if (transform) { + auto cx = (x2 - x1) * 0.5f + x1; + auto cy = (y2 - y1) * 0.5f + y1; + auto dx = x1 - cx; + auto dy = y1 - cy; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; + dx = x2 - cx; + dy = y2 - cy; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; + } + fill->linear.dx = x2 - x1; fill->linear.dy = y2 - y1; fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; @@ -105,11 +118,11 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear) fill->linear.dy /= fill->linear.len; fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; - return _updateColorTable(fill, linear); + return true; } -bool _prepareRadial(SwFill* fill, const RadialGradient* radial) +bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTransform* transform) { assert(fill && radial); @@ -117,10 +130,18 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial) if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; if (radius < FLT_EPSILON) return true; + if (transform) { + auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; + auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; + fill->radial.cx = tx; + fill->radial.cy = ty; + radius *= transform->e33; + } + fill->radial.a = radius * radius; fill->radial.inv2a = pow(1 / (2 * fill->radial.a), 2); - return _updateColorTable(fill, radial); + return true; } @@ -251,7 +272,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable) { if (!fill) return false; @@ -259,10 +280,14 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata) fill->spread = fdata->spread(); + if (ctable) { + if (!_updateColorTable(fill, fdata)) return false; + } + if (fdata->id() == FILL_ID_LINEAR) { - return _prepareLinear(fill, static_cast(fdata)); + return _prepareLinear(fill, static_cast(fdata), transform); } else if (fdata->id() == FILL_ID_RADIAL) { - return _prepareRadial(fill, static_cast(fdata)); + return _prepareRadial(fill, static_cast(fdata), transform); } cout << "What type of gradient?!" << endl; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 35a3122e..1246eabf 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -113,11 +113,12 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* } //Fill - if (flags & (RenderUpdateFlag::Gradient)) { + if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { auto fill = sdata.fill(); if (fill) { - shapeResetFill(*shape, fill); - if (!shapeGenFillColors(*shape, fill)) return shape; + auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; + if (ctable) shapeResetFill(*shape, fill); + if (!shapeGenFillColors(*shape, fill, transform, ctable)) return shape; } else { shapeDelFill(*shape); } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4dcf2109..4d3c44ec 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -347,9 +347,9 @@ static void _transformOutline(SwOutline* outline, const RenderTransform* transfo for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13; - auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23; - auto pt = Point{tx + transform->e31, ty + transform->e32}; + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; + auto pt = Point{tx, ty}; outline->pts[i] = TO_SWPOINT(&pt); } } @@ -740,11 +740,11 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) } -bool shapeGenFillColors(SwShape& shape, const Fill* fill) +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable) { assert(fill); - fillGenColorTable(shape.fill, fill); + fillGenColorTable(shape.fill, fill, transform, ctable); return true; } diff --git a/test/makefile b/test/makefile index b041e6de..431fa665 100644 --- a/test/makefile +++ b/test/makefile @@ -14,3 +14,4 @@ all: 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` diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp new file mode 100644 index 00000000..0b4b677c --- /dev/null +++ b/test/testGradientTransform.cpp @@ -0,0 +1,170 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::Shape* pShape = nullptr; +tvg::Shape* pShape2 = nullptr; +tvg::Shape* pShape3 = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape1 + auto shape = tvg::Shape::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->appendRect(-285, -300, 200, 200, 0); + shape->appendRect(-185, -200, 300, 300, 100); + shape->appendCircle(115, 100, 100, 100); + shape->appendCircle(115, 200, 170, 100); + + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(-285, -300, 285, 300); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, 255, 0, 0, 255}; + colorStops[1] = {0.5, 255, 255, 0, 255}; + colorStops[2] = {1, 255, 255, 255, 255}; + + fill->colorStops(colorStops, 3); + shape->fill(move(fill)); + shape->translate(385, 400); + canvas->push(move(shape)); + + //Shape2 + auto shape2 = tvg::Shape::gen(); + pShape2 = shape2.get(); + shape2->appendRect(-50, -50, 100, 100, 0); + shape2->translate(400, 400); + + //LinearGradient + auto fill2 = tvg::LinearGradient::gen(); + fill2->linear(-50, -50, 50, 50); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops2[2]; + colorStops2[0] = {0, 0, 0, 0, 255}; + colorStops2[1] = {1, 255, 255, 255, 255}; + + fill2->colorStops(colorStops2, 2); + shape2->fill(move(fill2)); + canvas->push(move(shape2)); + + //Shape3 + auto shape3 = tvg::Shape::gen(); + pShape3 = shape3.get(); + + /* Look, how shape3's origin is different with shape2 + The center of the shape is the anchor point for transformation. */ + shape3->appendRect(100, 100, 150, 100, 20); + + //RadialGradient + auto fill3 = tvg::RadialGradient::gen(); + fill3->radial(175, 150, 75); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops3[4]; + colorStops3[0] = {0, 0, 127, 0, 127}; + colorStops3[1] = {0.25, 0, 170, 170, 170}; + colorStops3[2] = {0.5, 200, 0, 200, 200}; + colorStops3[3] = {1, 255, 255, 255, 255}; + + fill3->colorStops(colorStops3, 4); + + 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) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + //Update Shape1 + pShape->scale(1 - 0.75 * progress); + pShape->rotate(360 * progress); + + //Update shape for drawing (this may work asynchronously) + canvas->update(pShape); + + //Update Shape2 + pShape2->rotate(360 * progress); + pShape2->translate(400 + progress * 300, 400); + canvas->update(pShape2); + + //Update Shape3 + pShape3->rotate(-360 * progress); + pShape3->scale(0.5 + progress); + canvas->update(pShape3); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + 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 TizenVG Engine + tvg::Engine::term(); +} From fb208defedd896619b5ab1781a33311c9ef58656 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 20:55:55 +0900 Subject: [PATCH 091/244] common engine: manage engine initializing context. Change-Id: Ida3997fd7cc9ee0916d48290168cdb884e946833 --- src/lib/tvgEngine.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index 40b13081..5038cb80 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -24,6 +24,8 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +static bool initialized = false; + /************************************************************************/ @@ -32,11 +34,13 @@ Result Engine::init() noexcept { - //TODO: Initialize Raster engines by configuration. + if (initialized) return Result::InsufficientCondition; - int ret = 0; - ret |= SwRenderer::init(); - ret |= GlRenderer::init(); + //TODO: Initialize Raster engines by configuration. + SwRenderer::init(); + GlRenderer::init(); + + initialized = true; return Result::Success; } @@ -44,9 +48,13 @@ Result Engine::init() noexcept Result Engine::term() noexcept { - int ret = 0; - ret |= SwRenderer::term(); - ret |= GlRenderer::term(); + if (!initialized) return Result::InsufficientCondition; + + //TODO: Terminate only allowed engines. + SwRenderer::term(); + GlRenderer::term(); + + initialized = false; return Result::Success; } From f62767988247f3a61948b72a1679e3bc5044ec58 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 21:01:46 +0900 Subject: [PATCH 092/244] common initializer: replace engine class with intializer This initializer will take over the global environments of tvg engines. Change-Id: I7b99973dafaea57ddd3134800bd442ef4dc319ae --- inc/tizenvg.h | 67 ++++++++++--------- src/lib/meson.build | 2 +- src/lib/{tvgEngine.cpp => tvgInitializer.cpp} | 43 ++++++------ src/lib/tvgRenderCommon.h | 14 ++-- test/testBlending.cpp | 4 +- test/testBoundary.cpp | 4 +- test/testComposition.cpp | 4 +- test/testDirectUpdate.cpp | 4 +- test/testGradient.cpp | 4 +- test/testGradientTransform.cpp | 4 +- test/testLinearGradient.cpp | 4 +- test/testMultiShapes.cpp | 4 +- test/testPath.cpp | 4 +- test/testPathCopy.cpp | 4 +- test/testRadialGradient.cpp | 4 +- test/testScene.cpp | 4 +- test/testSceneTransform.cpp | 4 +- test/testShape.cpp | 4 +- test/testStroke.cpp | 4 +- test/testStrokeLine.cpp | 4 +- test/testTransform.cpp | 4 +- test/testUpdate.cpp | 4 +- 22 files changed, 102 insertions(+), 96 deletions(-) rename src/lib/{tvgEngine.cpp => tvgInitializer.cpp} (58%) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 044cdfeb..abb08d67 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -69,7 +69,7 @@ enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; - +enum class TVG_EXPORT CanvasEngine { Sw = 0, Gl }; struct Point { @@ -130,6 +130,34 @@ public: }; +/** + * @class Canvas + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT Canvas +{ +public: + Canvas(RenderMethod*); + virtual ~Canvas(); + + Result reserve(uint32_t n) noexcept; + virtual Result push(std::unique_ptr paint) noexcept; + virtual Result clear() noexcept; + virtual Result update() noexcept; + virtual Result update(Paint* paint) noexcept; + virtual Result draw(bool async = true) noexcept; + virtual Result sync() = 0; + + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_PRIVATE(Canvas); +}; + + + /** * @class LinearGradient * @@ -174,32 +202,6 @@ public: }; -/** - * @class Canvas - * - * @ingroup TizenVG - * - * @brief description... - * - */ -class TVG_EXPORT Canvas -{ -public: - Canvas(RenderMethod*); - virtual ~Canvas(); - - Result reserve(uint32_t n) noexcept; - virtual Result push(std::unique_ptr paint) noexcept; - virtual Result clear() noexcept; - virtual Result update() noexcept; - virtual Result update(Paint* paint) noexcept; - virtual Result draw(bool async = true) noexcept; - virtual Result sync() = 0; - - _TVG_DECLARE_ACCESSOR(Scene); - _TVG_DECLARE_PRIVATE(Canvas); -}; - /** * @class Shape @@ -277,7 +279,7 @@ class TVG_EXPORT Scene final : public Paint public: ~Scene(); - Result push(std::unique_ptr shape) noexcept; + Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; Result rotate(float degree) noexcept override; @@ -347,9 +349,10 @@ public: * @brief description... * */ -class TVG_EXPORT Engine final +class TVG_EXPORT Initializer final { public: + /** * @brief ... * @@ -361,10 +364,10 @@ public: * * @see ... */ - static Result init() noexcept; - static Result term() noexcept; + static Result init(CanvasEngine engine) noexcept; + static Result term(CanvasEngine engine) noexcept; - _TVG_DISABLE_CTOR(Engine); + _TVG_DISABLE_CTOR(Initializer); }; } //namespace diff --git a/src/lib/meson.build b/src/lib/meson.build index 5aba9bb1..c936501b 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -9,9 +9,9 @@ source_file = [ 'tvgShapePath.h', 'tvgShapeImpl.h', 'tvgCanvas.cpp', - 'tvgEngine.cpp', 'tvgFill.cpp', 'tvgGlCanvas.cpp', + 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', 'tvgRadialGradient.cpp', 'tvgScene.cpp', diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgInitializer.cpp similarity index 58% rename from src/lib/tvgEngine.cpp rename to src/lib/tvgInitializer.cpp index 5038cb80..ac6ce3ab 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgInitializer.cpp @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_ENGINE_CPP_ -#define _TVG_ENGINE_CPP_ +#ifndef _TVG_INITIALIZER_CPP_ +#define _TVG_INITIALIZER_CPP_ #include "tvgCommon.h" #include "tvgSwRenderer.h" @@ -24,39 +24,42 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static bool initialized = false; - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -Result Engine::init() noexcept +Result Initializer::init(CanvasEngine engine) noexcept { - if (initialized) return Result::InsufficientCondition; + if (engine == CanvasEngine::Sw) { + if (!SwRenderer::init()) return Result::InsufficientCondition; + } else if (engine == CanvasEngine::Gl) { + if (!GlRenderer::init()) return Result::InsufficientCondition; + } else { + return Result::InvalidArguments; + } - //TODO: Initialize Raster engines by configuration. - SwRenderer::init(); - GlRenderer::init(); - - initialized = true; + //TODO: check modules then enable them + //1. TVG + //2. SVG return Result::Success; } -Result Engine::term() noexcept +Result Initializer::term(CanvasEngine engine) noexcept { - if (!initialized) return Result::InsufficientCondition; + //TODO: deinitialize modules - //TODO: Terminate only allowed engines. - SwRenderer::term(); - GlRenderer::term(); - - initialized = false; + if (engine == CanvasEngine::Sw) { + if (!SwRenderer::term()) return Result::InsufficientCondition; + } else if (engine == CanvasEngine::Gl) { + if (!GlRenderer::term()) return Result::InsufficientCondition; + } else { + return Result::InvalidArguments; + } return Result::Success; } -#endif /* _TVG_ENGINE_CPP_ */ +#endif /* _TVG_INITIALIZER_CPP_ */ diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index f89d9492..a581067b 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -136,28 +136,28 @@ struct RenderInitializer uint32_t refCnt = 0; bool initialized = false; - static int init(RenderInitializer& renderInit, RenderMethod* engine) + static bool init(RenderInitializer& renderInit, RenderMethod* engine) { assert(engine); - if (renderInit.pInst || renderInit.refCnt > 0) return -1; + if (renderInit.pInst || renderInit.refCnt > 0) return false; renderInit.pInst = engine; renderInit.refCnt = 0; renderInit.initialized = true; - return 0; + return true; } - static int term(RenderInitializer& renderInit) + static bool term(RenderInitializer& renderInit) { - if (!renderInit.pInst || !renderInit.initialized) return -1; + if (!renderInit.pInst || !renderInit.initialized) return false; renderInit.initialized = false; //Still it's refered.... - if (renderInit.refCnt > 0) return 0; + if (renderInit.refCnt > 0) return true; delete(renderInit.pInst); renderInit.pInst = nullptr; - return 0; + return true; } static uint32_t unref(RenderInitializer& renderInit) diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 58ae0251..a5559d49 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -63,7 +63,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index c5d39f62..701bb840 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -53,7 +53,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testComposition.cpp b/test/testComposition.cpp index 57a8e435..d8ca9794 100644 --- a/test/testComposition.cpp +++ b/test/testComposition.cpp @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Composition Source Canvas auto canvas1 = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); @@ -31,5 +31,5 @@ int main(int argc, char **argv) canvas2->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index e1a4c608..eb3a9dc6 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -69,7 +69,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -100,5 +100,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testGradient.cpp b/test/testGradient.cpp index 6a7b6ba7..cf33a1ef 100644 --- a/test/testGradient.cpp +++ b/test/testGradient.cpp @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); @@ -48,5 +48,5 @@ int main(int argc, char **argv) canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 0b4b677c..90fab168 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -135,7 +135,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -166,5 +166,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 08cdb667..decf263d 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -81,7 +81,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 25393822..e6db3bb7 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -41,7 +41,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testPath.cpp b/test/testPath.cpp index c2ca8754..3d520037 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -56,7 +56,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 28d19eb9..8ce33c3c 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -96,7 +96,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index f9ed87d5..b50204b8 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -81,7 +81,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testScene.cpp b/test/testScene.cpp index f7c9ea5b..e134237f 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -87,7 +87,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 975f4faf..11dade09 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -129,7 +129,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -159,5 +159,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testShape.cpp b/test/testShape.cpp index 8cff17d2..16fc1a0e 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -35,7 +35,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testStroke.cpp b/test/testStroke.cpp index b17c3a10..a7ae5d09 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -12,7 +12,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -80,7 +80,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 1288c075..61e035e5 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -116,7 +116,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 0a126cc5..a99708d0 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -98,7 +98,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -129,5 +129,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 453b47c0..0ee9412d 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -59,7 +59,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -90,5 +90,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } From c235b7b81d0ab87a989da91738eef2f55a8d1d5e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 16 Jun 2020 15:28:43 +0900 Subject: [PATCH 093/244] common scene: design load()/save() interfaces these interfaces will perform for vector resources such as svg/tvg/etc ... see testSvg examples Change-Id: Icec0a4682301a13646868bd7c3bfc1771ae7db2c --- .gitignore | 2 ++ inc/tizenvg.h | 4 +++ src/lib/tvgScene.cpp | 23 +++++++++++++++ src/lib/tvgSceneImpl.h | 10 +++++++ test/makefile | 2 ++ test/testSvg.cpp | 63 +++++++++++++++++++++++++++++++++++++++ test/testSvg2.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+) create mode 100644 test/testSvg.cpp create mode 100644 test/testSvg2.cpp diff --git a/.gitignore b/.gitignore index bc115012..3b90d3af 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ testStrokeLine testLinearGradient testRadialGradient testGradientTransform +testSvg +testSvg2 diff --git a/inc/tizenvg.h b/inc/tizenvg.h index abb08d67..c62dda2f 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -71,6 +71,7 @@ enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; enum class TVG_EXPORT CanvasEngine { Sw = 0, Gl }; + struct Point { float x, y; @@ -282,6 +283,9 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; + Result load(const std::string& path, float w, float h, bool lazy = false) noexcept; + Result save(const std::string& path) noexcept; + Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; Result translate(float x, float y) noexcept override; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 1ce0ada4..c0939332 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -107,4 +107,27 @@ Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept return Result::Success; } + +Result Scene::load(const std::string& path, float w, float h, bool lazy) noexcept +{ + if (path.empty()) return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + return impl->load(path, w, h, lazy); +} + + +Result Scene::save(const std::string& path) noexcept +{ + if (path.empty()) return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + return impl->save(path); +} + + #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 2c92d5b5..5ba8d510 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -191,6 +191,16 @@ struct Scene::Impl return true; } + + Result load(const string& path, float w, float h, bool lazy) + { + return Result::Success; + } + + Result save(const string& path) + { + return Result::Success; + } }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/test/makefile b/test/makefile index 431fa665..8dce9e9b 100644 --- a/test/makefile +++ b/test/makefile @@ -15,3 +15,5 @@ all: 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 testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testSvg.cpp b/test/testSvg.cpp new file mode 100644 index 00000000..dea96a2e --- /dev/null +++ b/test/testSvg.cpp @@ -0,0 +1,63 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + /* Create a SVG scene, keep original size, + You can pass 0 x 0 size for lazying loading in this case. + scene->load("sample.svg", 0, 0, true); */ + auto scene = tvg::Scene::gen(); + scene->load("sample.svg"); + canvas->push(move(scene)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp new file mode 100644 index 00000000..4714db6b --- /dev/null +++ b/test/testSvg2.cpp @@ -0,0 +1,67 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Create a SVG scene, keep aspect ratio to width/2 with lazy loading + auto scene = tvg::Scene::gen(); + scene->load("sample.svg", WIDTH/2, 0, true); + canvas->push(move(scene)); + + //Create a SVG scene, keep aspect ratio to height/2 with lazy loading + auto scene2 = tvg::Scene::gen(); + scene2->load("sample.svg", 0, HEIGHT/2, true); + scene2->translate(WIDTH/2, HEIGHT/2); + canvas->push(move(scene2)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} From ec03afa83a319a2390aeba24f4d3bca30dd5d9ec Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 10:41:58 +0900 Subject: [PATCH 094/244] sw_engine renderer: accept stroke less 1 width size. Change-Id: I5fe6a0993ab5c1abc79d89834ea04c25b059c320 --- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 1246eabf..adeb7388 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -126,7 +126,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (sdata.strokeWidth() > 0.5) { + if (sdata.strokeWidth() > FLT_EPSILON) { shapeResetStroke(*shape, sdata); uint8_t alpha = 0; sdata.strokeColor(nullptr, nullptr, nullptr, &alpha); From 968286df57bdc712a09351160c0c3a23697a0da5 Mon Sep 17 00:00:00 2001 From: Pranay Kumar Samanta Date: Wed, 10 Jun 2020 18:14:42 +0530 Subject: [PATCH 095/244] gl_engine: implement gl infrastructure interfaces & test Gl shape sample Change-Id: Ie142616bf02f9bd50ac8e88e31ed9f782dd6324b Signed-off-by: Pranay Kumar Samanta --- .gitignore | 1 + src/lib/gl_engine/meson.build | 6 + src/lib/gl_engine/tvgGlCommon.h | 26 ++- src/lib/gl_engine/tvgGlGeometry.cpp | 319 +++++++++++++++++++++++++++ src/lib/gl_engine/tvgGlGeometry.h | 62 +++--- src/lib/gl_engine/tvgGlGpuBuffer.cpp | 32 +++ src/lib/gl_engine/tvgGlGpuBuffer.h | 4 +- src/lib/gl_engine/tvgGlProgram.cpp | 144 ++++++++++++ src/lib/gl_engine/tvgGlProgram.h | 13 +- src/lib/gl_engine/tvgGlRenderer.cpp | 111 ++++++++-- src/lib/gl_engine/tvgGlRenderer.h | 20 +- src/lib/gl_engine/tvgGlShader.cpp | 77 +++++++ src/lib/gl_engine/tvgGlShader.h | 5 +- src/lib/gl_engine/tvgGlShaderSrc.cpp | 22 ++ src/lib/gl_engine/tvgGlShaderSrc.h | 7 + src/lib/tvgGlCanvas.cpp | 4 + src/lib/tvgRenderCommon.h | 0 src/lib/tvgShape.cpp | 0 test/makefile | 5 +- test/testGlShape.cpp | 113 ++++++++++ 20 files changed, 904 insertions(+), 67 deletions(-) mode change 100644 => 100755 src/lib/gl_engine/meson.build mode change 100644 => 100755 src/lib/gl_engine/tvgGlCommon.h create mode 100755 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlGeometry.h create mode 100755 src/lib/gl_engine/tvgGlGpuBuffer.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlGpuBuffer.h create mode 100755 src/lib/gl_engine/tvgGlProgram.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlProgram.h mode change 100644 => 100755 src/lib/gl_engine/tvgGlRenderer.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlRenderer.h create mode 100755 src/lib/gl_engine/tvgGlShader.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlShader.h create mode 100755 src/lib/gl_engine/tvgGlShaderSrc.cpp create mode 100755 src/lib/gl_engine/tvgGlShaderSrc.h mode change 100644 => 100755 src/lib/tvgGlCanvas.cpp mode change 100644 => 100755 src/lib/tvgRenderCommon.h mode change 100644 => 100755 src/lib/tvgShape.cpp mode change 100644 => 100755 test/makefile create mode 100755 test/testGlShape.cpp diff --git a/.gitignore b/.gitignore index 3b90d3af..af30a22a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ testRadialGradient testGradientTransform testSvg testSvg2 +testGlShape diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build old mode 100644 new mode 100755 index 5494f692..a5409a74 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -5,7 +5,13 @@ source_file = [ 'tvgGlProgram.h', 'tvgGlRenderer.h', 'tvgGlShader.h', + 'tvgGlShaderSrc.h', + 'tvgGlGeometry.cpp', + 'tvgGlGpuBuffer.cpp', + 'tvgGlProgram.cpp', 'tvgGlRenderer.cpp', + 'tvgGlShader.cpp', + 'tvgGlShaderSrc.cpp', ] glraster_dep = declare_dependency( diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h old mode 100644 new mode 100755 index f68666a4..c5969545 --- a/src/lib/gl_engine/tvgGlCommon.h +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -2,11 +2,31 @@ #define _TVG_GL_COMMON_H_ #include "tvgCommon.h" -#include "tvgGlProgram.h" -#include "tvgGlShader.h" -#include "tvgGlGeometry.h" +#define GL_CHECK(x) \ + x; \ + do { \ + GLenum glError = glGetError(); \ + if(glError != GL_NO_ERROR) { \ + printf("glGetError() = %i (0x%.8x) at line %s : %i\n", glError, glError, __FILE__, __LINE__); \ + assert(0); \ + } \ + } while(0) + +#define EGL_CHECK(x) \ + x; \ + do { \ + EGLint eglError = eglGetError(); \ + if(eglError != EGL_SUCCESS) { \ + printf("eglGetError() = %i (0x%.8x) at line %s : %i\n", eglError, eglError, __FILE__, __LINE__); \ + assert(0); \ + } \ + } while(0) + + +class GlGeometry; + struct GlShape { float viewWd; diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp new file mode 100755 index 00000000..59b730bd --- /dev/null +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -0,0 +1,319 @@ +#include "tvgGlGpuBuffer.h" +#include "tvgGlGeometry.h" +#include "tvgGlCommon.h" + +#include + + +uint32_t GlGeometry::getPrimitiveCount() +{ + return mPrimitives.size(); +} + + +bool GlGeometry::decomposeOutline(const Shape &shape) +{ + const PathCommand *cmds = nullptr; + auto cmdCnt = shape.pathCommands(&cmds); + + Point *pts = nullptr; + auto ptsCnt = shape.pathCoords(const_cast(&pts)); + + //No actual shape data + if (cmdCnt == 0 || ptsCnt == 0) + return false; + + GlPrimitive* curPrimitive = nullptr; + for (size_t i = 0; i < cmdCnt; ++i) + { + switch (*(cmds + i)) + { + case PathCommand::Close: + { + if (curPrimitive && curPrimitive->mAAPoints.size() > 0 && + (curPrimitive->mAAPoints[0].orgPt != curPrimitive->mAAPoints.back().orgPt) ) + { + curPrimitive->mAAPoints.push_back(curPrimitive->mAAPoints[0].orgPt); + } + break; + } + case PathCommand::MoveTo: + mPrimitives.push_back(GlPrimitive()); + curPrimitive = &mPrimitives.back(); + case PathCommand::LineTo: + { + if (curPrimitive) + { + addPoint(*curPrimitive, pts[0]); + } + pts++; + break; + } + case PathCommand::CubicTo: + { + if (curPrimitive) + { + decomposeCubicCurve(*curPrimitive, curPrimitive->mAAPoints.back().orgPt, pts[0], pts[1], pts[2]); + } + pts += 3; + break; + } + } + } + return true; +} + +bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpdateFlag flag) +{ + for (auto& shapeGeometry : mPrimitives) + { + std::vector normalInfo; + constexpr float blurDir = -1.0f; + float antiAliasWidth = 1.0f; + vector& aaPts = shapeGeometry.mAAPoints; + + const float stroke = (strokeWd > 1) ? strokeWd - antiAliasWidth : strokeWd; + + size_t nPoints = aaPts.size(); + if (nPoints < 2) + { + return false; + } + + normalInfo.resize(nPoints); + + size_t fPoint = 0; + size_t sPoint = 1; + for (size_t i = 0; i < nPoints - 1; ++i) + { + fPoint = i; + sPoint = i + 1; + if (sPoint == nPoints - 1) + sPoint = 0; + + GlPoint normal = getNormal(aaPts[fPoint].orgPt, aaPts[sPoint].orgPt); + + normalInfo[fPoint].normal1 = normal; + normalInfo[sPoint].normal2 = normal; + } + normalInfo[nPoints - 1].normal1 = normalInfo[0].normal1; + normalInfo[nPoints - 1].normal2 = normalInfo[0].normal2; + + for (uint32_t i = 0; i < nPoints; ++i) + { + normalInfo[i].normalF = normalInfo[i].normal1 + normalInfo[i].normal2; + normalInfo[i].normalF.normalize(); + + float angle = dotProduct(normalInfo[i].normal2, normalInfo[i].normalF); + if (angle != 0) + normalInfo[i].normalF = normalInfo[i].normalF / angle; + else + normalInfo[i].normalF = GlPoint(0, 0); + + if (flag & RenderUpdateFlag::Color) + { + aaPts[i].fillOuterBlur = extendEdge(aaPts[i].orgPt, normalInfo[i].normalF, blurDir * stroke); + aaPts[i].fillOuter = extendEdge(aaPts[i].fillOuterBlur, normalInfo[i].normalF, blurDir*antiAliasWidth); + } + if (flag & RenderUpdateFlag::Stroke) + { + aaPts[i].strokeOuterBlur = aaPts[i].orgPt; + aaPts[i].strokeOuter = extendEdge(aaPts[i].strokeOuterBlur, normalInfo[i].normalF, blurDir*antiAliasWidth); + aaPts[i].strokeInner = extendEdge(aaPts[i].strokeOuter, normalInfo[i].normalF, blurDir * stroke); + aaPts[i].strokeInnerBlur = extendEdge(aaPts[i].strokeInner, normalInfo[i].normalF, blurDir*antiAliasWidth); + } + } + } + + return true; +} + +bool GlGeometry::tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag) +{ + for (auto& shapeGeometry : mPrimitives) + { + constexpr float opaque = 1.0f; + constexpr float transparent = 0.0f; + vector& aaPts = shapeGeometry.mAAPoints; + VertexDataArray& fill = shapeGeometry.mFill; + VertexDataArray& stroke = shapeGeometry.mStroke; + + if (flag & RenderUpdateFlag::Color) + { + uint32_t i = 0; + for (size_t pt = 0; pt < aaPts.size(); ++pt) + { + addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque); + if (i > 1) + { + addTriangleFanIndices(i, fill.indices); + } + ++i; + } + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(fill, aaPts[pt - 1].fillOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(fill, aaPts[pt - 1].fillOuter, viewWd, viewHt, opaque); + addGeometryPoint(fill, aaPts[pt].fillOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque); + addQuadIndices(i, fill.indices); + } + } + if (flag & RenderUpdateFlag::Stroke) + { + uint32_t i = 0; + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(stroke, aaPts[pt - 1].strokeOuter, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt - 1].strokeInner, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeOuter, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeInner, viewWd, viewHt, opaque); + addQuadIndices(i, stroke.indices); + } + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(stroke, aaPts[pt - 1].strokeOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(stroke, aaPts[pt - 1].strokeOuter, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(stroke, aaPts[pt].strokeOuter, viewWd, viewHt, opaque); + addQuadIndices(i, stroke.indices); + } + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(stroke, aaPts[pt - 1].strokeInner, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt - 1].strokeInnerBlur, viewWd, viewHt, transparent); + addGeometryPoint(stroke, aaPts[pt].strokeInner, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeInnerBlur, viewWd, viewHt, transparent); + addQuadIndices(i, stroke.indices); + } + } + aaPts.clear(); + } + return true; +} + + +void GlGeometry::disableVertex(uint32_t location) +{ + GL_CHECK(glDisableVertexAttribArray(location)); + mGpuBuffer->unbind(GlGpuBuffer::Target::ARRAY_BUFFER); +} + + +void GlGeometry::draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag) +{ + if (primitiveIndex >= mPrimitives.size()) + { + return; + } + VertexDataArray& geometry = (flag == RenderUpdateFlag::Color) ? mPrimitives[primitiveIndex].mFill : mPrimitives[primitiveIndex].mStroke; + + updateBuffer(location, geometry); + GL_CHECK(glDrawElements(GL_TRIANGLES, geometry.indices.size(), GL_UNSIGNED_INT, geometry.indices.data())); +} + + +void GlGeometry::updateBuffer(uint32_t location, const VertexDataArray& vertexArray) +{ + if (mGpuBuffer.get() == nullptr) + { + mGpuBuffer = make_unique(); + } + mGpuBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, vertexArray.vertices.size() * sizeof(VertexData), vertexArray.vertices.data()); + GL_CHECK(glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0)); + GL_CHECK(glEnableVertexAttribArray(location)); +} + + +GlPoint GlGeometry::normalizePoint(const GlPoint &pt, float viewWd, float viewHt) +{ + GlPoint p; + p.x = (pt.x * 2.0f / viewWd) - 1.0f; + p.y = -1.0f * ((pt.y * 2.0f / viewHt) - 1.0f); + return p; +} + +void GlGeometry::addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity) +{ + VertexData tv = { normalizePoint(pt, viewWd, viewHt), opacity}; + geometry.vertices.push_back(tv); +} + +GlPoint GlGeometry::getNormal(const GlPoint &p1, const GlPoint &p2) +{ + GlPoint normal = p1 - p2; + normal.normalize(); + return GlPoint(-normal.y, normal.x); +} + +float GlGeometry::dotProduct(const GlPoint &p1, const GlPoint &p2) +{ + return (p1.x * p2.x + p1.y * p2.y); +} + +GlPoint GlGeometry::extendEdge(const GlPoint &pt, const GlPoint &normal, float scalar) +{ + GlPoint tmp = (normal * scalar); + return (pt + tmp); +} + +void GlGeometry::addPoint(GlPrimitive& primitve, const GlPoint &pt) +{ + primitve.mAAPoints.push_back(GlPoint(pt.x, pt.y)); +} + +void GlGeometry::addTriangleFanIndices(uint32_t &curPt, std::vector &indices) +{ + indices.push_back(0); + indices.push_back(curPt - 1); + indices.push_back(curPt); +} + +void GlGeometry::addQuadIndices(uint32_t &curPt, std::vector &indices) +{ + indices.push_back(curPt); + indices.push_back(curPt + 1); + indices.push_back(curPt + 2); + indices.push_back(curPt + 1); + indices.push_back(curPt + 3); + indices.push_back(curPt + 2); + curPt += 4; +} + +bool GlGeometry::isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2) +{ + GlPoint diff1 = (c1 * 3.0f) - (p1 * 2.0f) - p2; + GlPoint diff2 = (c2 * 3.0f) - (p2 * 2.0f) - p1; + + diff1.mod(); + diff2.mod(); + if (diff1.x < diff2.x) + diff1.x = diff2.x; + if (diff1.y < diff2.y) + diff1.y = diff2.y; + + if (diff1.x + diff1.y <= 0.5f) + return true; + return false; +} + +void GlGeometry::decomposeCubicCurve(GlPrimitive& primitve, const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2) +{ + if (isBezierFlat(pt1, cpt1, cpt2, pt2)) + { + addPoint(primitve, pt2); + return; + } + GlPoint p12 = (pt1 + cpt1) * 0.5f; + GlPoint p23 = (cpt1 + cpt2) * 0.5f; + GlPoint p34 = (cpt2 + pt2) * 0.5f; + + GlPoint p123 = (p12 + p23) * 0.5f; + GlPoint p234 = (p23 + p34) * 0.5f; + + GlPoint p1234 = (p123 + p234) * 0.5f; + + decomposeCubicCurve(primitve, pt1, p12, p123, p1234); + decomposeCubicCurve(primitve, p1234, p234, p34, pt2); +} + diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h old mode 100644 new mode 100755 index 8f7cc610..9f87efa9 --- a/src/lib/gl_engine/tvgGlGeometry.h +++ b/src/lib/gl_engine/tvgGlGeometry.h @@ -1,7 +1,7 @@ #ifndef _TVG_GL_GEOMETRY_H_ #define _TVG_GL_GEOMETRY_H_ -#include "tvgGlGpuBuffer.h" +#include "tvgGlCommon.h" class GlPoint { @@ -9,6 +9,8 @@ public: float x = 0.0f; float y = 0.0f; + GlPoint() = default; + GlPoint(float pX, float pY):x(pX), y(pY) {} @@ -145,36 +147,42 @@ struct VertexDataArray vector indices; }; -class GlGeometry +struct GlPrimitive { -public: - GlGeometry(); - void reset(); - void updateBuffer(const uint32_t location, const VertexDataArray& geometry); - void draw(const VertexDataArray& geometry); - bool decomposeOutline(const Shape& shape); - bool generateAAPoints(const Shape& shape, float strokeWd, RenderUpdateFlag flag); - bool tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag); - - const VertexDataArray& getFill(); - const VertexDataArray& getStroke(); - -private: - GlPoint normalizePoint(GlPoint &pt, float viewWd, float viewHt); - void addGeometryPoint(VertexDataArray &geometry, GlPoint &pt, float viewWd, float viewHt, float opacity); - GlPoint getNormal(GlPoint &p1, GlPoint &p2); - float dotProduct(GlPoint &p1, GlPoint &p2); - GlPoint extendEdge(GlPoint &pt, GlPoint &normal, float scalar); - void addPoint(const GlPoint &pt); - void addTriangleFanIndices(uint32_t &curPt, vector &indices); - void addQuadIndices(uint32_t &curPt, vector &indices); - bool isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2); - void decomposeCubicCurve(const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2); - - unique_ptr mGpuBuffer; vector mAAPoints; VertexDataArray mFill; VertexDataArray mStroke; }; +class GlGpuBuffer; + +class GlGeometry +{ +public: + + uint32_t getPrimitiveCount(); + bool decomposeOutline(const Shape& shape); + bool generateAAPoints(const Shape& shape, float strokeWd, RenderUpdateFlag flag); + bool tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag); + void disableVertex(uint32_t location); + void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag); + +private: + GlPoint normalizePoint(const GlPoint &pt, float viewWd, float viewHt); + void addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity); + GlPoint getNormal(const GlPoint &p1, const GlPoint &p2); + float dotProduct(const GlPoint &p1, const GlPoint &p2); + GlPoint extendEdge(const GlPoint &pt, const GlPoint &normal, float scalar); + + void addPoint(GlPrimitive& primitve, const GlPoint &pt); + void addTriangleFanIndices(uint32_t &curPt, vector &indices); + void addQuadIndices(uint32_t &curPt, vector &indices); + bool isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2); + void decomposeCubicCurve(GlPrimitive& primitve, const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2); + void updateBuffer(const uint32_t location, const VertexDataArray& vertexArray); + + unique_ptr mGpuBuffer; + vector mPrimitives; +}; + #endif /* _TVG_GL_GEOMETRY_H_ */ diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp new file mode 100755 index 00000000..2aaba198 --- /dev/null +++ b/src/lib/gl_engine/tvgGlGpuBuffer.cpp @@ -0,0 +1,32 @@ +#include "tvgGlCommon.h" +#include "tvgGlGpuBuffer.h" + +#include + +GlGpuBuffer::GlGpuBuffer() +{ + GL_CHECK(glGenBuffers(1, &mGlBufferId)); + assert(mGlBufferId != GL_INVALID_VALUE); +} + + +GlGpuBuffer::~GlGpuBuffer() +{ + if (mGlBufferId) + { + GL_CHECK(glDeleteBuffers(1, &mGlBufferId)); + } +} + + +void GlGpuBuffer::updateBufferData(Target target, uint32_t size, const void* data) +{ + GL_CHECK(glBindBuffer(static_cast(target), mGlBufferId)); + GL_CHECK(glBufferData(static_cast(target), size, data, GL_STATIC_DRAW)); +} + + +void GlGpuBuffer::unbind(Target target) +{ + GL_CHECK(glBindBuffer(static_cast(target), 0)); +} \ No newline at end of file diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h old mode 100644 new mode 100755 index 79dd26d6..3116001c --- a/src/lib/gl_engine/tvgGlGpuBuffer.h +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -15,8 +15,8 @@ public: GlGpuBuffer(); ~GlGpuBuffer(); - void updateBufferData(Target target, uint32_t size, void* data); - + void updateBufferData(Target target, uint32_t size, const void* data); + void unbind(Target target); private: uint32_t mGlBufferId = 0; diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp new file mode 100755 index 00000000..dbf87622 --- /dev/null +++ b/src/lib/gl_engine/tvgGlProgram.cpp @@ -0,0 +1,144 @@ +#include "tvgGlCommon.h" +#include "tvgGlProgram.h" + +#include + + +static std::vector gStdAttributes = { + "aLocation" +}; + +static std::vector gStdUniforms = { + "uColor" +}; + +uint32_t GlProgram::mCurrentProgram = 0; +map GlProgram::mAttributeBuffer; +map GlProgram::mUniformBuffer; + + +unique_ptr GlProgram::gen(std::shared_ptr shader) +{ + return make_unique(shader); +} + + +GlProgram::GlProgram(std::shared_ptr shader) +{ + linkProgram(shader); + load(); + + for (auto name : gStdAttributes) + { + getAttributeLocation(name.c_str()); + } + for (auto name : gStdUniforms) + { + getUniformLocation(name.c_str()); + } + +} + + +GlProgram::~GlProgram() +{ + if (mCurrentProgram == mProgramObj) + { + unload(); + } + glDeleteProgram(mProgramObj); +} + + +void GlProgram::load() +{ + if (mCurrentProgram == mProgramObj) + { + return; + } + + mCurrentProgram = mProgramObj; + GL_CHECK(glUseProgram(mProgramObj)); + +} + + +void GlProgram::unload() +{ + mCurrentProgram = 0; +} + + +int32_t GlProgram::getAttributeLocation(const char* name) +{ + if (mAttributeBuffer.find(name) != mAttributeBuffer.end()) + { + return mAttributeBuffer[name]; + } + GL_CHECK(int32_t location = glGetAttribLocation(mCurrentProgram, name)); + if (location != -1) + { + mAttributeBuffer[name] = location; + } + return location; +} + + +int32_t GlProgram::getUniformLocation(const char* name) +{ + if (mUniformBuffer.find(name) != mUniformBuffer.end()) + { + return mUniformBuffer[name]; + } + GL_CHECK(int32_t location = glGetUniformLocation(mCurrentProgram, name)); + if (location != -1) + { + mUniformBuffer[name] = location; + } + return location; + +} + + +void GlProgram::setUniformValue(int32_t location, float r, float g, float b, float a) +{ + glUniform4f(location, r, g, b, a); +} + + +void GlProgram::linkProgram(std::shared_ptr shader) +{ + GLint linked; + + // Create the program object + uint32_t progObj = glCreateProgram(); + assert(progObj); + + glAttachShader(progObj, shader->getVertexShader()); + glAttachShader(progObj, shader->getFragmentShader()); + + // Link the program + glLinkProgram(progObj); + + // Check the link status + glGetProgramiv(progObj, GL_LINK_STATUS, &linked); + + if (!linked) + { + GLint infoLen = 0; + glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 0) + { + char* infoLog = new char[infoLen]; + glGetProgramInfoLog(progObj, infoLen, NULL, infoLog); + std::cout << "Error linking shader: " << infoLog << std::endl; + delete[] infoLog; + + } + glDeleteProgram(progObj); + progObj = 0; + assert(0); + } + mProgramObj = progObj; +} + diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h old mode 100644 new mode 100755 index d485d3d2..5df0e4f1 --- a/src/lib/gl_engine/tvgGlProgram.h +++ b/src/lib/gl_engine/tvgGlProgram.h @@ -3,22 +3,25 @@ #include "tvgGlShader.h" +#include #include - class GlProgram { public: - GlProgram(shared_ptr shader); - void create(); + static std::unique_ptr gen(std::shared_ptr shader); + GlProgram(std::shared_ptr shader); + ~GlProgram(); + void load(); + void unload(); int32_t getAttributeLocation(const char* name); int32_t getUniformLocation(const char* name); void setUniformValue(int32_t location, float r, float g, float b, float a); private: - void linkProgram(); - std::shared_ptr mShader; + + void linkProgram(std::shared_ptr shader); uint32_t mProgramObj; static uint32_t mCurrentProgram; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100644 new mode 100755 index 1ca9588b..ecabf6ad --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -17,7 +17,10 @@ #ifndef _TVG_GL_RENDERER_CPP_ #define _TVG_GL_RENDERER_CPP_ -#include "tvgCommon.h" +#include "tvgGlShaderSrc.h" +#include "tvgGlGpuBuffer.h" +#include "tvgGlGeometry.h" +#include "tvgGlCommon.h" #include "tvgGlRenderer.h" /************************************************************************/ @@ -33,16 +36,55 @@ static RenderInitializer renderInit; bool GlRenderer::clear() { //TODO: (Request) to clear target + // Will be adding glClearColor for input buffer + return true; +} + + +bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +{ + assert(w > 0 && h > 0); + + surface.stride = stride; + surface.w = w; + surface.h = h; return true; } + +void GlRenderer::flush() +{ + GL_CHECK(glFinish()); + mColorProgram->unload(); +} + + bool GlRenderer::render(const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; - //TODO: + uint8_t r, g, b, a; + size_t flags = static_cast(sdata->updateFlag); + + GL_CHECK(glViewport(0, 0, sdata->viewWd, sdata->viewHt)); + + uint32_t geometryCnt = sdata->geometry->getPrimitiveCount(); + for (uint32_t i = 0; i < geometryCnt; ++i) + { + mColorProgram->load(); + if (flags & RenderUpdateFlag::Color) + { + shape.fill(&r, &g, &b, &a); + drawPrimitive(*(sdata->geometry), (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, i, RenderUpdateFlag::Color); + } + if (flags & RenderUpdateFlag::Stroke) + { + shape.strokeColor(&r, &g, &b, &a); + drawPrimitive(*(sdata->geometry), (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, i, RenderUpdateFlag::Stroke); + } + } return true; } @@ -53,9 +95,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) GlShape* sdata = static_cast(data); if (!sdata) return false; - //TODO: - - free(sdata); + delete sdata; return true; } @@ -64,21 +104,35 @@ void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* { //prepare shape data GlShape* sdata = static_cast(data); - if (!sdata) { - sdata = static_cast(calloc(1, sizeof(GlShape))); + if (!sdata) + { + sdata = new GlShape; assert(sdata); } + sdata->viewWd = static_cast(surface.w); + sdata->viewHt = static_cast(surface.h); + sdata->updateFlag = flags; - if (flags & RenderUpdateFlag::Path) { - //TODO: Updated Vertices + if (sdata->updateFlag == RenderUpdateFlag::None) return nullptr; + + initShaders(); + + sdata->geometry = make_unique(); + + //invisible? + uint8_t alphaF, alphaS; + shape.fill(nullptr, nullptr, nullptr, &alphaF); + shape.strokeColor(nullptr, nullptr, nullptr, &alphaS); + auto strokeWd = shape.strokeWidth(); + + if (alphaF == 0 && alphaS == 0) return sdata; + + if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke) ) + { + if (!sdata->geometry->decomposeOutline(shape)) return sdata; + if (!sdata->geometry->generateAAPoints(shape, static_cast(strokeWd), sdata->updateFlag)) return sdata; + if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata; } - - if (flags & RenderUpdateFlag::Transform) { - //TODO: Updated Transform - } - - //TODO: - return sdata; } @@ -91,6 +145,10 @@ int GlRenderer::init() int GlRenderer::term() { + if (inst()->mColorProgram.get()) + { + inst()->mColorProgram.reset(nullptr); + } return RenderInitializer::term(renderInit); } @@ -114,4 +172,25 @@ GlRenderer* GlRenderer::inst() } +void GlRenderer::initShaders() +{ + if (!mColorProgram.get()) + { + shared_ptr shader = GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER); + mColorProgram = GlProgram::gen(shader); + } + mColorProgram->load(); + mColorUniformLoc = mColorProgram->getUniformLocation("uColor"); + mVertexAttrLoc = mColorProgram->getAttributeLocation("aLocation"); +} + + +void GlRenderer::drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag) +{ + mColorProgram->setUniformValue(mColorUniformLoc, r, g, b, a); + geometry.draw(mVertexAttrLoc, primitiveIndex, flag); + geometry.disableVertex(mVertexAttrLoc); + +} + #endif /* _TVG_GL_RENDERER_CPP_ */ diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h old mode 100644 new mode 100755 index 3ef0ee97..5214a63d --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -18,9 +18,8 @@ #define _TVG_GL_RENDERER_H_ #include "tvgGlCommon.h" +#include "tvgGlProgram.h" -namespace tvg -{ class GlRenderer : public RenderMethod { @@ -30,10 +29,8 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) - { - return 0; - }; + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); + void flush(); bool clear() override; uint32_t ref() override; uint32_t unref() override; @@ -46,11 +43,12 @@ private: GlRenderer(){}; ~GlRenderer(){}; - std::unique_ptr mColorProgram; - int32_t mColorUniform; - uint32_t mVertexAttrID; + void initShaders(); + void drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag); + + unique_ptr mColorProgram; + int32_t mColorUniformLoc; + uint32_t mVertexAttrLoc; }; -} - #endif /* _TVG_GL_RENDERER_H_ */ diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp new file mode 100755 index 00000000..a655159c --- /dev/null +++ b/src/lib/gl_engine/tvgGlShader.cpp @@ -0,0 +1,77 @@ +#include "tvgGlCommon.h" +#include "tvgGlShader.h" + +#include + + +shared_ptr GlShader::gen(const char * vertSrc, const char * fragSrc) +{ + shared_ptr shader = make_shared(); + shader->createShader(vertSrc, fragSrc); + return shader; +} + + +GlShader::~GlShader() +{ + glDeleteShader(mVtShader); + glDeleteShader(mFrShader); +} + +uint32_t GlShader::getVertexShader() +{ + return mVtShader; +} + + +uint32_t GlShader::getFragmentShader() +{ + return mFrShader; +} + + +void GlShader::createShader(const char* vertSrc, const char* fragSrc) +{ + mVtShader = complileShader(GL_VERTEX_SHADER, const_cast(vertSrc)); + mFrShader = complileShader(GL_FRAGMENT_SHADER, const_cast(fragSrc)); +} + + +uint32_t GlShader::complileShader(uint32_t type, char* shaderSrc) +{ + GLuint shader; + GLint compiled; + + // Create the shader object + shader = glCreateShader(type); + assert(shader); + + // Load the shader source + glShaderSource(shader, 1, &shaderSrc, NULL); + + // Compile the shader + glCompileShader(shader); + + // Check the compile status + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) + { + GLint infoLen = 0; + + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + + if (infoLen > 0) + { + char* infoLog = new char[infoLen]; + glGetShaderInfoLog(shader, infoLen, NULL, infoLog); + std::cout << "Error compiling shader: " << infoLog << std::endl; + delete[] infoLog; + } + glDeleteShader(shader); + assert(0); + } + + return shader; +} + diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h old mode 100644 new mode 100755 index 36b125a9..85bf1160 --- a/src/lib/gl_engine/tvgGlShader.h +++ b/src/lib/gl_engine/tvgGlShader.h @@ -1,10 +1,13 @@ #ifndef _TVG_GL_SHADER_H_ #define _TVG_GL_SHADER_H_ +#include + class GlShader { public: - static shared_ptr gen(const char * vertSrc, const char * fragSrc); + static std::shared_ptr gen(const char * vertSrc, const char * fragSrc); + ~GlShader(); uint32_t getVertexShader(); uint32_t getFragmentShader(); diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp new file mode 100755 index 00000000..cdd25f0f --- /dev/null +++ b/src/lib/gl_engine/tvgGlShaderSrc.cpp @@ -0,0 +1,22 @@ +#include "tvgGlShaderSrc.h" + +const char* COLOR_VERT_SHADER = +"attribute highp vec4 aLocation; \n" +"uniform highp vec4 uColor; \n" +"varying highp vec4 vcolor; \n" +"varying highp float vOpacity; \n" +"void main() \n" +"{ \n" +" gl_Position = vec4(aLocation.xy, 0.0, 1.0); \n" +" vcolor = uColor; \n" +" vOpacity = aLocation.z; \n" +"} \n"; + +const char* COLOR_FRAG_SHADER = +"varying highp vec4 vcolor; \n" +"varying highp float vOpacity; \n" +"void main() \n" +"{ \n" +" gl_FragColor = vec4(vcolor.xyz, vcolor.w*vOpacity); \n" +"} \n"; + diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h new file mode 100755 index 00000000..e6d3b911 --- /dev/null +++ b/src/lib/gl_engine/tvgGlShaderSrc.h @@ -0,0 +1,7 @@ +#ifndef _TVG_GL_SHADERSRC_H_ +#define _TVG_GL_SHADERSRC_H_ + +extern const char* COLOR_VERT_SHADER; +extern const char* COLOR_FRAG_SHADER; + +#endif /* _TVG_GL_SHADERSRC_H_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp old mode 100644 new mode 100755 index 7d3903c2..80a00177 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -59,6 +59,10 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t Result GlCanvas::sync() noexcept { + auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + assert(renderer); + + renderer->flush(); return Result::Success; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h old mode 100644 new mode 100755 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp old mode 100644 new mode 100755 diff --git a/test/makefile b/test/makefile old mode 100644 new mode 100755 index 8dce9e9b..aca250bf --- a/test/makefile +++ b/test/makefile @@ -15,5 +15,6 @@ all: 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 testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` +# gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` +# gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp new file mode 100755 index 00000000..077057e2 --- /dev/null +++ b/test/testGlShape.cpp @@ -0,0 +1,113 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 +#define BPP 4 +static Evas_GL_API *glapi; +static unique_ptr canvas; + +static void +tvgtest() +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Gl); + + + //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)); +} + +static void +init_gl(Evas_Object *obj) +{ + tvgtest(); +} + +static void +del_gl(Evas_Object *obj) +{ + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Gl); +} + +static 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); + + Eo* win = elm_win_util_standard_add(nullptr, "TizenVG 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); + + elm_object_focus_set(gl, EINA_TRUE); + + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); + + return 0; +} From 9f82ea86a84a5713d2dad6ff1ef3ba185c8072c2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 18:41:10 +0900 Subject: [PATCH 096/244] test: revise glShape sample. turn on gl window for testing. Change-Id: I8a965f820d4a09697bc4145147cb0940672933be --- test/testGlShape.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp index 077057e2..3ff4a33c 100755 --- a/test/testGlShape.cpp +++ b/test/testGlShape.cpp @@ -12,10 +12,6 @@ static unique_ptr canvas; static void tvgtest() { - //Initialize TizenVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Gl); - - //Create a Canvas canvas = tvg::GlCanvas::gen(); canvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); @@ -40,6 +36,9 @@ tvgtest() static void init_gl(Evas_Object *obj) { + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Gl); + tvgtest(); } @@ -78,10 +77,12 @@ 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, "TizenVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); - // create a new glview object + //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); @@ -93,16 +94,14 @@ int main(int argc, char **argv) evas_object_resize(gl, WIDTH, HEIGHT); - // initialize callback function gets registered here + //Initialize callback function gets registered here elm_glview_init_func_set(gl, init_gl); - // delete callback function gets registered here + //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); - elm_object_focus_set(gl, EINA_TRUE); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); evas_object_show(win); From 0e25879d1285e748b1e94d89ab7b0c8e4dad28d4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 18:44:52 +0900 Subject: [PATCH 097/244] correct unmatched files permission. Please keep file permission 664. Change-Id: I90bdfa76b4f94a06d3b560df42509f30e59111a4 --- src/lib/gl_engine/meson.build | 0 src/lib/gl_engine/tvgGlCommon.h | 0 src/lib/gl_engine/tvgGlGeometry.cpp | 0 src/lib/gl_engine/tvgGlGeometry.h | 0 src/lib/gl_engine/tvgGlGpuBuffer.cpp | 0 src/lib/gl_engine/tvgGlGpuBuffer.h | 0 src/lib/gl_engine/tvgGlProgram.cpp | 0 src/lib/gl_engine/tvgGlProgram.h | 0 src/lib/gl_engine/tvgGlRenderer.cpp | 0 src/lib/gl_engine/tvgGlRenderer.h | 0 src/lib/gl_engine/tvgGlShader.cpp | 0 src/lib/gl_engine/tvgGlShader.h | 0 src/lib/gl_engine/tvgGlShaderSrc.cpp | 0 src/lib/gl_engine/tvgGlShaderSrc.h | 0 src/lib/tvgGlCanvas.cpp | 0 src/lib/tvgRenderCommon.h | 0 src/lib/tvgShape.cpp | 0 test/testGlShape.cpp | 0 18 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/gl_engine/meson.build mode change 100755 => 100644 src/lib/gl_engine/tvgGlCommon.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlGpuBuffer.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlGpuBuffer.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlProgram.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlProgram.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlShader.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlShader.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlShaderSrc.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlShaderSrc.h mode change 100755 => 100644 src/lib/tvgGlCanvas.cpp mode change 100755 => 100644 src/lib/tvgRenderCommon.h mode change 100755 => 100644 src/lib/tvgShape.cpp mode change 100755 => 100644 test/testGlShape.cpp diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h old mode 100755 new mode 100644 diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp old mode 100755 new mode 100644 diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h old mode 100755 new mode 100644 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp old mode 100755 new mode 100644 diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp old mode 100755 new mode 100644 From 01e52c7c7aaeeeb4018022023ff53673d7a2114d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 19 Jun 2020 14:49:07 +0900 Subject: [PATCH 098/244] common loader: build up loader infrastructure. Change-Id: I62aaed43015301ec39e414833f37d6c5485d8043 --- .gitignore | 1 - inc/tizenvg.h | 5 +- src/lib/gl_engine/meson.build | 2 +- src/lib/meson.build | 3 + src/lib/sw_engine/meson.build | 2 +- src/lib/tvgCommon.h | 2 + src/lib/tvgInitializer.cpp | 7 ++- src/lib/tvgLoader.h | 36 +++++++++++ src/lib/tvgLoaderMgr.cpp | 52 ++++++++++++++++ src/lib/tvgLoaderMgr.h | 27 +++++++++ src/lib/tvgScene.cpp | 16 +---- src/lib/tvgSceneImpl.h | 21 +++++-- src/loaders/meson.build | 1 + src/loaders/svg_loader/meson.build | 9 +++ src/loaders/svg_loader/tvgSvgLoader.cpp | 80 +++++++++++++++++++++++++ src/loaders/svg_loader/tvgSvgLoader.h | 38 ++++++++++++ src/meson.build | 6 +- test/makefile | 3 +- test/testSvg.cpp | 4 +- test/testSvg2.cpp | 67 --------------------- 20 files changed, 279 insertions(+), 103 deletions(-) create mode 100644 src/lib/tvgLoader.h create mode 100644 src/lib/tvgLoaderMgr.cpp create mode 100644 src/lib/tvgLoaderMgr.h create mode 100644 src/loaders/meson.build create mode 100644 src/loaders/svg_loader/meson.build create mode 100644 src/loaders/svg_loader/tvgSvgLoader.cpp create mode 100644 src/loaders/svg_loader/tvgSvgLoader.h delete mode 100644 test/testSvg2.cpp diff --git a/.gitignore b/.gitignore index af30a22a..7aa8bd7f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,4 @@ testLinearGradient testRadialGradient testGradientTransform testSvg -testSvg2 testGlShape diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c62dda2f..bc541b31 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -64,7 +64,7 @@ class Scene; class Canvas; -enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; +enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, NonSupport, Unknown }; enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; @@ -283,8 +283,7 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; - Result load(const std::string& path, float w, float h, bool lazy = false) noexcept; - Result save(const std::string& path) noexcept; + Result load(const std::string& path) noexcept; Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index a5409a74..943fb067 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -14,7 +14,7 @@ source_file = [ 'tvgGlShaderSrc.cpp', ] -glraster_dep = declare_dependency( +glengine_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) diff --git a/src/lib/meson.build b/src/lib/meson.build index c936501b..32db5f10 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,6 +4,8 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgLoader.h', + 'tvgLoaderMgr.h', 'tvgRenderCommon.h', 'tvgSceneImpl.h', 'tvgShapePath.h', @@ -13,6 +15,7 @@ source_file = [ 'tvgGlCanvas.cpp', 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', + 'tvgLoaderMgr.cpp', 'tvgRadialGradient.cpp', 'tvgScene.cpp', 'tvgShape.cpp', diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index f96fe970..8b062587 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -10,7 +10,7 @@ source_file = [ 'tvgSwStroke.cpp', ] -swraster_dep = declare_dependency( +swengine_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 49c3f968..d147521b 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,8 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgLoader.h" +#include "tvgLoaderMgr.h" #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index ac6ce3ab..857698d2 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -20,6 +20,7 @@ #include "tvgCommon.h" #include "tvgSwRenderer.h" #include "tvgGlRenderer.h" +#include "tvgLoaderMgr.h" /************************************************************************/ /* Internal Class Implementation */ @@ -39,9 +40,7 @@ Result Initializer::init(CanvasEngine engine) noexcept return Result::InvalidArguments; } - //TODO: check modules then enable them - //1. TVG - //2. SVG + if (!LoaderMgr::init()) return Result::Unknown; return Result::Success; } @@ -59,6 +58,8 @@ Result Initializer::term(CanvasEngine engine) noexcept return Result::InvalidArguments; } + if (!LoaderMgr::term()) return Result::Unknown; + return Result::Success; } diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h new file mode 100644 index 00000000..8a1c9184 --- /dev/null +++ b/src/lib/tvgLoader.h @@ -0,0 +1,36 @@ +/* + * 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_LOADER_H_ +#define _TVG_LOADER_H_ + +namespace tvg +{ + +class Loader +{ +public: + virtual ~Loader() {} + + virtual bool open(const char* path) = 0; + virtual bool read() = 0; + virtual bool close() = 0; + virtual unique_ptr data() = 0; +}; + +} + +#endif //_TVG_LOADER_H_ \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp new file mode 100644 index 00000000..a99838b7 --- /dev/null +++ b/src/lib/tvgLoaderMgr.cpp @@ -0,0 +1,52 @@ +/* + * 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_LOADER_MGR_CPP_ +#define _TVG_LOADER_MGR_CPP_ + +#include "tvgCommon.h" +#include "tvgSvgLoader.h" + + +static int initCnt = 0; + +bool LoaderMgr::init() +{ + if (initCnt > 0) return true; + ++initCnt; + + //TODO: + + return true; +} + +bool LoaderMgr::term() +{ + --initCnt; + if (initCnt > 0) return true; + + //TODO: + + return true; +} + +unique_ptr LoaderMgr::loader(const char* path) +{ + //TODO: + return unique_ptr(new SvgLoader); +} + +#endif //_TVG_LOADER_MGR_CPP_ \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h new file mode 100644 index 00000000..0d37012f --- /dev/null +++ b/src/lib/tvgLoaderMgr.h @@ -0,0 +1,27 @@ +/* + * 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_LOADER_MGR_H_ +#define _TVG_LOADER_MGR_H_ + +struct LoaderMgr +{ + static bool init(); + static bool term(); + static unique_ptr loader(const char* path); +}; + +#endif //_TVG_LOADER_MGR_H_ \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index c0939332..41620a0b 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -108,26 +108,14 @@ Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept } -Result Scene::load(const std::string& path, float w, float h, bool lazy) noexcept +Result Scene::load(const std::string& path) noexcept { if (path.empty()) return Result::InvalidArguments; auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; - return impl->load(path, w, h, lazy); + return impl->load(path); } - -Result Scene::save(const std::string& path) noexcept -{ - if (path.empty()) return Result::InvalidArguments; - - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - return impl->save(path); -} - - #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 5ba8d510..5e67a666 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -28,6 +28,7 @@ struct Scene::Impl vector paints; RenderTransform *transform = nullptr; uint32_t flag = RenderUpdateFlag::None; + unique_ptr loader = nullptr; ~Impl() { @@ -71,6 +72,15 @@ struct Scene::Impl bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { + if (loader) { + auto scene = loader->data(); + auto p = scene.release(); + if (!p) return false; + paints.push_back(p); + loader->close(); + loader.reset(nullptr); + } + if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; if (!transform->update()) { @@ -192,13 +202,12 @@ struct Scene::Impl return true; } - Result load(const string& path, float w, float h, bool lazy) - { - return Result::Success; - } - - Result save(const string& path) + Result load(const string& path) { + if (loader) loader->close(); + loader = LoaderMgr::loader(path.c_str()); + if (!loader || !loader->open(path.c_str())) return Result::NonSupport; + if (!loader->read()) return Result::Unknown; return Result::Success; } }; diff --git a/src/loaders/meson.build b/src/loaders/meson.build new file mode 100644 index 00000000..53186ddb --- /dev/null +++ b/src/loaders/meson.build @@ -0,0 +1 @@ +subdir('svg_loader') diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build new file mode 100644 index 00000000..1bd40c10 --- /dev/null +++ b/src/loaders/svg_loader/meson.build @@ -0,0 +1,9 @@ +source_file = [ + 'tvgSvgLoader.h', + 'tvgSvgLoader.cpp', +] + +svgloader_dep = declare_dependency( + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp new file mode 100644 index 00000000..f4b8f43b --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -0,0 +1,80 @@ +/* + * 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_CPP_ +#define _TVG_SVG_LOADER_CPP_ + +#include "tvgSvgLoader.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +SvgLoader::SvgLoader() +{ + cout << "SvgLoader()" << endl; +} + + +SvgLoader::~SvgLoader() +{ + cout << "~SvgLoader()" << endl; +} + + +bool SvgLoader::open(const char* path) +{ + //TODO: + cout << "SvgLoader::open()" << endl; + + return false; +} + + +bool SvgLoader::read() +{ + //TODO: + cout << "SvgLoader::read()" << endl; + + return false; +} + + +bool SvgLoader::close() +{ + //TODO: + cout << "SvgLoader::close()" << endl; + + return false; +} + + +unique_ptr SvgLoader::data() +{ + //TODO: + cout << "SvgLoader::data()" << endl; + + return nullptr; +} + +#endif //_TVG_SVG_LOADER_CPP_ \ No newline at end of file diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h new file mode 100644 index 00000000..2b4d8b16 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -0,0 +1,38 @@ +/* + * 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_H_ +#define _TVG_SVG_LOADER_H_ + +#include "tvgCommon.h" + +class SvgLoader : public Loader +{ +private: + //TODO: + +public: + SvgLoader(); + ~SvgLoader(); + + bool open(const char* path) override; + bool read() override; + bool close() override; + unique_ptr data() override; +}; + + +#endif //_TVG_SVG_LOADER_H_ \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index a0ef37db..e49c9a0d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,12 +1,14 @@ compiler_flags = ['-DTVG_BUILD'] subdir('lib') +subdir('loaders') subdir('examples') + m_dep = meson.get_compiler('cpp').find_library('m') egl_dep = meson.get_compiler('cpp').find_library('EGL') -gl_dep = meson.get_compiler('cpp').find_library('GLESv2') +gles_dep = meson.get_compiler('cpp').find_library('GLESv2') -tizenvg_lib_dep = [ src_dep, swraster_dep, glraster_dep, m_dep, egl_dep, gl_dep] +tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep] tizenvg_lib = library( diff --git a/test/makefile b/test/makefile index aca250bf..501eef58 100755 --- a/test/makefile +++ b/test/makefile @@ -15,6 +15,5 @@ all: 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 testSvg2 testSvg2.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` diff --git a/test/testSvg.cpp b/test/testSvg.cpp index dea96a2e..e9189023 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -17,9 +17,7 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - /* Create a SVG scene, keep original size, - You can pass 0 x 0 size for lazying loading in this case. - scene->load("sample.svg", 0, 0, true); */ + // Create a SVG scene, request the original size, auto scene = tvg::Scene::gen(); scene->load("sample.svg"); canvas->push(move(scene)); diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp deleted file mode 100644 index 4714db6b..00000000 --- a/test/testSvg2.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() -{ - //Initialize TizenVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - - //Create a SVG scene, keep aspect ratio to width/2 with lazy loading - auto scene = tvg::Scene::gen(); - scene->load("sample.svg", WIDTH/2, 0, true); - canvas->push(move(scene)); - - //Create a SVG scene, keep aspect ratio to height/2 with lazy loading - auto scene2 = tvg::Scene::gen(); - scene2->load("sample.svg", 0, HEIGHT/2, true); - scene2->translate(WIDTH/2, HEIGHT/2); - canvas->push(move(scene2)); - - canvas->draw(); - canvas->sync(); - - //Terminate TizenVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} - -void -win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - - -int main(int argc, char **argv) -{ - tvgtest(); - - //Show the result using EFL... - elm_init(argc, argv); - - Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); -} From 538254a32d83a49e65565ab50c5af5eaeb3dd812 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 16:30:18 +0900 Subject: [PATCH 099/244] common render: code refactoring. just replace the filename. Change-Id: I6b18520d33c7db3ac9d6c44b10dd693b204495e5 --- src/lib/{tvgRenderCommon.h => tvgRender.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/lib/{tvgRenderCommon.h => tvgRender.h} (100%) diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRender.h similarity index 100% rename from src/lib/tvgRenderCommon.h rename to src/lib/tvgRender.h From f56a3b791c0f8a229c84fba232b4f35975abc36c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 16:44:11 +0900 Subject: [PATCH 100/244] comon render: split declaration and body. Change-Id: I39eb1dfb929b7811fab82956aedbb15f001390e7 --- src/lib/meson.build | 3 +- src/lib/tvgCommon.h | 2 +- src/lib/tvgRender.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgRender.h | 81 +++---------------------------- 4 files changed, 118 insertions(+), 77 deletions(-) create mode 100644 src/lib/tvgRender.cpp diff --git a/src/lib/meson.build b/src/lib/meson.build index 32db5f10..96752064 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -6,7 +6,7 @@ source_file = [ 'tvgCommon.h', 'tvgLoader.h', 'tvgLoaderMgr.h', - 'tvgRenderCommon.h', + 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', @@ -17,6 +17,7 @@ source_file = [ 'tvgLinearGradient.cpp', 'tvgLoaderMgr.cpp', 'tvgRadialGradient.cpp', + 'tvgRender.cpp', 'tvgScene.cpp', 'tvgShape.cpp', 'tvgSwCanvas.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index d147521b..2b0e9c18 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -39,7 +39,7 @@ using namespace tvg; #include "tvgLoader.h" #include "tvgLoaderMgr.h" -#include "tvgRenderCommon.h" +#include "tvgRender.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" #include "tvgSceneImpl.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp new file mode 100644 index 00000000..4b4afc3b --- /dev/null +++ b/src/lib/tvgRender.cpp @@ -0,0 +1,109 @@ +/* + * 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_RENDER_CPP_ +#define _TVG_RENDER_CPP_ + +#include "tvgCommon.h" +#include "tvgRender.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool RenderTransform::update() +{ + constexpr auto PI = 3.141592f; + + //Init Status + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && + fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { + return false; + } + + //identity + e11 = 1.0f; + e12 = 0.0f; + e13 = 0.0f; + e21 = 0.0f; + e22 = 1.0f; + e23 = 0.0f; + e31 = 0.0f; + e32 = 0.0f; + e33 = 1.0f; + + //scale + e11 *= factor; + e22 *= factor; + e33 *= factor; + + //rotation + if (fabsf(degree) > FLT_EPSILON) { + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; + + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } + + e31 += x; + e32 += y; + + return true; +} + + +RenderTransform::RenderTransform() +{ +} + + +RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) +{ + assert(lhs && rhs); + + auto dx = rhs->x * lhs->factor; + auto dy = rhs->y * lhs->factor; + auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; + auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; + + x = lhs->x + tx; + y = lhs->y + ty; + degree = lhs->degree + rhs->degree; + factor = lhs->factor * rhs->factor; + + update(); +} + +#endif //_TVG_RENDER_CPP_ diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index a581067b..74feb778 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_RENDER_COMMON_H_ -#define _TVG_RENDER_COMMON_H_ +#ifndef _TVG_RENDER_H_ +#define _TVG_RENDER_H_ namespace tvg { @@ -42,79 +42,10 @@ struct RenderTransform float degree = 0.0f; //rotation degree float factor = 1.0f; //scale factor - bool update() - { - constexpr auto PI = 3.141592f; + bool update(); - //Init Status - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && - fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { - return false; - } - - //identity - e11 = 1.0f; - e12 = 0.0f; - e13 = 0.0f; - e21 = 0.0f; - e22 = 1.0f; - e23 = 0.0f; - e31 = 0.0f; - e32 = 0.0f; - e33 = 1.0f; - - //scale - e11 *= factor; - e22 *= factor; - e33 *= factor; - - //rotation - if (fabsf(degree) > FLT_EPSILON) { - auto radian = degree / 180.0f * PI; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; - - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; - } - - e31 += x; - e32 += y; - - return true; - } - - RenderTransform() - { - } - - RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) - { - assert(lhs && rhs); - - auto dx = rhs->x * lhs->factor; - auto dy = rhs->y * lhs->factor; - auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; - auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; - - x = lhs->x + tx; - y = lhs->y + ty; - degree = lhs->degree + rhs->degree; - factor = lhs->factor * rhs->factor; - - update(); - } + RenderTransform(); + RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; @@ -190,4 +121,4 @@ struct RenderInitializer } -#endif //_TVG_RENDER_COMMON_H_ +#endif //_TVG_RENDER_H_ \ No newline at end of file From ab5c1bc44180a256c6b9f02f26fcff40e7f0bf16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 17:06:53 +0900 Subject: [PATCH 101/244] common bezier: code refactoring. Organize bezier functions for internal share. this bezier can be used in svg loader. Change-Id: I78acd3273c0528688ca46ff7c29d78607bd729bd --- src/lib/meson.build | 2 + src/lib/sw_engine/tvgSwShape.cpp | 109 +---------------------- src/lib/tvgBezier.cpp | 144 +++++++++++++++++++++++++++++++ src/lib/tvgBezier.h | 39 +++++++++ src/lib/tvgCommon.h | 1 + src/lib/tvgRender.cpp | 2 - 6 files changed, 188 insertions(+), 109 deletions(-) create mode 100644 src/lib/tvgBezier.cpp create mode 100644 src/lib/tvgBezier.h diff --git a/src/lib/meson.build b/src/lib/meson.build index 96752064..53c9a19a 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,12 +4,14 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgBezier.h', 'tvgLoader.h', 'tvgLoaderMgr.h', 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', + 'tvgBezier.cpp', 'tvgCanvas.cpp', 'tvgFill.cpp', 'tvgGlCanvas.cpp', diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4d3c44ec..ee599df5 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -30,15 +30,6 @@ struct Line }; -struct Bezier -{ - Point start; - Point ctrl1; - Point ctrl2; - Point end; -}; - - static float _lineLength(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. @@ -64,102 +55,6 @@ static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right) } -static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right) -{ - auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; - left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; - right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; - left.start.x = cur.start.x; - right.end.x = cur.end.x; - left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; - right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; - left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; - - c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; - left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; - right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; - left.start.y = cur.start.y; - right.end.y = cur.end.y; - left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; - right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; - left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; -} - - -static float _bezLength(const Bezier& cur) -{ - Bezier left, right; - auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); - auto chord = _lineLength(cur.start, cur.end); - - if (fabs(len - chord) > FLT_EPSILON) { - _bezSplit(cur, left, right); - return _bezLength(left) + _bezLength(right); - } - return len; -} - - -static void _bezSplitLeft(Bezier& cur, float at, Bezier& left) -{ - left.start = cur.start; - - left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); - left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); - - left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot - left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot - - cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); - cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); - - cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); - cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); - - left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); - left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); - - left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); - left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); -} - - -static float _bezAt(const Bezier& bz, float at) -{ - auto len = _bezLength(bz); - auto biggest = 1.0f; - - if (at >= len) return 1.0f; - - at *= 0.5f; - - while (true) { - auto right = bz; - Bezier left; - _bezSplitLeft(right, at, left); - auto len2 = _bezLength(left); - - if (fabs(len2 - len) < FLT_EPSILON) break; - - if (len2 < len) { - at += (biggest - at) * 0.5f; - } else { - biggest = at; - at -= (at * 0.5f); - } - } - return at; -} - - -static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) -{ - right = cur; - auto t = _bezAt(right, at); - _bezSplitLeft(right, t, left); -} - - static void _growOutlineContour(SwOutline& outline, uint32_t n) { if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; @@ -407,7 +302,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to}; - auto len = _bezLength(cur); + auto len = bezLength(cur); if (len < dash.curLen) { dash.curLen -= len; @@ -419,7 +314,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct while (len > dash.curLen) { Bezier left, right; len -= dash.curLen; - _bezSplitAt(cur, dash.curLen, left, right); + bezSplitAt(cur, dash.curLen, left, right); dash.curIdx = (dash.curIdx + 1) % dash.cnt; if (!dash.curOpGap) { _outlineMoveTo(*dash.outline, &left.start); diff --git a/src/lib/tvgBezier.cpp b/src/lib/tvgBezier.cpp new file mode 100644 index 00000000..1aa2dab5 --- /dev/null +++ b/src/lib/tvgBezier.cpp @@ -0,0 +1,144 @@ +/* + * 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_BEZIER_CPP_ +#define _TVG_BEZIER_CPP_ + +#include "tvgCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static float _lineLength(const Point& pt1, const Point& pt2) +{ + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + if (diff.x < 0) diff.x = -diff.x; + if (diff.y < 0) diff.y = -diff.y; + return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +namespace tvg +{ + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +{ + auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; + left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; + right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; + left.start.x = cur.start.x; + right.end.x = cur.end.x; + left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; + right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; + left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; + + c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; + left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; + right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; + left.start.y = cur.start.y; + right.end.y = cur.end.y; + left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; + right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; + left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; +} + + +float bezLength(const Bezier& cur) +{ + Bezier left, right; + auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); + auto chord = _lineLength(cur.start, cur.end); + + if (fabs(len - chord) > FLT_EPSILON) { + bezSplit(cur, left, right); + return bezLength(left) + bezLength(right); + } + return len; +} + + +void bezSplitLeft(Bezier& cur, float at, Bezier& left) +{ + left.start = cur.start; + + left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); + left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); + + left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot + left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot + + cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); + cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); + + cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); + cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); + + left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); + left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); + + left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); + left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); +} + + +float bezAt(const Bezier& bz, float at) +{ + auto len = bezLength(bz); + auto biggest = 1.0f; + + if (at >= len) return 1.0f; + + at *= 0.5f; + + while (true) { + auto right = bz; + Bezier left; + bezSplitLeft(right, at, left); + auto len2 = bezLength(left); + + if (fabs(len2 - len) < FLT_EPSILON) break; + + if (len2 < len) { + at += (biggest - at) * 0.5f; + } else { + biggest = at; + at -= (at * 0.5f); + } + } + return at; +} + + +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) +{ + right = cur; + auto t = bezAt(right, at); + bezSplitLeft(right, t, left); +} + + +} + +#endif //_TVG_BEZIER_CPP_ diff --git a/src/lib/tvgBezier.h b/src/lib/tvgBezier.h new file mode 100644 index 00000000..aa7d77f0 --- /dev/null +++ b/src/lib/tvgBezier.h @@ -0,0 +1,39 @@ +/* + * 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_BEZIER_H_ +#define _TVG_BEZIER_H_ + +namespace tvg +{ + +struct Bezier +{ + Point start; + Point ctrl1; + Point ctrl2; + Point end; +}; + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right); +float bezLength(const Bezier& cur); +void bezSplitLeft(Bezier& cur, float at, Bezier& left); +float bezAt(const Bezier& bz, float at); +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right); + +} + +#endif //_TVG_BEZIER_H_ \ No newline at end of file diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2b0e9c18..302f4e91 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,7 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgBezier.h" #include "tvgLoader.h" #include "tvgLoaderMgr.h" #include "tvgRender.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4b4afc3b..bffbe400 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -18,8 +18,6 @@ #define _TVG_RENDER_CPP_ #include "tvgCommon.h" -#include "tvgRender.h" - /************************************************************************/ /* Internal Class Implementation */ From c6742e9590ba243cd7f2eefed511e4adf72d68e4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 20:53:52 +0900 Subject: [PATCH 102/244] common transform: support matrix transform interface. this interface is designed for user-defined arbitrary affine-transform paints. required by svg loader. Change-Id: I7f08023605d224e36cef3770098d3757aee81848 --- .gitignore | 1 + inc/tizenvg.h | 33 ++++---- src/lib/sw_engine/tvgSwFill.cpp | 14 ++-- src/lib/sw_engine/tvgSwShape.cpp | 4 +- src/lib/tvgRender.cpp | 70 +++++++++------- src/lib/tvgRender.h | 8 +- src/lib/tvgScene.cpp | 11 +++ src/lib/tvgSceneImpl.h | 64 ++++++++------ src/lib/tvgShape.cpp | 13 ++- src/lib/tvgShapeImpl.h | 68 +++++++++------ test/makefile | 1 + test/testCustomTransform.cpp | 140 +++++++++++++++++++++++++++++++ 12 files changed, 317 insertions(+), 110 deletions(-) create mode 100644 test/testCustomTransform.cpp diff --git a/.gitignore b/.gitignore index 7aa8bd7f..c2b9a6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ testUpdate testDirectUpdate testScene testTransform +testCustomTransform testSceneTransform testStroke testStrokeLine diff --git a/inc/tizenvg.h b/inc/tizenvg.h index bc541b31..a7eede4c 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -78,6 +78,14 @@ struct Point }; +struct Matrix +{ + float e11, e12, e13; + float e21, e22, e23; + float e31, e32, e33; +}; + + /** * @class Paint * @@ -91,12 +99,6 @@ class TVG_EXPORT Paint public: virtual ~Paint() {} - virtual Result rotate(float degree) = 0; - virtual Result scale(float factor) = 0; - virtual Result translate(float x, float y) = 0; - - virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; - _TVG_DECALRE_IDENTIFIER(); }; @@ -242,16 +244,17 @@ public: Result fill(std::unique_ptr f) noexcept; //Transform - Result rotate(float degree) noexcept override; - Result scale(float factor) noexcept override; - Result translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept; + Result scale(float factor) noexcept; + Result translate(float x, float y) noexcept; + Result transform(const Matrix& m) noexcept; //Getters uint32_t pathCommands(const PathCommand** cmds) const noexcept; uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; const Fill* fill() const noexcept; - Result bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result bounds(float* x, float* y, float* w, float* h) const noexcept; float strokeWidth() const noexcept; Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; @@ -282,14 +285,14 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; - Result load(const std::string& path) noexcept; - Result rotate(float degree) noexcept override; - Result scale(float factor) noexcept override; - Result translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept; + Result scale(float factor) noexcept; + Result translate(float x, float y) noexcept; + Result transform(const Matrix& m) noexcept; - Result bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result bounds(float* x, float* y, float* w, float* h) const noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index f6091837..0bf30248 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -100,12 +100,12 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTran auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; - y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; + x1 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; + y1 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; - y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; + x2 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; + y2 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; } fill->linear.dx = x2 - x1; @@ -131,11 +131,11 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTran if (radius < FLT_EPSILON) return true; if (transform) { - auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; - auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; + auto tx = fill->radial.cx * transform->m.e11 + fill->radial.cy * transform->m.e12 + transform->m.e31; + auto ty = fill->radial.cx * transform->m.e21 + fill->radial.cy * transform->m.e22 + transform->m.e32; fill->radial.cx = tx; fill->radial.cy = ty; - radius *= transform->e33; + radius *= transform->m.e33; } fill->radial.a = radius * radius; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4d3c44ec..6d8c9f2d 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -347,8 +347,8 @@ static void _transformOutline(SwOutline* outline, const RenderTransform* transfo for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; - auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; + auto tx = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; + auto ty = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; auto pt = Point{tx, ty}; outline->pts[i] = TO_SWPOINT(&pt); } diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4b4afc3b..cd9dff26 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -30,10 +30,24 @@ /* External Class Implementation */ /************************************************************************/ +void RenderTransform::override(const Matrix& m) +{ + this->m = m; + + if (m.e11 == 0.0f && m.e12 == 0.0f && m.e13 == 0.0f && + m.e21 == 0.0f && m.e22 == 0.0f && m.e23 == 0.0f && + m.e31 == 0.0f && m.e32 == 0.0f && m.e33 == 0.0f) { + overriding = false; + } else overriding = true; +} + + bool RenderTransform::update() { constexpr auto PI = 3.141592f; + if (overriding) return true; + //Init Status if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { @@ -41,20 +55,20 @@ bool RenderTransform::update() } //identity - e11 = 1.0f; - e12 = 0.0f; - e13 = 0.0f; - e21 = 0.0f; - e22 = 1.0f; - e23 = 0.0f; - e31 = 0.0f; - e32 = 0.0f; - e33 = 1.0f; + m.e11 = 1.0f; + m.e12 = 0.0f; + m.e13 = 0.0f; + m.e21 = 0.0f; + m.e22 = 1.0f; + m.e23 = 0.0f; + m.e31 = 0.0f; + m.e32 = 0.0f; + m.e33 = 1.0f; //scale - e11 *= factor; - e22 *= factor; - e33 *= factor; + m.e11 *= factor; + m.e22 *= factor; + m.e33 *= factor; //rotation if (fabsf(degree) > FLT_EPSILON) { @@ -62,23 +76,23 @@ bool RenderTransform::update() auto cosVal = cosf(radian); auto sinVal = sinf(radian); - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; + auto t11 = m.e11 * cosVal + m.e12 * sinVal; + auto t12 = m.e11 * -sinVal + m.e12 * cosVal; + auto t21 = m.e21 * cosVal + m.e22 * sinVal; + auto t22 = m.e21 * -sinVal + m.e22 * cosVal; + auto t31 = m.e31 * cosVal + m.e32 * sinVal; + auto t32 = m.e31 * -sinVal + m.e32 * cosVal; - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; + m.e11 = t11; + m.e12 = t12; + m.e21 = t21; + m.e22 = t22; + m.e31 = t31; + m.e32 = t32; } - e31 += x; - e32 += y; + m.e31 += x; + m.e32 += y; return true; } @@ -95,8 +109,8 @@ RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransfo auto dx = rhs->x * lhs->factor; auto dy = rhs->y * lhs->factor; - auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; - auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; + auto tx = dx * lhs->m.e11 + dy * lhs->m.e12 + lhs->m.e13; + auto ty = dx * lhs->m.e21 + dy * lhs->m.e22 + lhs->m.e23; x = lhs->x + tx; y = lhs->y + ty; diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 74feb778..8e9a50f3 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -32,17 +32,15 @@ enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, struct RenderTransform { - //3x3 Matrix Elements - float e11, e12, e13; - float e21, e22, e23; - float e31, e32, e33; - + Matrix m; //3x3 Matrix Elements float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree float factor = 1.0f; //scale factor + bool overriding = false; //user transform? bool update(); + void override(const Matrix& m); RenderTransform(); RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 41620a0b..1980d96a 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -97,6 +97,17 @@ Result Scene::translate(float x, float y) noexcept } +Result Scene::transform(const Matrix& m) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (!impl->transform(m)) return Result::FailedAllocation; + + return Result::Success; +} + + Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 5e67a666..4e412d47 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -26,7 +26,7 @@ struct Scene::Impl { vector paints; - RenderTransform *transform = nullptr; + RenderTransform *rTransform = nullptr; uint32_t flag = RenderUpdateFlag::None; unique_ptr loader = nullptr; @@ -34,7 +34,7 @@ struct Scene::Impl { //Are you sure clear() prior to this? assert(paints.empty()); - if (transform) delete(transform); + if (rTransform) delete(rTransform); } bool clear(RenderMethod& renderer) @@ -82,20 +82,20 @@ struct Scene::Impl } if (flag & RenderUpdateFlag::Transform) { - if (!transform) return false; - if (!transform->update()) { - delete(transform); - transform = nullptr; + if (!rTransform) return false; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; } } auto ret = true; - if (transform && pTransform) { - RenderTransform outTransform(pTransform, transform); + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); ret = updateInternal(renderer, &outTransform, pFlag | flag); } else { - auto outTransform = pTransform ? pTransform : transform; + auto outTransform = pTransform ? pTransform : rTransform; ret = updateInternal(renderer, outTransform, pFlag | flag); } @@ -158,14 +158,14 @@ struct Scene::Impl bool scale(float factor) { - if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->factor = factor; + rTransform->factor = factor; flag |= RenderUpdateFlag::Transform; return true; @@ -173,14 +173,14 @@ struct Scene::Impl bool rotate(float degree) { - if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; } else { if (fabsf(degree) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->degree = degree; + rTransform->degree = degree; flag |= RenderUpdateFlag::Transform; return true; @@ -188,20 +188,34 @@ struct Scene::Impl bool translate(float x, float y) { - if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; } else { if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->x = x; - transform->y = y; + rTransform->x = x; + rTransform->y = y; flag |= RenderUpdateFlag::Transform; return true; } + + bool transform(const Matrix& m) + { + if (!rTransform) { + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->override(m); + flag |= RenderUpdateFlag::Transform; + + return true; + } + + Result load(const string& path) { if (loader) loader->close(); diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index aabd5bd2..f7699b4b 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -303,7 +303,18 @@ Result Shape::translate(float x, float y) noexcept auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; - impl->translate(x, y); + if (!impl->translate(x, y)) return Result::FailedAllocation; + + return Result::Success; +} + + +Result Shape::transform(const Matrix& m) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (!impl->transform(m)) return Result::FailedAllocation; return Result::Success; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 4cce022d..fa670f01 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -44,7 +44,7 @@ struct Shape::Impl ShapePath *path = nullptr; Fill *fill = nullptr; ShapeStroke *stroke = nullptr; - RenderTransform *transform = nullptr; + RenderTransform *rTransform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a uint32_t flag = RenderUpdateFlag::None; void *edata = nullptr; //engine data @@ -59,7 +59,7 @@ struct Shape::Impl if (path) delete(path); if (fill) delete(fill); if (stroke) delete(stroke); - if (transform) delete(transform); + if (rTransform) delete(rTransform); } bool dispose(Shape& shape, RenderMethod& renderer) @@ -75,18 +75,18 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { - if (!transform) return false; - if (!transform->update()) { - delete(transform); - transform = nullptr; + if (!rTransform) return false; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; } } - if (transform && pTransform) { - RenderTransform outTransform(pTransform, transform); + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); edata = renderer.prepare(shape, edata, &outTransform, static_cast(pFlag | flag)); } else { - auto outTransform = pTransform ? pTransform : transform; + auto outTransform = pTransform ? pTransform : rTransform; edata = renderer.prepare(shape, edata, outTransform, static_cast(pFlag | flag)); } @@ -104,50 +104,64 @@ struct Shape::Impl bool scale(float factor) { - if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->factor = factor; - flag |= RenderUpdateFlag::Transform; + rTransform->factor = factor; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; return true; } bool rotate(float degree) { - if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; } else { if (fabsf(degree) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->degree = degree; - flag |= RenderUpdateFlag::Transform; + rTransform->degree = degree; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; return true; } bool translate(float x, float y) { - if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; } else { if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->x = x; - transform->y = y; + rTransform->x = x; + rTransform->y = y; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; + } + + + bool transform(const Matrix& m) + { + if (!rTransform) { + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->override(m); flag |= RenderUpdateFlag::Transform; return true; } + bool strokeWidth(float width) { //TODO: Size Exception? diff --git a/test/makefile b/test/makefile index 501eef58..f6624fc8 100755 --- a/test/makefile +++ b/test/makefile @@ -9,6 +9,7 @@ all: 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` diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp new file mode 100644 index 00000000..ae3d7c83 --- /dev/null +++ b/test/testCustomTransform.cpp @@ -0,0 +1,140 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::Shape* pShape = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape1 + auto shape = tvg::Shape::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->moveTo(0, -114.5); + shape->lineTo(54, -5.5); + shape->lineTo(175, 11.5); + shape->lineTo(88, 95.5); + shape->lineTo(108, 216.5); + shape->lineTo(0, 160.5); + shape->lineTo(-102, 216.5); + shape->lineTo(-87, 96.5); + shape->lineTo(-173, 12.5); + shape->lineTo(-53, -5.5); + 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) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + //Transform Matrix + tvg::Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + + //scale x + m.e11 = 1 - (progress * 0.5f); + + //scale y + m.e22 = 1 + (progress * 2.0f); + + //rotation + constexpr auto PI = 3.141592f; + auto degree = 45.0f; + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = m.e11 * cosVal + m.e12 * sinVal; + auto t12 = m.e11 * -sinVal + m.e12 * cosVal; + auto t21 = m.e21 * cosVal + m.e22 * sinVal; + auto t22 = m.e21 * -sinVal + m.e22 * cosVal; + auto t31 = m.e31 * cosVal + m.e32 * sinVal; + auto t32 = m.e31 * -sinVal + m.e32 * cosVal; + + m.e11 = t11; + m.e12 = t12; + m.e21 = t21; + m.e22 = t22; + m.e31 = t31; + m.e32 = t32; + + //translate + m.e31 = progress * 300.0f + 300.0f; + m.e32 = progress * -100.0f + 300.0f; + + pShape->transform(m); + + //Update shape for drawing (this may work asynchronously) + canvas->update(pShape); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + 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 TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} From 4f48c856f6f965390e198c2a6c52cdb99e287bf7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 14:14:47 +0900 Subject: [PATCH 103/244] sw_engie: fix wrong boundary check. this bounding box max indicates absolute positions, not width/height size. because of this, shape couldn't rendered properly, when it's clipped out. Change-Id: I0afb0d6e63d1b511b83716c55f55e3fd5370fdb8 --- src/lib/sw_engine/tvgSwShape.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 723650be..22fed2c1 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -225,9 +225,7 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; //Check boundary - if ((bbox.min.x > clip.w || bbox.min.y > clip.h) || - (bbox.min.x + bbox.max.x < 0) || - (bbox.min.y + bbox.max.y < 0)) return false; + if (bbox.min.x >= clip.w || bbox.min.y >= clip.h || bbox.max.x <= 0 || bbox.max.y <= 0) return false; return true; } From 86300c5fc05a9e0b269f2f1a624c7c1f77fd5913 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 14:41:57 +0900 Subject: [PATCH 104/244] sw_engine: optimize raster. memset() is more than 10x faster than manual loop. Thus we replace it to manipulate buffer pixels. Change-Id: If0f255578f7d49ff6704c4f15e2eefe435cc3c15 --- meson.build | 2 +- src/lib/sw_engine/tvgSwCommon.h | 17 +++++++++++++++ src/lib/sw_engine/tvgSwFill.cpp | 25 +--------------------- src/lib/sw_engine/tvgSwRaster.cpp | 33 ++++++++++++++++++++++------- src/lib/sw_engine/tvgSwRenderer.cpp | 13 ++---------- test/makefile | 0 6 files changed, 46 insertions(+), 44 deletions(-) mode change 100755 => 100644 test/makefile diff --git a/meson.build b/meson.build index 5692fbce..6693650e 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('tizenvg', 'cpp', - default_options : ['buildtype=debug', 'werror=false', 'cpp_std=c++14'], + default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14', 'optimization=s'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index eedaf9d9..076cccdb 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -19,6 +19,16 @@ #include "tvgCommon.h" +#if 1 +#include +static double timeStamp() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec + tv.tv_usec / 1000000.0); +} +#endif + using namespace tvg; #define SW_CURVE_TYPE_POINT 0 @@ -230,6 +240,12 @@ static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t } +static inline void COLOR_SET(uint32_t *dst, uint32_t val, uint32_t len) +{ + while (len--) *dst++ = val; +} + + int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -273,5 +289,6 @@ void rleFree(SwRleData* rle); bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterClear(Surface& surface); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 0bf30248..bd7f81e7 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -181,29 +181,6 @@ static inline uint32_t _pixel(const SwFill* fill, float pos) } -static inline void _write(uint32_t *dst, uint32_t val, uint32_t len) -{ - if (len <= 0) return; - - // Cute hack to align future memcopy operation - // and do unroll the loop a bit. Not sure it is - // the most efficient, but will do for now. - auto n = (len + 7) / 8; - - switch (len & 0x07) { - case 0: do { *dst++ = val; - case 7: *dst++ = val; - case 6: *dst++ = val; - case 5: *dst++ = val; - case 4: *dst++ = val; - case 3: *dst++ = val; - case 2: *dst++ = val; - case 1: *dst++ = val; - } while (--n > 0); - } -} - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -244,7 +221,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); - _write(dst, color, len); + COLOR_SET(dst, color, len); return; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 05f23e61..05429f3c 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,20 +24,22 @@ /* Internal Class Implementation */ /************************************************************************/ + static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color) { if (!rle) return false; auto span = rle->spans; auto stride = surface.stride; - uint32_t tmp; + uint32_t src; for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; - if (span->coverage < 255) tmp = COLOR_ALPHA_BLEND(color, span->coverage); - else tmp = color; + if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage); + else src = color; + auto ialpha = 255 - COLOR_ALPHA(src); for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); } ++span; } @@ -55,12 +57,12 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = color; - } + COLOR_SET(dst, color, span->len); } else { + auto src = COLOR_ALPHA_BLEND(color, span->coverage); + auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(color, span->coverage) + COLOR_ALPHA_BLEND(dst[i], 255 - span->coverage); + dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -188,4 +190,19 @@ bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_ } +bool rasterClear(Surface& surface) +{ + if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; + + if (surface.w == surface.stride) { + COLOR_SET(surface.buffer, 0xff000000, surface.w * surface.h); + } else { + for (uint32_t i = 0; i < surface.h; i++) { + COLOR_SET(surface.buffer + surface.stride * i, 0xff000000, surface.w); + } + } + return true; +} + + #endif /* _TVG_SW_RASTER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index adeb7388..9a5db51e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -20,6 +20,7 @@ #include "tvgSwCommon.h" #include "tvgSwRenderer.h" + /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ @@ -32,17 +33,7 @@ static RenderInitializer renderInit; bool SwRenderer::clear() { - if (!surface.buffer) return false; - - assert(surface.stride > 0 && surface.w > 0 && surface.h > 0); - - //OPTIMIZE ME: SIMD! - for (uint32_t i = 0; i < surface.h; i++) { - for (uint32_t j = 0; j < surface.w; j++) - surface.buffer[surface.stride * i + j] = 0xff000000; //Solid Black - } - - return true; + return rasterClear(surface); } bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) diff --git a/test/makefile b/test/makefile old mode 100755 new mode 100644 From 55e215e6ea50c35dbaeb720cec2c75b7877cc3a2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 17:29:28 +0900 Subject: [PATCH 105/244] sw_engine: optimize span generation. there are unnecessary partial spans generated in orthogonal rectangle. we can merge those partial spans to others if they are on the same scanline... Change-Id: I35a437a4f2eec106bd50f46f0390c652e617311d --- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwFill.cpp | 9 ++++----- src/lib/sw_engine/tvgSwRle.cpp | 10 ++++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 076cccdb..71af7df8 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -19,7 +19,7 @@ #include "tvgCommon.h" -#if 1 +#if 0 #include static double timeStamp() { diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index bd7f81e7..2a9ba698 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -189,7 +189,7 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, { if (fill->radial.a < FLT_EPSILON) return; - //TODO: Rotation??? + //Rotation auto rx = x + 0.5f - fill->radial.cx; auto ry = y + 0.5f - fill->radial.cy; auto inv2a = fill->radial.inv2a; @@ -199,13 +199,12 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, auto detDelta = (4 * fill->radial.a * (rxryPlus + 1.0f)) * inv2a; auto detDelta2 = (4 * fill->radial.a * 2.0f) * inv2a; - for (uint32_t i = 0 ; i < len ; ++i) - { + for (uint32_t i = 0 ; i < len ; ++i) { *dst = _pixel(fill, sqrt(det)); ++dst; det += detDelta; detDelta += detDelta2; - } + } } @@ -213,7 +212,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, { if (fill->linear.len < FLT_EPSILON) return; - //TODO: Rotation??? + //Rotation auto rx = x + 0.5f; auto ry = y + 0.5f; auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index cab54631..5d7d5a73 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -195,7 +195,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor y = SHRT_MAX; } - if (coverage) { + if (coverage > 0) { auto count = rw.spansCnt; auto span = rw.spans + count - 1; assert(span); @@ -209,13 +209,15 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); if (x < 0) xOver += x; - span->len += (acount + xOver) - 1; + //span->len += (acount + xOver) - 1; + span->len += (acount + xOver); return; } if (count >= MAX_SPANS) { _genSpan(rw.rle, rw.spans, count); rw.spansCnt = 0; + rw.ySpan = 0; span = rw.spans; assert(span); } else { @@ -240,6 +242,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor span->len = (acount + xOver); span->coverage = coverage; ++rw.spansCnt; + rw.ySpan = y; } } @@ -249,6 +252,7 @@ static void _sweep(RleWorker& rw) if (rw.cellsCnt == 0) return; rw.spansCnt = 0; + rw.ySpan = 0; for (int y = 0; y < rw.yCnt; ++y) { auto cover = 0; @@ -775,6 +779,4 @@ void rleFree(SwRleData* rle) free(rle); } - - #endif /* _TVG_SW_RLE_H_ */ From b212df1061a96232035e6e6de650e001ead17258 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 17:38:59 +0900 Subject: [PATCH 106/244] sw_engine stroke: initialize a missing variable. Change-Id: I1c3d83d56045f592ff89a5462d4de494e50c9d34 --- src/lib/sw_engine/tvgSwStroke.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 8b6f1ce4..94a25370 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -297,13 +297,11 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) auto border = stroke.borders + side; auto theta = mathDiff(stroke.angleIn, stroke.angleOut) / 2; SwPoint delta; - bool intersect; + bool intersect = false; /* Only intersect borders if between two line_to's and both lines are long enough (line length is zero fur curves). */ - if (!border->movable || lineLength == 0) { - intersect = false; - } else { + if (border->movable && lineLength > 0) { //compute minimum required length of lines SwFixed minLength = abs(mathMultiply(stroke.width, mathTan(theta))); if (stroke.lineLength >= minLength && lineLength >= minLength) intersect = true; From 9ffc1d40f6f9f1ffd439c5b25cfb3918ac96fc77 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 18:59:12 +0900 Subject: [PATCH 107/244] sw_engine: optimize memory allocation. there are a logical wrong that memory increase size, it correct that also tune the number to reduce memory allocation time. Now scene transform test works smoothly. Change-Id: If0674e33426d794546801a96ad9de711b5de0dcd --- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5d7d5a73..5bb3a319 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -147,9 +147,9 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, uint32_t count) /* alloc is required to prevent free and reallocation */ /* when the rle needs to be regenerated because of attribute change. */ if (rle->alloc < newSize) { - rle->spans = static_cast(realloc(rle->spans, (count + rle->size) << 2 * sizeof(SwSpan))); + rle->alloc = (newSize * 2); + rle->spans = static_cast(realloc(rle->spans, rle->alloc * sizeof(SwSpan))); assert(rle->spans); - rle->alloc = rle->size + (count << 2); } //copy the new spans to the allocated memory From 35803e9c2b145bdfe19d50f1ab99edf3cdd7efa8 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 13:31:09 +0900 Subject: [PATCH 108/244] test: add stress test for performance profiling. Change-Id: I4a1556c107ba59b7c972375ab8bfd22c777a5503 --- .gitignore | 1 + test/makefile | 1 + test/testStress.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 test/testStress.cpp diff --git a/.gitignore b/.gitignore index c2b9a6c0..c8da1b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ testRadialGradient testGradientTransform testSvg testGlShape +testStress diff --git a/test/makefile b/test/makefile index f6624fc8..9f776483 100644 --- a/test/makefile +++ b/test/makefile @@ -18,3 +18,4 @@ all: 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 testStress testStress.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testStress.cpp b/test/testStress.cpp new file mode 100644 index 00000000..2c1020e3 --- /dev/null +++ b/test/testStress.cpp @@ -0,0 +1,117 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 +#define COUNT 50 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); +} + +Eina_Bool anim_cb(void *data) +{ + static unsigned cnt = 0; + + //Explicitly clear all retained paint nodes. + double t1 = ecore_time_get(); + canvas->clear(); + double t2 = ecore_time_get(); + + for (int i = 0; i < COUNT; i++) { + auto shape = tvg::Shape::gen(); + + float x = rand() % 400; + float y = rand() % 400; + float w = 1 + rand() % 600; + float h = 1 + rand() % 600; + + shape->appendRect(x, y, w, h, rand() % 400); + + if (rand() % 2) { + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(x, y, x + w, y + h); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[1] = {1, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[2] = {2, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + + fill->colorStops(colorStops, 3); + shape->fill(move(fill)); + } else { + shape->fill(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); + } +#if 0 + if (rand() % 2) { + shape->stroke(float(rand() % 10)); + shape->stroke(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); + } +#endif + canvas->push(move(shape)); + } + + double t3 = ecore_time_get(); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + double t4 = ecore_time_get(); + + printf("[%5d]: total[%fms] = clear[%fms] + update[%fms] + render[%fms]\n", ++cnt, t4 - t1, t2 - t1, t3 - t2, t4 - t3); + + //Update Efl Canvas + Eo* img = (Eo*) data; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + + return ECORE_CALLBACK_RENEW; +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG 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); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + ecore_animator_add(anim_cb, img); + + elm_run(); + elm_shutdown(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} From 36c76ca73ca4791ee1d42d14dde16dda3f4f4b9f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 20:12:39 +0900 Subject: [PATCH 109/244] sw_engine: threading optimization make it prepare step asynchronously. Change-Id: Ifb85f01d579cf1c111558842496b93fcaef74cd9 --- src/lib/sw_engine/tvgSwCommon.h | 32 +++++--- src/lib/sw_engine/tvgSwFill.cpp | 22 +++--- src/lib/sw_engine/tvgSwRenderer.cpp | 109 +++++++++++++++------------- src/lib/sw_engine/tvgSwShape.cpp | 67 ++++++++--------- src/lib/sw_engine/tvgSwStroke.cpp | 10 ++- src/lib/tvgCanvasImpl.h | 10 +-- src/meson.build | 3 +- test/testBlending.cpp | 3 +- test/testBoundary.cpp | 3 +- test/testCustomTransform.cpp | 3 +- test/testGlShape.cpp | 15 ++-- test/testGradientTransform.cpp | 3 +- test/testLinearGradient.cpp | 3 +- test/testMultiShapes.cpp | 3 +- test/testPath.cpp | 3 +- test/testPathCopy.cpp | 3 +- test/testRadialGradient.cpp | 3 +- test/testScene.cpp | 3 +- test/testSceneTransform.cpp | 3 +- test/testShape.cpp | 3 +- test/testStress.cpp | 48 ++++++------ test/testStroke.cpp | 4 +- test/testStrokeLine.cpp | 3 +- test/testSvg.cpp | 3 +- test/testTransform.cpp | 3 +- test/testUpdate.cpp | 3 +- 26 files changed, 186 insertions(+), 182 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 71af7df8..9c540888 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -17,6 +17,8 @@ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ +#include +#include #include "tvgCommon.h" #if 0 @@ -201,6 +203,16 @@ struct SwShape }; +struct SwTask +{ + SwShape shape; + const Shape* sdata; + SwSize clip; + const Matrix* transform; + RenderUpdateFlag flags; + future prepared; +}; + static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; @@ -261,24 +273,24 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); -bool shapeGenOutline(SwShape& shape, const Shape& sdata); -bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform); +bool shapeGenOutline(SwShape& shape, const Shape* sdata); +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); void shapeDelOutline(SwShape& shape); -void shapeResetStroke(SwShape& shape, const Shape& sdata); -bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); -void shapeFree(SwShape* shape); +void shapeResetStroke(SwShape& shape, const Shape* sdata); +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip); +void shapeFree(SwShape& shape); void shapeDelStroke(SwShape& shape); -bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable); -void shapeResetFill(SwShape& shape, const Fill* fill); +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable); +void shapeResetFill(SwShape& shape); void shapeDelFill(SwShape& shape); -void strokeReset(SwStroke& stroke, const Shape& shape); +void strokeReset(SwStroke& stroke, const Shape* shape); bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable); -void fillReset(SwFill* fill, const Fill* fdata); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); +void fillReset(SwFill* fill); void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 2a9ba698..5992bcaa 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -88,7 +88,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) } -bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTransform* transform) +bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* transform) { assert(fill && linear); @@ -100,12 +100,12 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTran auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; - y1 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; - y2 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; } fill->linear.dx = x2 - x1; @@ -122,7 +122,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTran } -bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTransform* transform) +bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform) { assert(fill && radial); @@ -131,11 +131,11 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTran if (radius < FLT_EPSILON) return true; if (transform) { - auto tx = fill->radial.cx * transform->m.e11 + fill->radial.cy * transform->m.e12 + transform->m.e31; - auto ty = fill->radial.cx * transform->m.e21 + fill->radial.cy * transform->m.e22 + transform->m.e32; + auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; + auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; fill->radial.cx = tx; fill->radial.cy = ty; - radius *= transform->m.e33; + radius *= transform->e33; } fill->radial.a = radius * radius; @@ -248,7 +248,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable) { if (!fill) return false; @@ -272,7 +272,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* t } -void fillReset(SwFill* fill, const Fill* fdata) +void fillReset(SwFill* fill) { if (fill->ctable) { free(fill->ctable); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 9a5db51e..8c59029c 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -36,6 +36,7 @@ bool SwRenderer::clear() return rasterClear(surface); } + 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; @@ -48,22 +49,25 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t return true; } + bool SwRenderer::render(const Shape& sdata, void *data) { - SwShape* shape = static_cast(data); - if (!shape) return false; + auto task = static_cast(data); + if (!task) return false; + + if (task->prepared.valid()) task->prepared.get(); uint8_t r, g, b, a; if (auto fill = sdata.fill()) { - rasterGradientShape(surface, *shape, fill->id()); + rasterGradientShape(surface, task->shape, fill->id()); } else { sdata.fill(&r, &g, &b, &a); - if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a); + if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); } sdata.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, *shape, r, g, b, a); + if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); return true; } @@ -71,67 +75,74 @@ bool SwRenderer::render(const Shape& sdata, void *data) bool SwRenderer::dispose(const Shape& sdata, void *data) { - auto shape = static_cast(data); - if (!shape) return true; - shapeFree(shape); + auto task = static_cast(data); + if (!task) return true; + if (task->prepared.valid()) task->prepared.wait(); + shapeFree(task->shape); + free(task); return true; } void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { - //prepare shape data - auto shape = static_cast(data); - if (!shape) { - shape = static_cast(calloc(1, sizeof(SwShape))); - assert(shape); + //prepare task + auto task = static_cast(data); + if (!task) { + task = static_cast(calloc(1, sizeof(SwTask))); + if (!task) return nullptr; } - if (flags == RenderUpdateFlag::None) return shape; + if (flags == RenderUpdateFlag::None || task->prepared.valid()) return task; - //TODO: Threading + task->sdata = &sdata; + task->clip = {static_cast(surface.w), static_cast(surface.h)}; - SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; + if (transform) task->transform = &transform->m; + else task->transform = nullptr; - //Shape - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - shapeReset(*shape); - uint8_t alpha = 0; - sdata.fill(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0 || sdata.fill()) { - if (!shapeGenRle(*shape, sdata, clip, transform)) return shape; - } - } + task->flags = flags; - //Fill - if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { - auto fill = sdata.fill(); - if (fill) { - auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; - if (ctable) shapeResetFill(*shape, fill); - if (!shapeGenFillColors(*shape, fill, transform, ctable)) return shape; - } else { - shapeDelFill(*shape); - } - } - - //Stroke - if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (sdata.strokeWidth() > FLT_EPSILON) { - shapeResetStroke(*shape, sdata); + auto asyncTask = [](SwTask* task) { + //Shape + if (task->flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { + shapeReset(task->shape); uint8_t alpha = 0; - sdata.strokeColor(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0) { - if (!shapeGenStrokeRle(*shape, sdata, clip)) return shape; + task->sdata->fill(nullptr, nullptr, nullptr, &alpha); + if (alpha > 0 || task->sdata->fill()) { + if (!shapeGenRle(task->shape, task->sdata, task->clip, task->transform)) return; } - } else { - shapeDelStroke(*shape); } - } + //Fill + if (task->flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { + auto fill = task->sdata->fill(); + if (fill) { + auto ctable = (task->flags & RenderUpdateFlag::Gradient) ? true : false; + if (ctable) shapeResetFill(task->shape); + if (!shapeGenFillColors(task->shape, fill, task->transform, ctable)) return; + } else { + shapeDelFill(task->shape); + } + } + //Stroke + if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + if (task->sdata->strokeWidth() > FLT_EPSILON) { + 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; + } + } else { + shapeDelStroke(task->shape); + } + } + shapeDelOutline(task->shape); + }; - shapeDelOutline(*shape); + task->prepared = async((launch::async | launch::deferred), asyncTask, task); - return shape; + return task; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 22fed2c1..d9a4e816 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -231,17 +231,17 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi } -static void _transformOutline(SwOutline* outline, const RenderTransform* transform) +static void _transformOutline(SwOutline* outline, const Matrix* transform) { - assert(outline); - if (!transform) return; + assert(outline); + for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; - auto ty = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; auto pt = Point{tx, ty}; outline->pts[i] = TO_SWPOINT(&pt); } @@ -340,13 +340,15 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct } -SwOutline* _genDashOutline(const Shape& shape) +SwOutline* _genDashOutline(const Shape* sdata) { + assert(sdata); + const PathCommand* cmds = nullptr; - auto cmdCnt = shape.pathCommands(&cmds); + auto cmdCnt = sdata->pathCommands(&cmds); const Point* pts = nullptr; - auto ptsCnt = shape.pathCoords(&pts); + auto ptsCnt = sdata->pathCoords(&pts); //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return nullptr; @@ -359,7 +361,7 @@ SwOutline* _genDashOutline(const Shape& shape) dash.curOpGap = false; const float* pattern; - dash.cnt = shape.strokeDash(&pattern); + dash.cnt = sdata->strokeDash(&pattern); assert(dash.cnt > 0 && pattern); //Is it safe to mutual exclusive? @@ -440,7 +442,7 @@ SwOutline* _genDashOutline(const Shape& shape) /* External Class Implementation */ /************************************************************************/ -bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform) +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) { if (!shapeGenOutline(shape, sdata)) return false; @@ -474,13 +476,15 @@ void shapeReset(SwShape& shape) } -bool shapeGenOutline(SwShape& shape, const Shape& sdata) +bool shapeGenOutline(SwShape& shape, const Shape* sdata) { + assert(sdata); + const PathCommand* cmds = nullptr; - auto cmdCnt = sdata.pathCommands(&cmds); + auto cmdCnt = sdata->pathCommands(&cmds); const Point* pts = nullptr; - auto ptsCnt = sdata.pathCoords(&pts); + auto ptsCnt = sdata->pathCoords(&pts); //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return false; @@ -559,19 +563,15 @@ bool shapeGenOutline(SwShape& shape, const Shape& sdata) } -void shapeFree(SwShape* shape) +void shapeFree(SwShape& shape) { - assert(shape); + shapeDelOutline(shape); + rleFree(shape.rle); - shapeDelOutline(*shape); - rleFree(shape->rle); - - if (shape->stroke) { - rleFree(shape->strokeRle); - strokeFree(shape->stroke); + if (shape.stroke) { + rleFree(shape.strokeRle); + strokeFree(shape.stroke); } - - free(shape); } @@ -585,7 +585,7 @@ void shapeDelStroke(SwShape& shape) } -void shapeResetStroke(SwShape& shape, const Shape& sdata) +void shapeResetStroke(SwShape& shape, const Shape* sdata) { if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); auto stroke = shape.stroke; @@ -598,12 +598,14 @@ void shapeResetStroke(SwShape& shape, const Shape& sdata) } -bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) { + assert(sdata); + SwOutline* shapeOutline = nullptr; //Dash Style Stroke - if (sdata.strokeDash(nullptr) > 0) { + if (sdata->strokeDash(nullptr) > 0) { shapeOutline = _genDashOutline(sdata); if (!shapeOutline) return false; @@ -633,23 +635,18 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) } -bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable) +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable) { - assert(fill); - - fillGenColorTable(shape.fill, fill, transform, ctable); - return true; + return fillGenColorTable(shape.fill, fill, transform, ctable); } -void shapeResetFill(SwShape& shape, const Fill* fill) +void shapeResetFill(SwShape& shape) { - assert(fill); - if (!shape.fill) shape.fill = static_cast(calloc(1, sizeof(SwFill))); assert(shape.fill); - fillReset(shape.fill, fill); + fillReset(shape.fill); } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 94a25370..6ccfb7dc 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -816,13 +816,15 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, const Shape& shape) +void strokeReset(SwStroke& stroke, const Shape* sdata) { - stroke.width = TO_SWCOORD(shape.strokeWidth() * 0.5); - stroke.cap = shape.strokeCap(); + assert(sdata); + + stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); + stroke.cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... - stroke.joinSaved = stroke.join = shape.strokeJoin(); + stroke.joinSaved = stroke.join = sdata->strokeJoin(); stroke.borders[0].ptsCnt = 0; stroke.borders[0].start = -1; diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 42cf4707..ae0ce3c0 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -42,7 +42,7 @@ struct Canvas::Impl Result push(unique_ptr paint) { auto p = paint.release(); - assert(p); + if (!p) return Result::MemoryCorruption; paints.push_back(p); return update(p); @@ -50,7 +50,7 @@ struct Canvas::Impl Result clear() { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; for (auto paint : paints) { if (paint->id() == PAINT_ID_SCENE) { @@ -70,7 +70,7 @@ struct Canvas::Impl Result update() { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; for(auto paint: paints) { if (paint->id() == PAINT_ID_SCENE) { @@ -87,7 +87,7 @@ struct Canvas::Impl Result update(Paint* paint) { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. @@ -102,7 +102,7 @@ struct Canvas::Impl Result draw() { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; //Clear render target before drawing if (!renderer->clear()) return Result::InsufficientCondition; diff --git a/src/meson.build b/src/meson.build index e49c9a0d..b5000bc5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,10 +5,11 @@ subdir('loaders') subdir('examples') m_dep = meson.get_compiler('cpp').find_library('m') +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] +tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep, thread_dep] tizenvg_lib = library( diff --git a/test/testBlending.cpp b/test/testBlending.cpp index a5559d49..ebb3e67f 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -66,8 +66,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 701bb840..a71374a4 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -56,8 +56,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index ae3d7c83..cc0c8bbe 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -96,8 +96,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp index 3ff4a33c..8ad43ae0 100644 --- a/test/testGlShape.cpp +++ b/test/testGlShape.cpp @@ -9,8 +9,7 @@ using namespace std; static Evas_GL_API *glapi; static unique_ptr canvas; -static void -tvgtest() +void tvgtest() { //Create a Canvas canvas = tvg::GlCanvas::gen(); @@ -33,8 +32,7 @@ tvgtest() canvas->push(move(shape1)); } -static void -init_gl(Evas_Object *obj) +void init_gl(Evas_Object *obj) { //Initialize TizenVG Engine tvg::Initializer::init(tvg::CanvasEngine::Gl); @@ -42,15 +40,13 @@ init_gl(Evas_Object *obj) tvgtest(); } -static void -del_gl(Evas_Object *obj) +void del_gl(Evas_Object *obj) { //Terminate TizenVG Engine tvg::Initializer::term(tvg::CanvasEngine::Gl); } -static void -draw_gl(Evas_Object *obj) +void draw_gl(Evas_Object *obj) { Evas_GL_API *gl = elm_glview_gl_api_get(obj); int w, h; @@ -66,8 +62,7 @@ draw_gl(Evas_Object *obj) canvas->sync(); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 90fab168..428acc51 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -126,8 +126,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index decf263d..8016a451 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -84,8 +84,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index e6db3bb7..9fff6f05 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -44,8 +44,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testPath.cpp b/test/testPath.cpp index 3d520037..efb784fd 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -59,8 +59,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 8ce33c3c..4ba5941d 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -99,8 +99,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index b50204b8..e10be472 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -84,8 +84,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testScene.cpp b/test/testScene.cpp index e134237f..db6fd53d 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -90,8 +90,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 11dade09..1e411fe2 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -120,8 +120,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testShape.cpp b/test/testShape.cpp index 16fc1a0e..4cc1f7fe 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -38,8 +38,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testStress.cpp b/test/testStress.cpp index 2c1020e3..870742ed 100644 --- a/test/testStress.cpp +++ b/test/testStress.cpp @@ -3,12 +3,14 @@ using namespace std; -#define WIDTH 800 -#define HEIGHT 800 +#define WIDTH 1920 +#define HEIGHT 1080 #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() { @@ -19,20 +21,18 @@ void tvgtest() Eina_Bool anim_cb(void *data) { - static unsigned cnt = 0; - //Explicitly clear all retained paint nodes. - double t1 = ecore_time_get(); + t1 = ecore_time_get(); canvas->clear(); - double t2 = ecore_time_get(); + t2 = ecore_time_get(); for (int i = 0; i < COUNT; i++) { auto shape = tvg::Shape::gen(); - float x = rand() % 400; - float y = rand() % 400; - float w = 1 + rand() % 600; - float h = 1 + rand() % 600; + float x = rand() % (WIDTH/2); + float y = rand() % (HEIGHT/2); + float w = 1 + rand() % 1200; + float h = 1 + rand() % 800; shape->appendRect(x, y, w, h, rand() % 400); @@ -61,25 +61,28 @@ Eina_Bool anim_cb(void *data) canvas->push(move(shape)); } - double t3 = ecore_time_get(); - - //Draw Next frames - canvas->draw(); - canvas->sync(); - - double t4 = ecore_time_get(); - - printf("[%5d]: total[%fms] = clear[%fms] + update[%fms] + render[%fms]\n", ++cnt, t4 - t1, t2 - t1, t3 - t2, t4 - t3); - //Update Efl Canvas Eo* img = (Eo*) data; + evas_object_image_pixels_dirty_set(img, EINA_TRUE); evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); return ECORE_CALLBACK_RENEW; } -void -win_del(void *data, Evas_Object *o, void *ev) +void render_cb(void* data, Eo* obj) +{ + t3 = ecore_time_get(); + + //Draw Next frames + canvas->draw(); + canvas->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) { elm_exit(); } @@ -100,6 +103,7 @@ int main(int argc, char **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_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); diff --git a/test/testStroke.cpp b/test/testStroke.cpp index a7ae5d09..68bffa2c 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -83,13 +83,11 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -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) { tvgtest(); diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 61e035e5..3b6cc9df 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -119,8 +119,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testSvg.cpp b/test/testSvg.cpp index e9189023..cad2f1b7 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -29,8 +29,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testTransform.cpp b/test/testTransform.cpp index a99708d0..52227439 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -89,8 +89,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 0ee9412d..7111b21b 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -50,8 +50,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } From 4156de72f1cedc5aa01d41f5a9a5686ec5dcd662 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 17:10:50 +0900 Subject: [PATCH 110/244] sw_engine: optimize rasterizey by threading it. Also, newly introduced render interfaces: preRender(), postRender(), flush() Change-Id: If506fa27e3c7dbd89f6734cad4774c1d151b88aa --- inc/tizenvg.h | 5 +- src/lib/gl_engine/tvgGlRenderer.cpp | 20 +++++- src/lib/gl_engine/tvgGlRenderer.h | 4 +- src/lib/sw_engine/tvgSwCommon.h | 12 ---- src/lib/sw_engine/tvgSwRenderer.cpp | 103 ++++++++++++++++++++++------ src/lib/sw_engine/tvgSwRenderer.h | 25 ++++++- src/lib/sw_engine/tvgSwShape.cpp | 2 + src/lib/tvgCanvas.cpp | 11 +++ src/lib/tvgCanvasImpl.h | 9 ++- src/lib/tvgGlCanvas.cpp | 10 --- src/lib/tvgRender.h | 3 + src/lib/tvgSwCanvas.cpp | 7 +- test/testStress.cpp | 21 ++++-- 13 files changed, 166 insertions(+), 66 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index a7eede4c..a9e797fd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -153,7 +153,7 @@ public: virtual Result update() noexcept; virtual Result update(Paint* paint) noexcept; virtual Result draw(bool async = true) noexcept; - virtual Result sync() = 0; + virtual Result sync() noexcept; _TVG_DECLARE_ACCESSOR(Scene); _TVG_DECLARE_PRIVATE(Canvas); @@ -315,7 +315,6 @@ public: ~SwCanvas(); Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; - Result sync() noexcept override; static std::unique_ptr gen() noexcept; @@ -337,9 +336,7 @@ public: ~GlCanvas(); //TODO: Gl Specific methods. Need gl backend configuration methods as well. - Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; - Result sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index ecabf6ad..bef3871b 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -53,10 +53,28 @@ bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -void GlRenderer::flush() +bool GlRenderer::flush() { GL_CHECK(glFinish()); mColorProgram->unload(); + + return true; +} + + +bool GlRenderer::preRender() +{ + //TODO: called just before render() + + return true; +} + + +bool GlRenderer::postRender() +{ + //TODO: called just after render() + + return true; } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 5214a63d..7d0972a7 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -28,9 +28,11 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; + bool preRender() override; bool render(const Shape& shape, void *data) override; + bool postRender() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); - void flush(); + bool flush() override; bool clear() override; uint32_t ref() override; uint32_t unref() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 9c540888..72fa7006 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -17,8 +17,6 @@ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ -#include -#include #include "tvgCommon.h" #if 0 @@ -203,16 +201,6 @@ struct SwShape }; -struct SwTask -{ - SwShape shape; - const Shape* sdata; - SwSize clip; - const Matrix* transform; - RenderUpdateFlag flags; - future prepared; -}; - static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 8c59029c..2458cdb6 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -17,6 +17,8 @@ #ifndef _TVG_SW_RENDERER_CPP_ #define _TVG_SW_RENDERER_CPP_ +using namespace std; + #include "tvgSwCommon.h" #include "tvgSwRenderer.h" @@ -24,19 +26,37 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +namespace tvg { + struct SwTask + { + SwShape shape; + const Shape* sdata; + SwSize clip; + const Matrix* transform; + RenderUpdateFlag flags; + future progress; + }; +} static RenderInitializer renderInit; + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -bool SwRenderer::clear() +SwRenderer::~SwRenderer() { - return rasterClear(surface); + if (progress.valid()) progress.get(); } +bool SwRenderer::clear() +{ + if (progress.valid()) return false; + return true; +} + 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; @@ -50,24 +70,64 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } +bool SwRenderer::preRender() +{ + //before we start rendering, we should finish all preparing tasks + while (prepareTasks.size() > 0) { + auto task = prepareTasks.front(); + if (task->progress.valid()) task->progress.get(); + prepareTasks.pop(); + renderTasks.push(task); + } + return true; +} + + +bool SwRenderer::postRender() +{ + auto asyncTask = [](SwRenderer* renderer) { + renderer->doRender(); + }; + + progress = async(launch::async, asyncTask, this); + + return true; +} + + +void SwRenderer::doRender() +{ + rasterClear(surface); + + while (renderTasks.size() > 0) { + auto task = renderTasks.front(); + uint8_t r, g, b, a; + if (auto fill = task->sdata->fill()) { + rasterGradientShape(surface, task->shape, fill->id()); + } else{ + task->sdata->fill(&r, &g, &b, &a); + if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); + } + task->sdata->strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); + renderTasks.pop(); + } +} + + +bool SwRenderer::flush() +{ + if (progress.valid()) { + progress.get(); + return true; + } + return false; +} + + bool SwRenderer::render(const Shape& sdata, void *data) { - auto task = static_cast(data); - if (!task) return false; - - if (task->prepared.valid()) task->prepared.get(); - - uint8_t r, g, b, a; - - if (auto fill = sdata.fill()) { - rasterGradientShape(surface, task->shape, fill->id()); - } else { - sdata.fill(&r, &g, &b, &a); - if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); - } - - sdata.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); + //Do Nothing return true; } @@ -77,7 +137,7 @@ bool SwRenderer::dispose(const Shape& sdata, void *data) { auto task = static_cast(data); if (!task) return true; - if (task->prepared.valid()) task->prepared.wait(); + if (task->progress.valid()) task->progress.get(); shapeFree(task->shape); free(task); return true; @@ -93,7 +153,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (!task) return nullptr; } - if (flags == RenderUpdateFlag::None || task->prepared.valid()) return task; + if (flags == RenderUpdateFlag::None || task->progress.valid()) return task; task->sdata = &sdata; task->clip = {static_cast(surface.w), static_cast(surface.h)}; @@ -140,7 +200,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* shapeDelOutline(task->shape); }; - task->prepared = async((launch::async | launch::deferred), asyncTask, task); + prepareTasks.push(task); + task->progress = async((launch::async | launch::deferred), asyncTask, task); return task; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 4a4fafdb..3669d034 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -17,16 +17,26 @@ #ifndef _TVG_SW_RENDERER_H_ #define _TVG_SW_RENDERER_H_ +#include +#include +#include + +namespace tvg +{ + +struct SwTask; + class SwRenderer : public RenderMethod { public: - Surface surface; - void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; + bool preRender() override; bool render(const Shape& shape, void *data) override; + bool postRender() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool clear() override; + bool flush() override; uint32_t ref() override; uint32_t unref() override; @@ -34,9 +44,18 @@ public: static int init(); static int term(); + void doRender(); //Internally used for threading + private: + Surface surface; + future progress; + queue prepareTasks; + queue renderTasks; + SwRenderer(){}; - ~SwRenderer(){}; + ~SwRenderer(); }; +} + #endif /* _TVG_SW_RENDERER_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d9a4e816..9a79c6ed 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -568,6 +568,8 @@ void shapeFree(SwShape& shape) shapeDelOutline(shape); rleFree(shape.rle); + shapeDelFill(shape); + if (shape.stroke) { rleFree(shape.strokeRle); strokeFree(shape.stroke); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index dc05d666..01fcae1f 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -82,4 +82,15 @@ Result Canvas::update(Paint* paint) noexcept return impl->update(paint); } + +Result Canvas::sync() noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (impl->renderer->flush()) return Result::Success; + + return Result::InsufficientCondition; +} + #endif /* _TVG_CANVAS_CPP_ */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index ae0ce3c0..94737c92 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -52,6 +52,9 @@ struct Canvas::Impl { if (!renderer) return Result::InsufficientCondition; + //Clear render target before drawing + if (!renderer->clear()) return Result::InsufficientCondition; + for (auto paint : paints) { if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. @@ -104,8 +107,7 @@ struct Canvas::Impl { if (!renderer) return Result::InsufficientCondition; - //Clear render target before drawing - if (!renderer->clear()) return Result::InsufficientCondition; + if (!renderer->preRender()) return Result::InsufficientCondition; for(auto paint: paints) { if (paint->id() == PAINT_ID_SCENE) { @@ -117,6 +119,9 @@ struct Canvas::Impl if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; } } + + if (!renderer->postRender()) return Result::InsufficientCondition; + return Result::Success; } }; diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 80a00177..1af7eace 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -57,16 +57,6 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -Result GlCanvas::sync() noexcept -{ - auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); - assert(renderer); - - renderer->flush(); - return Result::Success; -} - - unique_ptr GlCanvas::gen() noexcept { auto canvas = unique_ptr(new GlCanvas); diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 8e9a50f3..b0a3c846 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -53,8 +53,11 @@ public: virtual ~RenderMethod() {} virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; + virtual bool preRender() = 0; virtual bool render(const Shape& shape, void *data) = 0; + virtual bool postRender() = 0; virtual bool clear() = 0; + virtual bool flush() = 0; virtual uint32_t ref() = 0; virtual uint32_t unref() = 0; }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 780e4636..a0bfdd04 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,6 +45,7 @@ SwCanvas::~SwCanvas() { } + Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { //We know renderer type, avoid dynamic_cast for performance. @@ -57,12 +58,6 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -Result SwCanvas::sync() noexcept -{ - return Result::Success; -} - - unique_ptr SwCanvas::gen() noexcept { auto canvas = unique_ptr(new SwCanvas); diff --git a/test/testStress.cpp b/test/testStress.cpp index 870742ed..f500078b 100644 --- a/test/testStress.cpp +++ b/test/testStress.cpp @@ -21,9 +21,17 @@ void tvgtest() Eina_Bool anim_cb(void *data) { + auto t = ecore_time_get(); + //Explicitly clear all retained paint nodes. - t1 = ecore_time_get(); - canvas->clear(); + if (canvas->clear() != tvg::Result::Success) + { + //Probably, you missed sync() call before. + return ECORE_CALLBACK_RENEW; + } + + t1 = t; + t2 = ecore_time_get(); for (int i = 0; i < COUNT; i++) { @@ -61,6 +69,11 @@ Eina_Bool anim_cb(void *data) canvas->push(move(shape)); } + t3 = ecore_time_get(); + + //Draw Next frames + canvas->draw(); + //Update Efl Canvas Eo* img = (Eo*) data; evas_object_image_pixels_dirty_set(img, EINA_TRUE); @@ -71,10 +84,6 @@ Eina_Bool anim_cb(void *data) void render_cb(void* data, Eo* obj) { - t3 = ecore_time_get(); - - //Draw Next frames - canvas->draw(); canvas->sync(); t4 = ecore_time_get(); From 28485d4b9c8eb0891b592f06c51abafc22e96ac0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 20:14:46 +0900 Subject: [PATCH 111/244] test: revise async(stress) test code. Change-Id: I2005f12cc9552b4a98101ba53f48b04c9a6c5732 --- .gitignore | 2 +- test/makefile | 2 +- test/{testStress.cpp => testAsync.cpp} | 37 ++++++++++---------------- 3 files changed, 16 insertions(+), 25 deletions(-) rename test/{testStress.cpp => testAsync.cpp} (70%) diff --git a/.gitignore b/.gitignore index c8da1b2f..f6c52c51 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ testRadialGradient testGradientTransform testSvg testGlShape -testStress +testAsync diff --git a/test/makefile b/test/makefile index 9f776483..870c3bbf 100644 --- a/test/makefile +++ b/test/makefile @@ -18,4 +18,4 @@ all: 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 testStress testStress.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testStress.cpp b/test/testAsync.cpp similarity index 70% rename from test/testStress.cpp rename to test/testAsync.cpp index f500078b..4d042dcf 100644 --- a/test/testStress.cpp +++ b/test/testAsync.cpp @@ -26,12 +26,11 @@ Eina_Bool anim_cb(void *data) //Explicitly clear all retained paint nodes. if (canvas->clear() != tvg::Result::Success) { - //Probably, you missed sync() call before. + //Logically wrong! Probably, you missed to call sync() before. return ECORE_CALLBACK_RENEW; } t1 = t; - t2 = ecore_time_get(); for (int i = 0; i < COUNT; i++) { @@ -44,34 +43,25 @@ Eina_Bool anim_cb(void *data) shape->appendRect(x, y, w, h, rand() % 400); - if (rand() % 2) { - //LinearGradient - auto fill = tvg::LinearGradient::gen(); - fill->linear(x, y, x + w, y + h); + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(x, y, x + w, y + h); - //Gradient Color Stops - tvg::Fill::ColorStop colorStops[3]; - colorStops[0] = {0, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; - colorStops[1] = {1, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; - colorStops[2] = {2, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + //Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[1] = {1, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[2] = {2, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + + fill->colorStops(colorStops, 3); + shape->fill(move(fill)); - fill->colorStops(colorStops, 3); - shape->fill(move(fill)); - } else { - shape->fill(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); - } -#if 0 - if (rand() % 2) { - shape->stroke(float(rand() % 10)); - shape->stroke(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); - } -#endif canvas->push(move(shape)); } t3 = ecore_time_get(); - //Draw Next frames + //Drawing task can be performed asynchronously. canvas->draw(); //Update Efl Canvas @@ -84,6 +74,7 @@ Eina_Bool anim_cb(void *data) void render_cb(void* data, Eo* obj) { + //Make it guarantee finishing drawing task. canvas->sync(); t4 = ecore_time_get(); From ad5f147c747a2e737d7502b89d484dd87c4c1a40 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 21:00:43 +0900 Subject: [PATCH 112/244] 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 2458cdb6..ac5464e0 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 9a79c6ed..29ecf27b 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) { From 56e866dd36a7ac374966bb34e5854f598d741746 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Jun 2020 13:52:50 +0900 Subject: [PATCH 113/244] 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 72cf83d4..31d0cbd9 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 4046844c..c598ee5d 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 a9e797fd..54c7e113 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 6693650e..b1cf7acd 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 00000000..53235fe3 --- /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 631bc2ae..00000000 --- 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 4b9154bc..fee1aa8d 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 8954536e..4ba6e9be 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 302f4e91..79f7c187 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 b5000bc5..493497b2 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 870c3bbf..33eb7d98 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 4d042dcf..7172dd90 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 ebb3e67f..82aa32df 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 a71374a4..d7cb8fa2 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 d8ca9794..6230dc0e 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 cc0c8bbe..c57d4d4b 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 eb3a9dc6..4dbc26b7 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 8ad43ae0..c488091c 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 cf33a1ef..d20cce98 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 428acc51..1b5137bb 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 8016a451..ed0d31d5 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 9fff6f05..02101ed4 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 efb784fd..a5bdc9e2 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 4ba5941d..fc3395e3 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 e10be472..841c6e1d 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 db6fd53d..c5672c75 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 1e411fe2..07879c12 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 4cc1f7fe..a79c770c 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 68bffa2c..bc50dca5 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 3b6cc9df..559479dd 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 cad2f1b7..b7671b81 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 52227439..dd3423ac 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 7111b21b..3a39913f 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 From 4d6dee91e4c2347b4f9e97df29e3585a2a5634b3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 14:59:01 +0900 Subject: [PATCH 114/244] 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 | 120 +++++++++++++++++++++++++++++++++++-------- 4 files changed, 99 insertions(+), 130 deletions(-) delete mode 100644 test/testGlShape.cpp diff --git a/.gitignore b/.gitignore index f6c52c51..9a645208 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,4 @@ testLinearGradient testRadialGradient testGradientTransform testSvg -testGlShape testAsync diff --git a/test/makefile b/test/makefile index 33eb7d98..6455a0a2 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 c488091c..00000000 --- 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 a79c770c..e32142fb 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; + } + + elm_init(argc, argv); //Show the result using EFL... - elm_init(argc, argv); + 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); + Eo* viewer; - elm_win_resize_object_add(win, img); + 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); From 3a8d6821baf6889eccd834d6613d9bf434b36e09 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 24 Jun 2020 09:55:25 +0900 Subject: [PATCH 115/244] 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 1bd40c10..88fd37a6 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 00000000..40814535 --- /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 00000000..4e3b3a73 --- /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 2b4d8b16..13441f38 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 00000000..a909e547 --- /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 From ac3c46cf363a6a4e45494baea30e686b6a034ccb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 16:16:01 +0900 Subject: [PATCH 116/244] updated AUTHORS Change-Id: Ife45b8ec1ad39822491e57b6031927a42f6a113b --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index bcfd4d6c..3e778fef 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Hermet Park Prudhvi Raj Vasireddi +Junsu Choi From e9d6bd7833232e754d751cb7fcaf5407eb5a1295 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 24 Jun 2020 19:35:40 +0900 Subject: [PATCH 117/244] 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 88fd37a6..21967afe 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 4db82008..4dd5fd41 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 13441f38..eba74c39 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 00000000..601ed0c1 --- /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 00000000..20a41a74 --- /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_ From 3fe2eedd897faed9e7ce259e44418c2e404a8225 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 26 Jun 2020 18:51:36 +0900 Subject: [PATCH 118/244] 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 21967afe..de7adf76 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 00000000..70058e00 --- /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 00000000..47a35d87 --- /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 601ed0c1..b3fe81d9 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 20a41a74..1bd779b1 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 { From 0a562a4ae26e5f6c3d6dffc4d45982b7dc1e625b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 16:26:02 +0900 Subject: [PATCH 119/244] 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 e32142fb..cd1bab12 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... From be6615d93e0488f239edf62b61dd6ed33a9a36c5 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Jun 2020 16:35:21 +0900 Subject: [PATCH 120/244] 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 70058e00..c3d3cac3 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': From 9ba6bd654e310f5c3896a8043df1fcb3fbb753f9 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Jun 2020 19:24:54 +0900 Subject: [PATCH 121/244] 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 4dd5fd41..99bb689e 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) }; From 654299d0ab6b3eeb0a5c21aafba036b93f1e995e Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Jun 2020 19:30:29 +0900 Subject: [PATCH 122/244] 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 | 59 +++++++++++++++++++++++++++++-------------- 6 files changed, 122 insertions(+), 19 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 00000000..fe62615d --- /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 00000000..e5d210f2 --- /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 00000000..d4b2740c --- /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 00000000..bce75d84 --- /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 00000000..a0b3677a --- /dev/null +++ b/test/svgs/shape.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/test/testSvg.cpp b/test/testSvg.cpp index b7671b81..1ae4fe0b 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -8,36 +8,54 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -void tvgtest() +unique_ptr canvas = nullptr; +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) { - //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 SVG scene, request the original size, 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); } From 918b6c69d837bb6c181aa62d4e325bfe32454837 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 17:35:04 +0900 Subject: [PATCH 123/244] 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 | 134 ++++++++++++++++++++--------- test/testBoundary.cpp | 133 ++++++++++++++++++++--------- test/testCommon.h | 70 +++++++++++++++ test/testComposition.cpp | 35 -------- test/testCustomTransform.cpp | 149 +++++++++++++++++++++++--------- test/testDirectUpdate.cpp | 150 ++++++++++++++++++++++---------- test/testGradient.cpp | 52 ------------ test/testGradientTransform.cpp | 149 +++++++++++++++++++++++--------- test/testLinearGradient.cpp | 134 ++++++++++++++++++++--------- test/testMultiShapes.cpp | 134 ++++++++++++++++++++--------- test/testPath.cpp | 133 ++++++++++++++++++++--------- test/testPathCopy.cpp | 133 ++++++++++++++++++++--------- test/testRadialGradient.cpp | 134 ++++++++++++++++++++--------- test/testScene.cpp | 132 ++++++++++++++++++++-------- test/testSceneTransform.cpp | 149 +++++++++++++++++++++++--------- test/testShape.cpp | 121 ++++++++++---------------- test/testStroke.cpp | 136 ++++++++++++++++++++--------- test/testStrokeLine.cpp | 135 ++++++++++++++++++++--------- test/testSvg.cpp | 151 +++++++++++++++++++++++---------- test/testTransform.cpp | 149 +++++++++++++++++++++++--------- test/testUpdate.cpp | 149 +++++++++++++++++++++++--------- 22 files changed, 1921 insertions(+), 883 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 7172dd90..a8ac2b01 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) { - elm_exit(); + static constexpr auto BPP = 4; + + //Create a Canvas + glCanvas = tvg::GlCanvas::gen(); + glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); } +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->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) { + 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_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_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - 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 82aa32df..7794689a 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); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 d7cb8fa2..e74ac5e8 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(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void win_del(void *data, Evas_Object *o, void *ev) +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 00000000..c47723a5 --- /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 6230dc0e..00000000 --- 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 c57d4d4b..1109a21b 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); +} - //Draw Next frames - canvas->draw(); - canvas->sync(); + +/************************************************************************/ +/* 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 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 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(); +} + +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + 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); - - 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); + + 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_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 4dbc26b7..93b2dfb3 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); +} - //Draw Next frames - canvas->draw(); - canvas->sync(); + +/************************************************************************/ +/* 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 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 -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(); +} + +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + 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); - - 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); + + 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_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 d20cce98..00000000 --- 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 1b5137bb..b77062bf 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); +} - //Draw Next frames - canvas->draw(); - canvas->sync(); + +/************************************************************************/ +/* 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 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 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(); +} + +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + 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); - - 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); + + 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_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 ed0d31d5..36251f56 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); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 02101ed4..195547de 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); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 a5bdc9e2..49bd738b 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(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void win_del(void *data, Evas_Object *o, void *ev) +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 fc3395e3..b619f78d 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(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void win_del(void *data, Evas_Object *o, void *ev) +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 841c6e1d..f12777c0 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); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 c5672c75..e16772ad 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); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 07879c12..7bd8b417 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); +} - //Draw Next frames - canvas->draw(); - canvas->sync(); + +/************************************************************************/ +/* 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 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 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(); +} + +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + 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); - - 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); + + 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_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 cd1bab12..9aa284da 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -1,13 +1,10 @@ -#include -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -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(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvgDrawCmds(swCanvas.get()); } +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 */ -/************************************************************************/ -void win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} +/************************************************************************/ +/* Main Code */ +/************************************************************************/ 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; } - if (swEngine) cout << "engine: software" << endl; - else cout << "engine: opengl" << endl; + //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); - //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 bc50dca5..493bbde5 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(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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 559479dd..d57bf1f7 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); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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(); +} + + +/************************************************************************/ +/* 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; + + 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); - //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_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/testSvg.cpp b/test/testSvg.cpp index 1ae4fe0b..938d37a5 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 + + canvas->push(move(shape1)); + + eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, canvas); } -void win_del(void* data, Evas_Object* o, void* ev) +/************************************************************************/ +/* 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); - //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)); + /* 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()); +} - eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, NULL); +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(); + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + +int main(int argc, char **argv) +{ + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } + + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //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_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 dd3423ac..c017f243 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); +} - //Draw Next frames - canvas->draw(); - canvas->sync(); + +/************************************************************************/ +/* 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 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 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(); +} + +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + 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); - - 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); + + 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_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 3a39913f..d28207af 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)); +} - //Draw Next frames - canvas->draw(); - canvas->sync(); + +/************************************************************************/ +/* 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 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 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(); +} + +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + 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); - - 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); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); + + 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_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 From 8bb8710815d37302b3821514d5d03efb021e718e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 10:24:56 +0900 Subject: [PATCH 124/244] 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 938d37a5..4da0349c 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++; From 4bc0b584f3a50540042ddaec39f930e3e52575db Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 12:38:01 +0900 Subject: [PATCH 125/244] 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 ac5464e0..4f09c60a 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; } From 61cb144122f381c2bb32e44ff6a41f162ad96ea4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 13:08:09 +0900 Subject: [PATCH 126/244] 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 a8ac2b01..666e7bbb 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 7794689a..733e60bb 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 e74ac5e8..fcfcd683 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 1109a21b..d87b4815 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 93b2dfb3..529e067d 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 b77062bf..3edb5d8a 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 36251f56..63e690a4 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 195547de..73992b66 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 49bd738b..3fbb8346 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 b619f78d..3407f927 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 f12777c0..ffec5faf 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 e16772ad..5a6b25fc 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 7bd8b417..8c0898f6 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 9aa284da..406b369c 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 493bbde5..c7f95dfc 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 d57bf1f7..31e670eb 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 4da0349c..13f3e4ce 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 c017f243..7376f97b 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 d28207af..e1b02128 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) From f377f339935f60eb276a0eee7648863746413a59 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 16:57:31 +0900 Subject: [PATCH 127/244] 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 4f09c60a..f6fc88b6 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 29ecf27b..a4c811af 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 d87b4815..27e3c6e1 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 +} From 5faa94340f9abe6cefe2d52d41742ce2fc7b79ea Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 1 Jul 2020 12:53:01 +0900 Subject: [PATCH 128/244] sw_engine: fix a regression bug. Shape must have closed path for filling color. if closed is skipped, it would take it's a line. Change-Id: Ie1dcde9edbfc6501a34d6cb9ce54184ade6864db --- src/lib/sw_engine/tvgSwShape.cpp | 5 +++++ test/testPath.cpp | 3 ++- test/testSceneTransform.cpp | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index a4c811af..4c99fb14 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -528,11 +528,14 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata) _growOutlinePoint(*outline, outlinePtsCnt); _growOutlineContour(*outline, outlineCntrsCnt); + auto closed = false; + //Generate Outlines while (cmdCnt-- > 0) { switch(*cmds) { case PathCommand::Close: { _outlineClose(*outline); + closed = true; break; } case PathCommand::MoveTo: { @@ -556,6 +559,8 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata) _outlineEnd(*outline); + if (closed) outline->opened = false; + //FIXME: //outline->flags = SwOutline::FillRule::Winding; diff --git a/test/testPath.cpp b/test/testPath.cpp index 3fbb8346..8c798481 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -39,6 +39,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape2->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); 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->close(); shape2->fill(255, 0, 0, 255); if (canvas->push(move(shape2)) != tvg::Result::Success) return; @@ -147,4 +148,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 8c0898f6..fc088a5c 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -75,6 +75,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape5->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); + shape5->close(); shape5->fill(127, 0, 0, 127); scene2->push(move(shape5)); @@ -228,4 +229,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} From 8c815e95c8b4a08d55ad30df8e4b110715e693d7 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 1 Jul 2020 13:44:12 +0900 Subject: [PATCH 129/244] SvgLoader: Don't use custom transform Change-Id: Ia7cd0992bbb8d5ee117806ee62b35604ffd91e16 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index b3fe81d9..b79a3ebb 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -21,12 +21,37 @@ #include "tvgSvgSceneBuilder.h" +static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, float* z) +{ + float rz, si, cs, zcs, zsi; + + *tx = m->e13; + *ty = m->e23; + + cs = m->e11; + si = m->e12; + rz = atan2(si, cs); + *z = rz * (180.0 / M_PI); + zcs = cosf(rz); + zsi = sinf(rz); + m->e11 = m->e11 * zcs + m->e12 * zsi; + m->e22 = m->e21 * (-1 * zsi) + m->e22 * zcs; + *s = m->e11 > m->e22 ? m->e11 : m->e22; +} + + unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) { SvgStyleProperty* style = node->style; //Apply the transformation - if (node->transform) vg->transform(*node->transform); + if (node->transform) { + float tx = 0, ty = 0, s = 0, z = 0; + _getTransformationData(node->transform, &tx, &ty, &s, &z); + vg->scale(s); + vg->rotate(z); + vg->translate(tx, ty); + } if (node->type == SvgNodeType::Doc) return vg; @@ -151,8 +176,13 @@ 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); - + if (node->transform) { + float tx = 0, ty = 0, s = 0, z = 0; + _getTransformationData(node->transform, &tx, &ty, &s, &z); + scene->scale(s); + scene->rotate(z); + scene->translate(tx, ty); + } 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)); From 0d5adb2f033588bfe11a9b75aba2ad509bccbdfa Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 1 Jul 2020 14:25:53 +0900 Subject: [PATCH 130/244] test: enable gl window only on gl backend. Change-Id: Iafd790b7fc1df8a58bdce2f18c39029cc0d74945 --- test/testAsync.cpp | 2 -- test/testBlending.cpp | 2 -- test/testBoundary.cpp | 2 -- test/testCommon.h | 2 ++ test/testCustomTransform.cpp | 2 -- test/testDirectUpdate.cpp | 2 -- test/testGradientTransform.cpp | 2 -- test/testLinearGradient.cpp | 2 -- test/testMultiShapes.cpp | 2 -- test/testPath.cpp | 2 -- test/testPathCopy.cpp | 2 -- test/testRadialGradient.cpp | 2 -- test/testScene.cpp | 2 -- test/testSceneTransform.cpp | 2 -- test/testShape.cpp | 2 -- test/testStroke.cpp | 2 -- test/testStrokeLine.cpp | 2 -- test/testSvg.cpp | 2 -- test/testTransform.cpp | 2 -- test/testUpdate.cpp | 2 -- 20 files changed, 2 insertions(+), 38 deletions(-) diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 666e7bbb..9ae7113e 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -160,8 +160,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { auto view = createSwView(); evas_object_image_pixels_get_callback_set(view, drawSwView, nullptr); diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 733e60bb..14bc9acf 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -140,8 +140,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index fcfcd683..ca598e45 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -129,8 +129,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testCommon.h b/test/testCommon.h index c47723a5..f1769566 100644 --- a/test/testCommon.h +++ b/test/testCommon.h @@ -50,6 +50,8 @@ void drawGLview(Evas_Object *obj); static Eo* createGlView() { + 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); diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 27e3c6e1..08075d25 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -183,8 +183,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - Elm_Transit *transit = elm_transit_add(); if (tvgEngine == tvg::CanvasEngine::Sw) { diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 529e067d..24fae64b 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -146,8 +146,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - Elm_Transit *transit = elm_transit_add(); if (tvgEngine == tvg::CanvasEngine::Sw) { diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 3edb5d8a..ddc9c880 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -211,8 +211,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - Elm_Transit *transit = elm_transit_add(); if (tvgEngine == tvg::CanvasEngine::Sw) { diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 63e690a4..d6f04e47 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -158,8 +158,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 73992b66..b5c6d42c 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -118,8 +118,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testPath.cpp b/test/testPath.cpp index 8c798481..d74b89d8 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -135,8 +135,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 3407f927..ebf900c3 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -172,8 +172,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index ffec5faf..de93d469 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -158,8 +158,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testScene.cpp b/test/testScene.cpp index 5a6b25fc..ec1ed4a8 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -165,8 +165,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index fc088a5c..c1b16629 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -207,8 +207,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - Elm_Transit *transit = elm_transit_add(); if (tvgEngine == tvg::CanvasEngine::Sw) { diff --git a/test/testShape.cpp b/test/testShape.cpp index 406b369c..5bf9e650 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -108,8 +108,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testStroke.cpp b/test/testStroke.cpp index c7f95dfc..b9cfb4cf 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -155,8 +155,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 31e670eb..1856453a 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -192,8 +192,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 13f3e4ce..e0232748 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -132,8 +132,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - if (tvgEngine == tvg::CanvasEngine::Sw) { createSwView(); } else { diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 7376f97b..35b237c9 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -174,8 +174,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - Elm_Transit *transit = elm_transit_add(); if (tvgEngine == tvg::CanvasEngine::Sw) { diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index e1b02128..051a5810 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -135,8 +135,6 @@ int main(int argc, char **argv) elm_init(argc, argv); - elm_config_accel_preference_set("gl"); - Elm_Transit *transit = elm_transit_add(); if (tvgEngine == tvg::CanvasEngine::Sw) { From 322174d778d695be5153db574c6cb20fe251188b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 1 Jul 2020 11:33:50 +0900 Subject: [PATCH 131/244] sw_engine: optimize othogonal rectangle drawing. if the rectangle is not transformed, we don't need to use rle method. we can directly raster pixels onto the bounding box. Change-Id: I4e8b57149c0bcd78124d09388bf5115093a43bee --- src/lib/sw_engine/tvgSwCommon.h | 2 + src/lib/sw_engine/tvgSwRaster.cpp | 147 +++++++++++++++++++++++++++--- src/lib/sw_engine/tvgSwShape.cpp | 28 +++++- test/testAsync.cpp | 2 +- 4 files changed, 162 insertions(+), 17 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 72fa7006..88686b5b 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -198,6 +198,8 @@ struct SwShape SwRleData* rle; SwRleData* strokeRle; SwBBox bbox; + + bool rect; //Fast Track: Othogonal rectangle? }; diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 05429f3c..5a14822b 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,17 +24,58 @@ /* Internal Class Implementation */ /************************************************************************/ +static SwBBox _clipRegion(Surface& surface, SwBBox& in) +{ + auto bbox = in; + + if (bbox.min.x < 0) bbox.min.x = 0; + if (bbox.min.y < 0) bbox.min.y = 0; + if (bbox.max.x > surface.w) bbox.max.x = surface.w; + if (bbox.max.y > surface.h) bbox.max.y = surface.h; + + return bbox; +} + +static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint32_t color) +{ + auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + auto ialpha = 255 - COLOR_ALPHA(color); + + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface.stride]; + for (uint32_t x = 0; x < w; ++x) { + dst[x] = color + COLOR_ALPHA_BLEND(dst[x], ialpha); + } + } + return true; +} + + +static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t color) +{ + auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface.stride]; + COLOR_SET(dst, color, w); + } + return true; +} + static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color) { if (!rle) return false; auto span = rle->spans; - auto stride = surface.stride; uint32_t src; for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * stride + span->x]; + auto dst = &surface.buffer[span->y * surface.stride + span->x]; if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage); else src = color; auto ialpha = 255 - COLOR_ALPHA(src); @@ -52,10 +93,9 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) if (!rle) return false; auto span = rle->spans; - auto stride = surface.stride; for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * stride + span->x]; + auto dst = &surface.buffer[span->y * surface.stride + span->x]; if (span->coverage == 255) { COLOR_SET(dst, color, span->len); } else { @@ -71,6 +111,70 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) } +static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, const SwFill* fill) +{ + if (!fill) return false; + + auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + //Translucent Gradient + if (fill->translucent) { + + auto tmpBuf = static_cast(alloca(surface.w * sizeof(uint32_t))); + if (!tmpBuf) return false; + + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface.stride]; + fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w); + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); + } + } + //Opaque Gradient + } else { + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface.stride]; + fillFetchLinear(fill, dst, region.min.y + y, region.min.x, w); + } + } + return true; +} + + +static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, const SwFill* fill) +{ + if (!fill) return false; + + auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + //Translucent Gradient + if (fill->translucent) { + + auto tmpBuf = static_cast(alloca(surface.w * sizeof(uint32_t))); + if (!tmpBuf) return false; + + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface.stride]; + fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); + } + } + //Opaque Gradient + } else { + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface.stride]; + fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w); + } + } + return true; +} + + static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) { if (!rle || !fill) return false; @@ -79,12 +183,11 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF if (!buf) return false; auto span = rle->spans; - auto stride = surface.stride; //Translucent Gradient if (fill->translucent) { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * stride + span->x]; + auto dst = &surface.buffer[span->y * surface.stride + span->x]; fillFetchLinear(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { @@ -101,7 +204,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF //Opaque Gradient } else { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * stride + span->x]; + auto dst = &surface.buffer[span->y * surface.stride + span->x]; if (span->coverage == 255) { fillFetchLinear(fill, dst, span->y, span->x, span->len); } else { @@ -126,12 +229,11 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF if (!buf) return false; auto span = rle->spans; - auto stride = surface.stride; //Translucent Gradient if (fill->translucent) { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * stride + span->x]; + auto dst = &surface.buffer[span->y * surface.stride + span->x]; fillFetchRadial(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { @@ -148,7 +250,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF //Opaque Gradient } else { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * stride + span->x]; + auto dst = &surface.buffer[span->y * surface.stride + span->x]; if (span->coverage == 255) { fillFetchRadial(fill, dst, span->y, span->x, span->len); } else { @@ -171,15 +273,31 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id) { - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill); - return _rasterRadialGradientRle(surface, shape.rle, shape.fill); + //Fast Track + if (shape.rect) { + auto region = _clipRegion(surface, shape.bbox); + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, region, shape.fill); + return _rasterRadialGradientRect(surface, region, shape.fill); + } else { + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill); + return _rasterRadialGradientRle(surface, shape.rle, shape.fill); + } + return false; } bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); + //Fast Track + if (shape.rect) { + auto region = _clipRegion(surface, shape.bbox); + if (a == 255) return _rasterSolidRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); + } else{ + if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); + } + return false; } @@ -204,5 +322,4 @@ bool rasterClear(Surface& surface) return true; } - #endif /* _TVG_SW_RASTER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4c99fb14..1c0a09ef 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -241,7 +241,7 @@ static void _transformOutline(SwOutline* outline, const Matrix* transform) auto dy = static_cast(outline->pts[i].y >> 6); auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; - auto pt = Point{tx, ty}; + auto pt = Point{round(tx), round(ty)}; outline->pts[i] = TO_SWPOINT(&pt); } } @@ -437,6 +437,28 @@ SwOutline* _genDashOutline(const Shape* sdata) } +bool _fastTrack(const SwOutline* outline) +{ + //Fast Track: Othogonal rectangle? + if (outline->ptsCnt != 5) return false; + + auto pt1 = outline->pts + 0; + auto pt2 = outline->pts + 1; + auto pt3 = outline->pts + 2; + auto pt4 = outline->pts + 3; + + auto min1 = pt1->y < pt3->y ? pt1 : pt3; + auto min2 = pt2->y < pt4->y ? pt2 : pt4; + if (min1->y != min2->y) return false; + + SwCoord len1 = pow(pt1->x - pt3->x, 2) + pow(pt1->y - pt3->y, 2); + SwCoord len2 = pow(pt2->x - pt4->x, 2) + pow(pt2->y - pt4->y, 2); + if (len1 == len2) return true; + + return false; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -451,6 +473,9 @@ bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const M if (!_checkValid(shape.outline, shape.bbox, clip)) goto end; + //Case: Fast Track Rectangle Drawing + if ((shape.rect = _fastTrack(shape.outline))) return true; + //Case: Stroke Line if (shape.outline->opened) return true; @@ -474,6 +499,7 @@ void shapeReset(SwShape& shape) shapeDelOutline(shape); rleFree(shape.rle); shape.rle = nullptr; + shape.rect = false; _initBBox(shape.bbox); } diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 9ae7113e..ca1d473d 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -29,7 +29,7 @@ bool tvgUpdateCmds(tvg::Canvas* canvas) 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); + shape->appendRect(x, y, w, h, 0); //LinearGradient auto fill = tvg::LinearGradient::gen(); From add79b07cd3de40bf5a92d571224ec2ac534e30a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 1 Jul 2020 16:49:03 +0900 Subject: [PATCH 132/244] sw_engine: Draw shapes even though there is no explict closed command. This behavior is not confiremd but it's beneficial for svg spec. Change-Id: Ia711c057811ae51e472b4e164b36f3dd6af9893f --- src/lib/sw_engine/tvgSwCommon.h | 3 ++- src/lib/sw_engine/tvgSwRenderer.cpp | 8 ++++++-- src/lib/sw_engine/tvgSwShape.cpp | 24 +++++++++++++++--------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 88686b5b..5db4cd77 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -264,7 +264,8 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); bool shapeGenOutline(SwShape& shape, const Shape* sdata); -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); +bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip); void shapeDelOutline(SwShape& shape); void shapeResetStroke(SwShape& shape, const Shape* sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index f6fc88b6..b9ce7c0a 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -187,8 +187,12 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* shapeReset(task->shape); uint8_t alpha = 0; task->sdata->fill(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0 || task->sdata->fill() || strokeAlpha > 0) { - if (!shapeGenRle(task->shape, task->sdata, task->clip, task->transform)) return; + bool renderShape = (alpha > 0 || task->sdata->fill()); + if (renderShape || strokeAlpha > 0) { + if (!shapePrepare(task->shape, task->sdata, task->clip, task->transform)) return; + if (renderShape) { + if (!shapeGenRle(task->shape, task->sdata, task->clip)) return; + } } } //Fill diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 1c0a09ef..dbdfb6a4 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -463,25 +463,31 @@ bool _fastTrack(const SwOutline* outline) /* External Class Implementation */ /************************************************************************/ -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) +bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) { if (!shapeGenOutline(shape, sdata)) return false; _transformOutline(shape.outline, transform); - if (!_updateBBox(shape.outline, shape.bbox)) goto end; + if (!_updateBBox(shape.outline, shape.bbox)) return false; - if (!_checkValid(shape.outline, shape.bbox, clip)) goto end; + if (!_checkValid(shape.outline, shape.bbox, clip)) return false; - //Case: Fast Track Rectangle Drawing - if ((shape.rect = _fastTrack(shape.outline))) return true; + return true; +} + +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip) +{ + //FIXME: Should we draw it? //Case: Stroke Line - if (shape.outline->opened) return true; + //if (shape.outline->opened) return true; + + //Case A: Fast Track Rectangle Drawing + if ((shape.rect = _fastTrack(shape.outline))) return true; + //Case B: Normale Shape RLE Drawing + if ((shape.rle = rleRender(shape.outline, shape.bbox, clip))) return true; - shape.rle = rleRender(shape.outline, shape.bbox, clip); -end: - if (shape.rle) return true; return false; } From 2929fa5c57c17549da1b65e86140806b12823fc3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 3 Jul 2020 18:17:43 +0900 Subject: [PATCH 133/244] sw_engine: optimize rle rendering. we don't need to apply anti-aliasing if stroke is there. here turns off anti-alias if stroke width is more than 2. magic number 2 is experimentally confirmed. Change-Id: I09031dc2a0a84f31c5904651ed1e62004645ba9a --- src/lib/sw_engine/tvgSwCommon.h | 4 ++-- src/lib/sw_engine/tvgSwRenderer.cpp | 10 ++++++---- src/lib/sw_engine/tvgSwRle.cpp | 17 +++++++---------- src/lib/sw_engine/tvgSwShape.cpp | 6 +++--- test/testShape.cpp | 2 +- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 5db4cd77..8d903423 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -265,7 +265,7 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); bool shapeGenOutline(SwShape& shape, const Shape* sdata); bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip); +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias); void shapeDelOutline(SwShape& shape); void shapeResetStroke(SwShape& shape, const Shape* sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip); @@ -286,7 +286,7 @@ void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); -SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); +SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias); void rleFree(SwRleData* rle); bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index b9ce7c0a..adc3e9f5 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -109,7 +109,7 @@ void SwRenderer::doRender() if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); } task->sdata->strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); + if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); renderTasks.pop(); } } @@ -178,7 +178,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* //Valid Stroking? uint8_t strokeAlpha = 0; - if (task->sdata->strokeWidth() > FLT_EPSILON) { + auto strokeWidth = task->sdata->strokeWidth(); + if (strokeWidth > FLT_EPSILON) { task->sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); } @@ -188,10 +189,11 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* uint8_t alpha = 0; task->sdata->fill(nullptr, nullptr, nullptr, &alpha); bool renderShape = (alpha > 0 || task->sdata->fill()); - if (renderShape || strokeAlpha > 0) { + if (renderShape || strokeAlpha) { if (!shapePrepare(task->shape, task->sdata, task->clip, task->transform)) return; if (renderShape) { - if (!shapeGenRle(task->shape, task->sdata, task->clip)) return; + auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true; + if (!shapeGenRle(task->shape, task->sdata, task->clip, antiAlias)) return; } } } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5bb3a319..6ee6f7c2 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -87,6 +87,7 @@ struct RleWorker SwSize clip; bool invalid; + bool antiAlias; }; @@ -196,6 +197,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor } if (coverage > 0) { + if (!rw.antiAlias) coverage = 255; auto count = rw.spansCnt; auto span = rw.spans + count - 1; assert(span); @@ -261,22 +263,16 @@ static void _sweep(RleWorker& rw) while (cell) { - if (cell->x > x && cover != 0) - _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); - + if (cell->x > x && cover != 0) _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); cover += cell->cover; auto area = cover * (ONE_PIXEL * 2) - cell->area; - - //OPTIMIZE ME: This occurs 1 length span data. - if (area != 0 && cell->x >= 0) - _horizLine(rw, cell->x, y, area, 1); + if (area != 0 && cell->x >= 0) _horizLine(rw, cell->x, y, area, 1); x = cell->x + 1; cell = cell->next; } - if (cover != 0) - _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); + if (cover != 0) _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); } if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt); @@ -648,7 +644,7 @@ static bool _genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) +SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias) { //Please adjust when you out of cell memory (default: 16384L) constexpr auto RENDER_POOL_SIZE = 163840L * 2; @@ -681,6 +677,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; rw.clip = clip; + rw.antiAlias = antiAlias; rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); assert(rw.rle); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index dbdfb6a4..a2ca5c61 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -477,7 +477,7 @@ bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const } -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip) +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias) { //FIXME: Should we draw it? //Case: Stroke Line @@ -486,7 +486,7 @@ bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip) //Case A: Fast Track Rectangle Drawing if ((shape.rect = _fastTrack(shape.outline))) return true; //Case B: Normale Shape RLE Drawing - if ((shape.rle = rleRender(shape.outline, shape.bbox, clip))) return true; + if ((shape.rle = rleRender(shape.outline, shape.bbox, clip, antiAlias))) return true; return false; } @@ -667,7 +667,7 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) if (!_checkValid(strokeOutline, bbox, clip)) return false; - shape.strokeRle = rleRender(strokeOutline, bbox, clip); + shape.strokeRle = rleRender(strokeOutline, bbox, clip, true); _delOutline(strokeOutline); diff --git a/test/testShape.cpp b/test/testShape.cpp index 5bf9e650..617d024f 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -119,4 +119,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} From cfa17c6df602c04a88e9cc489a508207f963a309 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 6 Jul 2020 19:26:50 +0900 Subject: [PATCH 134/244] svg_engine: fix infinit loop dead in stroke rendering. here logic was wrongly introducedd, we fix the condition check properly. Change-Id: I97f18f68290c61096f4e7fe54bd6f6fde51e175b --- src/lib/sw_engine/tvgSwMath.cpp | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 1 - src/lib/sw_engine/tvgSwStroke.cpp | 10 ++++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 53cc8ce1..540ddcfb 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -237,7 +237,7 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& auto theta2 = abs(mathDiff(angleMid, angleOut)); if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return true; - else return false; + return false; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index a2ca5c61..66655b03 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -648,7 +648,6 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) if (sdata->strokeDash(nullptr) > 0) { shapeOutline = _genDashOutline(sdata); if (!shapeOutline) return false; - //Normal Style stroke } else { if (!shape.outline) { diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 6ccfb7dc..d45ddd8e 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -442,7 +442,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //initialize with current direction angleIn = angleOut = angleMid = stroke.angleIn; - if (arc < limit && mathSmallCubic(arc, angleIn, angleMid, angleOut)) { + if (arc < limit && !mathSmallCubic(arc, angleIn, angleMid, angleOut)) { if (stroke.firstPt) stroke.angleIn = angleIn; mathSplitCubic(arc); arc += 3; @@ -458,7 +458,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl stroke.angleOut = angleIn; _processCorner(stroke, 0); } - } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (SW_ANGLE_PI / 8)) { + } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (SW_ANGLE_PI / 8) / 4) { //if the deviation from one arc to the next is too great add a round corner stroke.center = arc[3]; stroke.angleOut = angleIn; @@ -534,9 +534,11 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl _borderLineTo(border, _end, false); _borderCubicTo(border, _ctrl2, _ctrl1, _start); - //and thenmove to the endpoint + //and then move to the endpoint _borderLineTo(border, _end, false); + ++side; + ++border; continue; } @@ -651,7 +653,7 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) { - /* We cannot process the first point because there is not enought + /* We cannot process the first point because there is not enough information regarding its corner/cap. Later, it will be processed in the _endSubPath() */ From 0d19700b4ea4a34cdcab1088cd1fbad0bbc3cfea Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 14:02:38 +0900 Subject: [PATCH 135/244] SvgLoader: Support ellipse draw Change-Id: I6420673d8341a59b91546224576d1c977c1a08d2 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index b79a3ebb..66b3593c 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -125,7 +125,7 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } case SvgNodeType::Ellipse: { - //TODO: Support ellipse + shape->appendCircle(node->node.ellipse.cx, node->node.ellipse.cy, node->node.ellipse.rx, node->node.ellipse.ry); break; } case SvgNodeType::Polygon: { From 02a0e985961b7472f32ab31e864bafbf6f387f18 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 17:01:56 +0900 Subject: [PATCH 136/244] SvgLoader: Support x,y rounded rect Change-Id: I45d8f7ff3604da0a80c09e2495ed8c0301310094 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 21 +++++++++++++++++-- test/svgs/rect.svg | 7 +++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/svgs/rect.svg diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 66b3593c..2451103e 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -150,11 +150,28 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } case SvgNodeType::Rect: { - if (node->node.rect.rx == node->node.rect.ry) { + if (node->node.rect.rx == node->node.rect.ry || (node->node.rect.rx == 0 || node->node.rect.ry == 0)) { 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 + float x = node->node.rect.x; + float y = node->node.rect.y; + float w = node->node.rect.w; + float h = node->node.rect.h; + float rx = node->node.rect.rx; + float ry = node->node.rect.ry; + float rhx = rx / 2; + float rhy = ry / 2; + shape->moveTo(x + rx, y); + shape->lineTo(x + w - rx, y); + shape->cubicTo(x + w - rx + rhx, y, x + w, y + ry - rhy, x + w, y + ry); + shape->lineTo(x + w, y + h - ry); + shape->cubicTo(x + w, y + h - ry + rhy, x + w - rx + rhx, y + h, x + w - rx, y + h); + shape->lineTo(x + rx, y + h); + shape->cubicTo(x + rx - rhx, y + h, x, y + h - ry + rhy, x, y + h - ry); + shape->lineTo(x, y + ry); + shape->cubicTo(x, y + ry - rhy, x + rx - rhx, y, x + rx, y); + shape->close(); } break; } diff --git a/test/svgs/rect.svg b/test/svgs/rect.svg new file mode 100644 index 00000000..2e829058 --- /dev/null +++ b/test/svgs/rect.svg @@ -0,0 +1,7 @@ + + + + + + + From ef4d7a39565926706f577ada8d8fbf5a50868d0b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 13:05:44 +0900 Subject: [PATCH 137/244] common shape: expand rectangle arguement to support both corner radius x, y this is useful for svg loader Change-Id: Ia11c2d1c6ea88f3fd65c7f75cef8b59bef426bcb --- inc/thorvg.h | 4 +- src/lib/tvgShape.cpp | 52 ++++++++++--------- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 24 +-------- test/testAsync.cpp | 2 +- test/testBlending.cpp | 4 +- test/testBoundary.cpp | 8 +-- test/testDirectUpdate.cpp | 6 +-- test/testGradientTransform.cpp | 10 ++-- test/testLinearGradient.cpp | 4 +- test/testMultiShapes.cpp | 4 +- test/testRadialGradient.cpp | 4 +- test/testScene.cpp | 4 +- test/testSceneTransform.cpp | 2 +- test/testShape.cpp | 10 ++-- test/testStroke.cpp | 8 +-- test/testSvg.cpp | 2 +- test/testTransform.cpp | 10 ++-- test/testUpdate.cpp | 6 +-- 18 files changed, 73 insertions(+), 91 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 54c7e113..bdca5a20 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -228,8 +228,8 @@ public: Result close() noexcept; //Shape - Result appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; - Result appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; + Result appendRect(float x, float y, float w, float h, float rx, float ry) noexcept; + Result appendCircle(float cx, float cy, float rx, float ry) noexcept; Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept; //Stroke diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index f7699b4b..36aefedd 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -154,20 +154,20 @@ Result Shape::close() noexcept } -Result Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept +Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept { auto impl = pImpl.get(); if (!impl || !impl->path) return Result::MemoryCorruption; - auto halfKappaW = radiusW * PATH_KAPPA; - auto halfKappaH = radiusH * PATH_KAPPA; + auto rxKappa = rx * PATH_KAPPA; + auto ryKappa = ry * PATH_KAPPA; impl->path->grow(6, 13); - impl->path->moveTo(cx, cy - radiusH); - impl->path->cubicTo(cx + halfKappaW, cy - radiusH, cx + radiusW, cy - halfKappaH, cx + radiusW, cy); - impl->path->cubicTo(cx + radiusW, cy + halfKappaH, cx + halfKappaW, cy + radiusH, cx, cy + radiusH); - impl->path->cubicTo(cx - halfKappaW, cy + radiusH, cx - radiusW, cy + halfKappaH, cx - radiusW, cy); - impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH); + impl->path->moveTo(cx, cy - ry); + impl->path->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); + impl->path->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); + impl->path->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); + impl->path->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); impl->path->close(); impl->flag |= RenderUpdateFlag::Path; @@ -176,17 +176,20 @@ Result Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noe } -Result Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept +Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) noexcept { auto impl = pImpl.get(); if (!impl || !impl->path) return Result::MemoryCorruption; + auto halfW = w * 0.5f; + auto halfH = h * 0.5f; + //clamping cornerRadius by minimum size - auto min = (w < h ? w : h) * 0.5f; - if (cornerRadius > min) cornerRadius = min; + if (rx > halfW) rx = halfW; + if (ry > halfH) ry = halfH; //rectangle - if (cornerRadius == 0) { + if (rx == 0 && ry == 0) { impl->path->grow(5, 4); impl->path->moveTo(x, y); impl->path->lineTo(x + w, y); @@ -194,20 +197,21 @@ Result Shape::appendRect(float x, float y, float w, float h, float cornerRadius) impl->path->lineTo(x, y + h); impl->path->close(); //circle - } else if (w == h && cornerRadius * 2 == w) { - return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius, cornerRadius); + } else if (fabsf(rx - halfW) < FLT_EPSILON && fabsf(ry - halfH) < FLT_EPSILON) { + return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry); } else { - auto halfKappa = cornerRadius * 0.5; + auto hrx = rx * 0.5f; + auto hry = ry * 0.5f; impl->path->grow(10, 17); - impl->path->moveTo(x + cornerRadius, y); - impl->path->lineTo(x + w - cornerRadius, y); - impl->path->cubicTo(x + w - cornerRadius + halfKappa, y, x + w, y + cornerRadius - halfKappa, x + w, y + cornerRadius); - impl->path->lineTo(x + w, y + h - cornerRadius); - impl->path->cubicTo(x + w, y + h - cornerRadius + halfKappa, x + w - cornerRadius + halfKappa, y + h, x + w - cornerRadius, y + h); - impl->path->lineTo(x + cornerRadius, y + h); - impl->path->cubicTo(x + cornerRadius - halfKappa, y + h, x, y + h - cornerRadius + halfKappa, x, y + h - cornerRadius); - impl->path->lineTo(x, y + cornerRadius); - impl->path->cubicTo(x, y + cornerRadius - halfKappa, x + cornerRadius - halfKappa, y, x + cornerRadius, y); + impl->path->moveTo(x + rx, y); + impl->path->lineTo(x + w - rx, y); + impl->path->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); + impl->path->lineTo(x + w, y + h - ry); + impl->path->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); + impl->path->lineTo(x + rx, y + h); + impl->path->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); + impl->path->lineTo(x, y + ry); + impl->path->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); impl->path->close(); } diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 2451103e..2be01222 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -150,29 +150,7 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } case SvgNodeType::Rect: { - if (node->node.rect.rx == node->node.rect.ry || (node->node.rect.rx == 0 || node->node.rect.ry == 0)) { - shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx); - } - else { - float x = node->node.rect.x; - float y = node->node.rect.y; - float w = node->node.rect.w; - float h = node->node.rect.h; - float rx = node->node.rect.rx; - float ry = node->node.rect.ry; - float rhx = rx / 2; - float rhy = ry / 2; - shape->moveTo(x + rx, y); - shape->lineTo(x + w - rx, y); - shape->cubicTo(x + w - rx + rhx, y, x + w, y + ry - rhy, x + w, y + ry); - shape->lineTo(x + w, y + h - ry); - shape->cubicTo(x + w, y + h - ry + rhy, x + w - rx + rhx, y + h, x + w - rx, y + h); - shape->lineTo(x + rx, y + h); - shape->cubicTo(x + rx - rhx, y + h, x, y + h - ry + rhy, x, y + h - ry); - shape->lineTo(x, y + ry); - shape->cubicTo(x, y + ry - rhy, x + rx - rhx, y, x + rx, y); - shape->close(); - } + shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx, node->node.rect.ry); break; } case SvgNodeType::Line: { diff --git a/test/testAsync.cpp b/test/testAsync.cpp index ca1d473d..bb890abf 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -29,7 +29,7 @@ bool tvgUpdateCmds(tvg::Canvas* canvas) float w = 1 + rand() % (int)(WIDTH * 1.3 / 2); float h = 1 + rand() % (int)(HEIGHT * 1.3 / 2); - shape->appendRect(x, y, w, h, 0); + shape->appendRect(x, y, w, h, 0, 0); //LinearGradient auto fill = tvg::LinearGradient::gen(); diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 14bc9acf..6f5f6e1b 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a if (canvas->push(move(shape1)) != tvg::Result::Success) return; @@ -151,4 +151,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index ca598e45..b23b82ec 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -10,19 +10,19 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Shape1 auto shape1 = tvg::Shape::gen(); - shape1->appendRect(-100, -100, 1000, 1000, 50); + shape1->appendRect(-100, -100, 1000, 1000, 50, 50); shape1->fill(255, 255, 255, 255); if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Shape2 auto shape2 = tvg::Shape::gen(); - shape2->appendRect(-100, -100, 250, 250, 50); + shape2->appendRect(-100, -100, 250, 250, 50, 50); shape2->fill(0, 0, 255, 255); if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Shape3 auto shape3 = tvg::Shape::gen(); - shape3->appendRect(500, 500, 550, 550, 0); + shape3->appendRect(500, 500, 550, 550, 0, 0); shape3->fill(0, 255, 255, 255); if (canvas->push(move(shape3)) != tvg::Result::Success) return; @@ -140,4 +140,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 24fae64b..437ad1f4 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -14,7 +14,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(-100, -100, 200, 200, 0); + shape->appendRect(-100, -100, 200, 200, 0, 0); //fill property will be retained shape->fill(127, 255, 255, 255); @@ -32,7 +32,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) //Reset Shape if (pShape->reset() == tvg::Result::Success) { - pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress), (100 * progress)); pShape->stroke(30 * progress); //Update shape for drawing (this may work asynchronously) @@ -166,4 +166,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index ddc9c880..fd5a563f 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -16,8 +16,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(-285, -300, 200, 200, 0); - shape->appendRect(-185, -200, 300, 300, 100); + shape->appendRect(-285, -300, 200, 200, 0, 0); + shape->appendRect(-185, -200, 300, 300, 100, 100); shape->appendCircle(115, 100, 100, 100); shape->appendCircle(115, 200, 170, 100); @@ -39,7 +39,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape2 auto shape2 = tvg::Shape::gen(); pShape2 = shape2.get(); - shape2->appendRect(-50, -50, 100, 100, 0); + shape2->appendRect(-50, -50, 100, 100, 0, 0); shape2->translate(400, 400); //LinearGradient @@ -61,7 +61,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) /* Look, how shape3's origin is different with shape2 The center of the shape is the anchor point for transformation. */ - shape3->appendRect(100, 100, 150, 100, 20); + shape3->appendRect(100, 100, 150, 100, 20, 20); //RadialGradient auto fill3 = tvg::RadialGradient::gen(); @@ -231,4 +231,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index d6f04e47..45f38d75 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 0, 0); //x, y, w, h, rx, ry //LinearGradient auto fill = tvg::LinearGradient::gen(); @@ -169,4 +169,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index b5c6d42c..ec46f2f9 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a if (canvas->push(move(shape1)) != tvg::Result::Success) return; @@ -129,4 +129,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index de93d469..71cfaaef 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 0, 0); //x, y, w, h, rx, ry //RadialGradient auto fill = tvg::RadialGradient::gen(); @@ -169,4 +169,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testScene.cpp b/test/testScene.cpp index ec1ed4a8..bee2b54f 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -12,7 +12,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a scene->push(move(shape1)); @@ -176,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/testSceneTransform.cpp b/test/testSceneTransform.cpp index c1b16629..d5d538d5 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -15,7 +15,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle (Scene1) auto shape1 = tvg::Shape::gen(); - shape1->appendRect(-235, -250, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(-235, -250, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a shape1->stroke(5); //width shape1->stroke(255, 255, 255, 255); //r, g, b, a diff --git a/test/testShape.cpp b/test/testShape.cpp index 617d024f..e5e4c572 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -8,11 +8,11 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //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->appendRect(0, 0, 200, 200, 0, 0); //x, y, w, h, rx, ry + shape1->appendRect(100, 100, 300, 300, 100, 100); //x, y, w, h, rx, ry + 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 canvas->push(move(shape1)); } diff --git a/test/testStroke.cpp b/test/testStroke.cpp index b9cfb4cf..f4f7c8c0 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -8,7 +8,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Shape 1 auto shape1 = tvg::Shape::gen(); - shape1->appendRect(50, 50, 200, 200, 0); + shape1->appendRect(50, 50, 200, 200, 0, 0); shape1->fill(50, 50, 50, 255); shape1->stroke(255, 255, 255, 255); //color: r, g, b, a shape1->stroke(tvg::StrokeJoin::Bevel); //default is Bevel @@ -18,7 +18,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape 2 auto shape2 = tvg::Shape::gen(); - shape2->appendRect(300, 50, 200, 200, 0); + shape2->appendRect(300, 50, 200, 200, 0, 0); shape2->fill(50, 50, 50, 255); shape2->stroke(255, 255, 255, 255); shape2->stroke(tvg::StrokeJoin::Round); @@ -28,7 +28,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape 3 auto shape3 = tvg::Shape::gen(); - shape3->appendRect(550, 50, 200, 200, 0); + shape3->appendRect(550, 50, 200, 200, 0, 0); shape3->fill(50, 50, 50, 255); shape3->stroke(255, 255, 255, 255); shape3->stroke(tvg::StrokeJoin::Miter); @@ -166,4 +166,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testSvg.cpp b/test/testSvg.cpp index e0232748..04b9ab0e 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -33,7 +33,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Background auto shape = tvg::Shape::gen(); - shape->appendRect(0, 0, WIDTH, HEIGHT, 0); //x, y, w, h, cornerRadius + shape->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry shape->fill(255, 255, 255, 255); //r, g, b, a if (canvas->push(move(shape)) != tvg::Result::Success) return; diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 35b237c9..65492b11 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -16,8 +16,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(-285, -300, 200, 200, 0); - shape->appendRect(-185, -200, 300, 300, 100); + shape->appendRect(-285, -300, 200, 200, 0, 0); + shape->appendRect(-185, -200, 300, 300, 100, 100); shape->appendCircle(115, 100, 100, 100); shape->appendCircle(115, 200, 170, 100); shape->fill(255, 255, 255, 255); @@ -27,7 +27,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape2 auto shape2 = tvg::Shape::gen(); pShape2 = shape2.get(); - shape2->appendRect(-50, -50, 100, 100, 0); + shape2->appendRect(-50, -50, 100, 100, 0, 0); shape2->fill(0, 255, 255, 255); shape2->translate(400, 400); if (canvas->push(move(shape2)) != tvg::Result::Success) return; @@ -38,7 +38,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) /* Look, how shape3's origin is different with shape2 The center of the shape is the anchor point for transformation. */ - shape3->appendRect(100, 100, 150, 50, 20); + shape3->appendRect(100, 100, 150, 50, 20, 20); shape3->fill(255, 0, 255, 255); shape3->translate(400, 400); if (canvas->push(move(shape3)) != tvg::Result::Success) return; @@ -194,4 +194,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 051a5810..6bfbddcf 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -8,7 +8,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Shape auto shape = tvg::Shape::gen(); - shape->appendRect(-100, -100, 200, 200, 0); + shape->appendRect(-100, -100, 200, 200, 0, 0); shape->fill(255, 255, 255, 255); canvas->push(move(shape)); } @@ -20,7 +20,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) //Shape auto shape = tvg::Shape::gen(); - shape->appendRect(-100, -100, 200, 200, (100 * progress)); + shape->appendRect(-100, -100, 200, 200, (100 * progress), (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); shape->translate(800 * progress, 800 * progress); shape->scale(1 - 0.75 * progress); @@ -155,4 +155,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} From d5e78eac71d73b6c73fdd42590feb1542c69d930 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 7 Jul 2020 10:15:05 +0900 Subject: [PATCH 138/244] SvgLoader: Async conversion of svg data Change-Id: I58025e646b531a0451be096ef1891377e655a3fc --- src/loaders/svg_loader/tvgSvgLoader.cpp | 64 ++++++++++++++----------- src/loaders/svg_loader/tvgSvgLoader.h | 3 +- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 99bb689e..81991a02 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2227,13 +2227,22 @@ static void _freeSvgNode(SvgNode* node) /************************************************************************/ -SvgLoader::SvgLoader() +SvgLoader::SvgLoader() : + loaderData {vector(), + nullptr, + nullptr, + vector(), + nullptr, + nullptr, + 0, + false} { } SvgLoader::~SvgLoader() { + if (rootProgress.valid()) root = rootProgress.get(); } @@ -2261,52 +2270,53 @@ bool SvgLoader::read() { if (content.empty()) return false; - loaderData = {vector(), - nullptr, - nullptr, - vector(), - nullptr, - nullptr, - 0, - false}; + auto asyncTask = [](SvgLoader *loader) { - loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); + loader->loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); - bool res = simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParser, &loaderData); + bool res = simpleXmlParse(loader->content.c_str(), loader->content.size(), true, _svgLoaderParser, &(loader->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 unique_ptr(nullptr); + + if (loader->loaderData.doc) { + SvgNode *defs; + _updateStyle(loader->loaderData.doc, nullptr); + defs = loader->loaderData.doc->node.doc.defs; + if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients); + else { + if (!loader->loaderData.gradients.empty()) { + vector gradientList; + std::copy(loader->loaderData.gradients.begin(), loader->loaderData.gradients.end(), gradientList.begin()); + _updateGradient(loader->loaderData.doc, gradientList); + gradientList.clear(); + } } } - } + return loader->builder.build(loader->loaderData.doc); + }; - root = builder.build(loaderData.doc); + rootProgress = async(launch::async, asyncTask, this); - if (!res) return false; return true; } bool SvgLoader::close() { + if (rootProgress.valid()) root = rootProgress.get(); + if (loaderData.svgParse) free(loaderData.svgParse); _freeSvgNode(loaderData.doc); - return false; + return true; } unique_ptr SvgLoader::data() { - return move(root); + if (rootProgress.valid()) root = rootProgress.get(); + + if (root) return move(root); + else return unique_ptr(nullptr); } #endif //_TVG_SVG_LOADER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h index eba74c39..9a02a86d 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.h +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -19,7 +19,7 @@ #include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" - +#include class SvgLoader : public Loader { @@ -27,6 +27,7 @@ private: string content; SvgLoaderData loaderData; SvgSceneBuilder builder; + future> rootProgress; unique_ptr root; public: From 88ed685f1da609c107e8095792b4bb446cf7c480 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 14:09:52 +0900 Subject: [PATCH 139/244] SvgLoader: Skip unnecessary transform calc Change-Id: I58e3baae6d68a2ad4a34c8b460fe67bd36f03b3d --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 2be01222..442cde49 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -48,9 +48,9 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); - vg->scale(s); - vg->rotate(z); - vg->translate(tx, ty); + if (!(fabsf(s - 1) <= FLT_EPSILON)) vg->scale(s); + if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) vg->rotate(fmod(z, 360.0)); + if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) vg->translate(tx, ty); } if (node->type == SvgNodeType::Doc) return vg; @@ -174,9 +174,9 @@ unique_ptr _sceneBuildHelper(SvgNode* node) if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); - scene->scale(s); - scene->rotate(z); - scene->translate(tx, ty); + if (!(fabsf(s - 1) <= FLT_EPSILON)) scene->scale(s); + if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) scene->rotate(fmod(z, 360.0)); + if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) scene->translate(tx, ty); } for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { SvgNode* child = *itrChild; From a94bd31d56b4886b4e2e252ebc17e7d74fe121bf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 13:54:33 +0900 Subject: [PATCH 140/244] svg_loader: release resources just in case when it's destroyed. Change-Id: Ib4a61ae0769d3f9284e3cf450002750c47fba01c --- src/loaders/svg_loader/tvgSvgLoader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 81991a02..928c7542 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2242,7 +2242,7 @@ SvgLoader::SvgLoader() : SvgLoader::~SvgLoader() { - if (rootProgress.valid()) root = rootProgress.get(); + close(); } @@ -2305,8 +2305,13 @@ bool SvgLoader::close() { if (rootProgress.valid()) root = rootProgress.get(); - if (loaderData.svgParse) free(loaderData.svgParse); + if (loaderData.svgParse) { + free(loaderData.svgParse); + loaderData.svgParse = nullptr; + } _freeSvgNode(loaderData.doc); + loaderData.doc = nullptr; + return true; } From 1d24838c672ffa1610b64cfa1e54c41ac4c0d365 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 16:35:10 +0900 Subject: [PATCH 141/244] SvgLoader: Support arc_to draw Change-Id: I950c8e850605f990d6a0aa59a067ced571ffdb51 --- src/loaders/svg_loader/tvgSvgPath.cpp | 193 ++++++++++++++++++++++++-- 1 file changed, 183 insertions(+), 10 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index c3d3cac3..ba01ae76 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -14,7 +14,7 @@ static char* _skipComma(const char* content) } -static inline bool _parseNumber(char** content, float* number) +static bool _parseNumber(char** content, float* number) { char* end = NULL; *number = strtof(*content, &end); @@ -26,7 +26,7 @@ static inline bool _parseNumber(char** content, float* number) } -static inline bool _parseLong(char** content, int* number) +static bool _parseLong(char** content, int* number) { char* end = NULL; *number = strtol(*content, &end, 10) ? 1 : 0; @@ -36,6 +36,183 @@ static inline bool _parseLong(char** content, int* number) return true; } +void _pathAppendArcTo(vector* cmds, vector* pts, float* arr, Point* cur, Point* curCtl, float x, float y, float rx, float ry, float angle, bool largeArc, bool sweep) +{ + float cxp, cyp, cx, cy; + float sx, sy; + float cosPhi, sinPhi; + float dx2, dy2; + float x1p, y1p; + float x1p2, y1p2; + float rx2, ry2; + float lambda; + float c; + float at; + float theta1, deltaTheta; + float nat; + float delta, bcp; + float cosPhiRx, cosPhiRy; + float sinPhiRx, sinPhiRy; + float cosTheta1, sinTheta1; + int segments, i; + + //Some helpful stuff is available here: + //http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + sx = cur->x; + sy = cur->y; + + //If start and end points are identical, then no arc is drawn + if ((fabs(x - sx) < (1.0f / 256.0f)) && (fabs(y - sy) < (1.0f / 256.0f))) return; + + //Correction of out-of-range radii, see F6.6.1 (step 2) + rx = fabs(rx); + ry = fabs(ry); + if ((rx < 0.5f) || (ry < 0.5f)) { + Point p = {x, y}; + cmds->push_back(PathCommand::LineTo); + pts->push_back(p); + *cur = p; + return; + } + + angle = angle * M_PI / 180.0f; + cosPhi = cosf(angle); + sinPhi = sinf(angle); + dx2 = (sx - x) / 2.0f; + dy2 = (sy - y) / 2.0f; + x1p = cosPhi * dx2 + sinPhi * dy2; + y1p = cosPhi * dy2 - sinPhi * dx2; + x1p2 = x1p * x1p; + y1p2 = y1p * y1p; + rx2 = rx * rx; + ry2 = ry * ry; + lambda = (x1p2 / rx2) + (y1p2 / ry2); + + //Correction of out-of-range radii, see F6.6.2 (step 4) + if (lambda > 1.0f) { + //See F6.6.3 + float lambdaRoot = sqrt(lambda); + + rx *= lambdaRoot; + ry *= lambdaRoot; + //Update rx2 and ry2 + rx2 = rx * rx; + ry2 = ry * ry; + } + + c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2); + + //Check if there is no possible solution + //(i.e. we can't do a square root of a negative value) + if (c < 0.0f) { + //Scale uniformly until we have a single solution + //(see F6.2) i.e. when c == 0.0 + float scale = sqrt(1.0f - c / (rx2 * ry2)); + rx *= scale; + ry *= scale; + //Update rx2 and ry2 + rx2 = rx * rx; + ry2 = ry * ry; + + //Step 2 (F6.5.2) - simplified since c == 0.0 + cxp = 0.0f; + cyp = 0.0f; + //Step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0 + cx = 0.0f; + cy = 0.0f; + } else { + //Complete c calculation + c = sqrt(c / ((rx2 * y1p2) + (ry2 * x1p2))); + //Inverse sign if Fa == Fs + if (largeArc == sweep) c = -c; + + //Step 2 (F6.5.2) + cxp = c * (rx * y1p / ry); + cyp = c * (-ry * x1p / rx); + + //Step 3 (F6.5.3 first part) + cx = cosPhi * cxp - sinPhi * cyp; + cy = sinPhi * cxp + cosPhi * cyp; + } + + //Step 3 (F6.5.3 second part) we now have the center point of the ellipse + cx += (sx + x) / 2.0f; + cy += (sy + y) / 2.0f; + + //Sstep 4 (F6.5.4) + //We dont' use arccos (as per w3c doc), see + //http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm + //Note: atan2 (0.0, 1.0) == 0.0 + at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx)); + theta1 = (at < 0.0f) ? 2.0f * M_PI + at : at; + + nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx)); + deltaTheta = (nat < at) ? 2.0f * M_PI - at + nat : nat - at; + + if (sweep) { + //Ensure delta theta < 0 or else add 360 degrees + if (deltaTheta < 0.0f) deltaTheta += 2.0f * M_PI; + } else { + //Ensure delta theta > 0 or else substract 360 degrees + if (deltaTheta > 0.0f) deltaTheta -= 2.0f * M_PI; + } + + //Add several cubic bezier to approximate the arc + //(smaller than 90 degrees) + //We add one extra segment because we want something + //Smaller than 90deg (i.e. not 90 itself) + segments = (int)(fabs(deltaTheta / M_PI_2)) + 1.0f; + delta = deltaTheta / segments; + + //http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13) + bcp = 4.0f / 3.0f * (1.0f - cos(delta / 2.0f)) / sin(delta / 2.0f); + + cosPhiRx = cosPhi * rx; + cosPhiRy = cosPhi * ry; + sinPhiRx = sinPhi * rx; + sinPhiRy = sinPhi * ry; + + cosTheta1 = cos(theta1); + sinTheta1 = sin(theta1); + + for (i = 0; i < segments; ++i) { + //End angle (for this segment) = current + delta + float c1x, c1y, ex, ey, c2x, c2y; + float theta2 = theta1 + delta; + float cosTheta2 = cos(theta2); + float sinTheta2 = sin(theta2); + static Point p[3]; + + //First control point (based on start point sx,sy) + c1x = sx - bcp * (cosPhiRx * sinTheta1 + sinPhiRy * cosTheta1); + c1y = sy + bcp * (cosPhiRy * cosTheta1 - sinPhiRx * sinTheta1); + + //End point (for this segment) + ex = cx + (cosPhiRx * cosTheta2 - sinPhiRy * sinTheta2); + ey = cy + (sinPhiRx * cosTheta2 + cosPhiRy * sinTheta2); + + //Second control point (based on end point ex,ey) + c2x = ex + bcp * (cosPhiRx * sinTheta2 + sinPhiRy * cosTheta2); + c2y = ey + bcp * (sinPhiRx * sinTheta2 - cosPhiRy * cosTheta2); + cmds->push_back(PathCommand::CubicTo); + p[0] = {c1x, c1y}; + p[1] = {c2x, c2y}; + p[2] = {ex, ey}; + pts->push_back(p[0]); + pts->push_back(p[1]); + pts->push_back(p[2]); + *curCtl = p[1]; + *cur = p[2]; + + //Next start point is the current end point (same for angle) + sx = ex; + sy = ey; + theta1 = theta2; + //Avoid recomputations + cosTheta1 = cosTheta2; + sinTheta1 = sinTheta2; + } +} static int _numberCount(char cmd) { @@ -170,12 +347,12 @@ static void _processCommand(vector* cmds, vector* pts, char } case 'q': case 'Q': { - tvg::Point p[3]; + 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); + cmds->push_back(PathCommand::CubicTo); p[0] = {ctrl_x0, ctrl_y0}; p[1] = {ctrl_x1, ctrl_y1}; p[2] = {arr[2], arr[3]}; @@ -217,12 +394,8 @@ static void _processCommand(vector* cmds, vector* pts, char } case 'a': case 'A': { - //TODO: Implement arc_to - break; - } - case 'E': - case 'e': { - //TODO: Implement arc + _pathAppendArcTo(cmds, pts, arr, cur, curCtl, arr[5], arr[6], arr[0], arr[1], arr[2], arr[3], arr[4]); + *cur = {arr[5] ,arr[6]}; break; } default: { From 6967b998b67d65e35e9dabd9cfecb0226fb87b1e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 15:12:11 +0900 Subject: [PATCH 142/244] common loader: return viewbox info from the vector resource. if a scene loads a vector resource, it must have viewbox info from the design, That viewbox will be used as bounding box so that user can scale up/down the scene by its requirements. Change-Id: Iafa39af23118a03de207c745364d56c837892e1b --- src/lib/tvgLoader.h | 6 +++ src/lib/tvgSceneImpl.h | 71 ++++++++++++++----------- src/loaders/svg_loader/tvgSvgLoader.cpp | 7 +++ 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h index 8a1c9184..8f5bb49f 100644 --- a/src/lib/tvgLoader.h +++ b/src/lib/tvgLoader.h @@ -23,6 +23,12 @@ namespace tvg class Loader { public: + //default view box, if any. + float vx = 0; + float vy = 0; + float vw = 0; + float vh = 0; + virtual ~Loader() {} virtual bool open(const char* path) = 0; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 4e412d47..a70991c6 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -74,11 +74,12 @@ struct Scene::Impl { if (loader) { auto scene = loader->data(); - auto p = scene.release(); - if (!p) return false; - paints.push_back(p); - loader->close(); - loader.reset(nullptr); + if (scene) { + auto p = scene.release(); + if (!p) return false; + paints.push_back(p); + loader->close(); + } } if (flag & RenderUpdateFlag::Transform) { @@ -121,38 +122,44 @@ struct Scene::Impl bool bounds(float* px, float* py, float* pw, float* ph) { - auto x = FLT_MAX; - auto y = FLT_MAX; - auto w = 0.0f; - auto h = 0.0f; + if (loader) { + if (px) *px = loader->vx; + if (py) *py = loader->vy; + if (pw) *pw = loader->vw; + if (ph) *ph = loader->vh; + } else { + auto x = FLT_MAX; + auto y = FLT_MAX; + auto w = 0.0f; + auto h = 0.0f; - for(auto paint: paints) { - auto x2 = FLT_MAX; - auto y2 = FLT_MAX; - auto w2 = 0.0f; - auto h2 = 0.0f; + for(auto paint: paints) { + auto x2 = FLT_MAX; + auto y2 = FLT_MAX; + auto w2 = 0.0f; + auto h2 = 0.0f; - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; + if (paint->id() == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); + if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; + } else { + auto shape = static_cast(paint); + if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; + } + + //Merge regions + if (x2 < x) x = x2; + if (x + w < x2 + w2) w = (x2 + w2) - x; + if (y2 < y) y = x2; + if (y + h < y2 + h2) h = (y2 + h2) - y; } - //Merge regions - if (x2 < x) x = x2; - if (x + w < x2 + w2) w = (x2 + w2) - x; - if (y2 < y) y = x2; - if (y + h < y2 + h2) h = (y2 + h2) - y; + if (px) *px = x; + if (py) *py = y; + if (pw) *pw = w; + if (ph) *ph = h; } - - if (px) *px = x; - if (py) *py = y; - if (pw) *pw = w; - if (ph) *ph = h; - return true; } diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 928c7542..d2580054 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2262,6 +2262,13 @@ bool SvgLoader::open(const char* path) if (content.empty()) return false; } + //FIXME: Verify this resource is normal SVG, otherwise return false + //Also, return the brief resource info such as viewbox: + //this->vx = ? + //this->vy = ? + //this->vw = ? + //this->vh = ? + return true; } From feb6aad641af8d792a1c3d57e642b641980048d5 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 7 Jul 2020 15:09:13 +0900 Subject: [PATCH 143/244] SvgLoader: Fix z-angle calculation Change-Id: I9220abd9f92dbdf250ea071af128a93a0bbb3d78 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 442cde49..69e4a0a2 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -29,11 +29,11 @@ static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, fl *ty = m->e23; cs = m->e11; - si = m->e12; + si = m->e21; rz = atan2(si, cs); - *z = rz * (180.0 / M_PI); - zcs = cosf(rz); - zsi = sinf(rz); + *z = rz * (180.0f / M_PI); + zcs = cosf(-1.0f * rz); + zsi = sinf(-1.0f * rz); m->e11 = m->e11 * zcs + m->e12 * zsi; m->e22 = m->e21 * (-1 * zsi) + m->e22 * zcs; *s = m->e11 > m->e22 ? m->e11 : m->e22; From 018f4919da4cfcbd3df97c5da91054a8f31688e0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 17:46:29 +0900 Subject: [PATCH 144/244] svg_loader: allow deferred loading. don't push thread to work hard unless it's necessary. that might occur performance drop. Change-Id: Ib71fa0ae46461b10b7ed7ef356512fbf2a7aa0a8 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 928c7542..2bfafdb3 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2295,7 +2295,7 @@ bool SvgLoader::read() return loader->builder.build(loader->loaderData.doc); }; - rootProgress = async(launch::async, asyncTask, this); + rootProgress = async((launch::async | launch::deferred), asyncTask, this); return true; } From c0280e6d57ead75dd0304cb2cdbcf1efb36513c3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 17:52:16 +0900 Subject: [PATCH 145/244] svg_loader: code refactoring. initialize members in its own constructor. Change-Id: I6450971330dd3e3235b0f690a8d9b066cf374212 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 11 +---------- src/loaders/svg_loader/tvgSvgLoaderCommon.h | 14 +++++++------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 2bfafdb3..cf91fb25 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2226,16 +2226,7 @@ static void _freeSvgNode(SvgNode* node) /* External Class Implementation */ /************************************************************************/ - -SvgLoader::SvgLoader() : - loaderData {vector(), - nullptr, - nullptr, - vector(), - nullptr, - nullptr, - 0, - false} +SvgLoader::SvgLoader() { } diff --git a/src/loaders/svg_loader/tvgSvgLoaderCommon.h b/src/loaders/svg_loader/tvgSvgLoaderCommon.h index a909e547..b5ae7bb2 100644 --- a/src/loaders/svg_loader/tvgSvgLoaderCommon.h +++ b/src/loaders/svg_loader/tvgSvgLoaderCommon.h @@ -325,13 +325,13 @@ struct SvgParser struct SvgLoaderData { vector stack; - SvgNode* doc; - SvgNode* def; + SvgNode* doc = nullptr; + SvgNode* def = nullptr; vector gradients; - SvgStyleGradient* latestGradient; //For stops - SvgParser* svgParse; - int level; - bool result; + SvgStyleGradient* latestGradient = nullptr; //For stops + SvgParser* svgParse = nullptr; + int level = 0; + bool result = false; }; -#endif +#endif \ No newline at end of file From e2fc3538463a8e8b8370cb81ef6758df750a43cf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 8 Jul 2020 10:44:51 +0900 Subject: [PATCH 146/244] build: refactoriong meson script. move gl dependency to gl_engine part which is right position. Change-Id: I9d4935f94eff96ca1527762c92d07f9b216f19cd --- meson.build | 2 +- src/lib/gl_engine/meson.build | 7 ++++++- src/meson.build | 6 +----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index b1cf7acd..66b907d7 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('thorvg', 'cpp', - default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14', 'optimization=s'], + default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++17', 'optimization=s'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 943fb067..6856f1dd 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -14,7 +14,12 @@ source_file = [ 'tvgGlShaderSrc.cpp', ] +egl_dep = meson.get_compiler('cpp').find_library('EGL') +gles_dep = meson.get_compiler('cpp').find_library('GLESv2') +external_dep = [egl_dep, gles_dep] + glengine_dep = declare_dependency( + dependencies : external_dep, include_directories : include_directories('.'), - sources : source_file + sources : source_file, ) diff --git a/src/meson.build b/src/meson.build index 493497b2..7320bb25 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,12 +4,8 @@ subdir('lib') subdir('loaders') subdir('examples') -m_dep = meson.get_compiler('cpp').find_library('m') 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') - -thorvg_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, svgloader_dep, thread_dep] thorvg_lib = library( From 84af527a27b7e2cbe67717ee5fbb527ec903d35c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 8 Jul 2020 10:51:34 +0900 Subject: [PATCH 147/244] build: refactoring meson script. move out engine/loader dependency to its immediate parent folders. Change-Id: I7f08433fc6d2a333951fceaffea81cbe2e5da9e3 --- meson.build | 2 +- src/lib/meson.build | 10 ++++++---- src/loaders/meson.build | 5 +++++ src/meson.build | 3 +-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 66b907d7..0142de08 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('thorvg', 'cpp', - default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++17', 'optimization=s'], + default_options : ['buildtype=debugoptimized', 'werror=false', 'optimization=s'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/meson.build b/src/lib/meson.build index 53c9a19a..9a7dc61c 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -25,8 +25,10 @@ source_file = [ 'tvgSwCanvas.cpp', ] -src_dep = declare_dependency( - include_directories : include_directories('.'), - sources : source_file -) +engine_dep = [swengine_dep, glengine_dep] +common_dep = declare_dependency( + dependencies : engine_dep, + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/loaders/meson.build b/src/loaders/meson.build index 53186ddb..3abf0fd4 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -1 +1,6 @@ subdir('svg_loader') + +loader_dep = declare_dependency( + dependencies : svgloader_dep, + include_directories : include_directories('.'), +) diff --git a/src/meson.build b/src/meson.build index 7320bb25..faff2b38 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,8 +5,7 @@ subdir('loaders') subdir('examples') thread_dep = meson.get_compiler('cpp').find_library('pthread') -thorvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, svgloader_dep, thread_dep] - +thorvg_lib_dep = [ common_dep, loader_dep, thread_dep] thorvg_lib = library( 'thorvg', From 99428ee80a2f9ab8774fb151a6ef7dcbd60ad207 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 8 Jul 2020 13:08:28 +0900 Subject: [PATCH 148/244] build: support features toggling in meson option. Change-Id: Id1ebda70fe8380aaa913f79af26e5c39893a6df5 --- meson.build | 18 ++++++++++-- meson_options.txt | 11 ++++++++ src/lib/gl_engine/meson.build | 10 +++---- src/lib/meson.build | 13 ++++++--- src/lib/sw_engine/meson.build | 8 +++--- src/lib/tvgCommon.h | 2 ++ src/lib/tvgGlCanvas.cpp | 21 +++++++++++++- src/lib/tvgInitializer.cpp | 39 +++++++++++++++++++++----- src/lib/tvgLoaderMgr.cpp | 9 ++++-- src/lib/tvgRender.h | 18 ++++++------ src/lib/tvgSwCanvas.cpp | 21 ++++++++++++-- src/loaders/meson.build | 8 ++++-- src/loaders/svg_loader/meson.build | 8 +++--- src/meson.build | 2 +- test/testAsync.cpp | 33 ++++++++++++---------- test/testBlending.cpp | 27 ++++++++++-------- test/testBoundary.cpp | 27 ++++++++++-------- test/testCustomTransform.cpp | 45 +++++++++++++++++------------- test/testDirectUpdate.cpp | 43 +++++++++++++++------------- test/testGradientTransform.cpp | 9 ++++-- test/testLinearGradient.cpp | 27 ++++++++++-------- test/testMultiShapes.cpp | 27 ++++++++++-------- test/testPath.cpp | 29 +++++++++++-------- test/testPathCopy.cpp | 27 ++++++++++-------- test/testRadialGradient.cpp | 29 +++++++++++-------- test/testScene.cpp | 29 +++++++++++-------- test/testSceneTransform.cpp | 45 +++++++++++++++++------------- test/testShape.cpp | 29 +++++++++++-------- test/testStroke.cpp | 29 +++++++++++-------- test/testStrokeLine.cpp | 27 ++++++++++-------- test/testSvg.cpp | 29 +++++++++++-------- test/testTransform.cpp | 45 +++++++++++++++++------------- test/testUpdate.cpp | 45 +++++++++++++++++------------- 33 files changed, 492 insertions(+), 297 deletions(-) create mode 100644 meson_options.txt diff --git a/meson.build b/meson.build index 0142de08..c23bcb16 100644 --- a/meson.build +++ b/meson.build @@ -6,12 +6,24 @@ project('thorvg', config_h = configuration_data() +if get_option('engines').contains('sw') == true + config_h.set10('THORVG_SW_RASTER_SUPPORT', true) +endif + +if get_option('engines').contains('gl') == true + config_h.set10('THORVG_GL_RASTER_SUPPORT', true) +endif + +if get_option('loaders').contains('svg') == true + config_h.set10('THORVG_SVG_LOADER_SUPPORT', true) +endif + configure_file( - output: 'config.h', - configuration: config_h + output: 'config.h', + configuration: config_h ) -headers = [include_directories('inc')] +headers = [include_directories('inc'), include_directories('.')] subdir('inc') subdir('src') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..daf3923f --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,11 @@ +option('engines', + type: 'array', + choices: ['sw', 'gl'], + value: ['sw', 'gl'], + description: 'Enable Rasterizer Engine in thorvg') + +option('loaders', + type: 'array', + choices: ['svg'], + value: ['svg'], + description: 'Enable Vector File Loader in thorvg') diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 6856f1dd..63c7ee89 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -18,8 +18,8 @@ egl_dep = meson.get_compiler('cpp').find_library('EGL') gles_dep = meson.get_compiler('cpp').find_library('GLESv2') external_dep = [egl_dep, gles_dep] -glengine_dep = declare_dependency( - dependencies : external_dep, - include_directories : include_directories('.'), - sources : source_file, -) +engine_dep += [declare_dependency( + dependencies : external_dep, + include_directories : include_directories('.'), + sources : source_file, +)] diff --git a/src/lib/meson.build b/src/lib/meson.build index 9a7dc61c..46d6a997 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -1,5 +1,12 @@ -subdir('sw_engine') -subdir('gl_engine') +engine_dep = [] + +if get_option('engines').contains('sw') == true + subdir('sw_engine') +endif + +if get_option('engines').contains('gl') == true + subdir('gl_engine') +endif source_file = [ 'tvgCanvasImpl.h', @@ -25,8 +32,6 @@ source_file = [ 'tvgSwCanvas.cpp', ] -engine_dep = [swengine_dep, glengine_dep] - common_dep = declare_dependency( dependencies : engine_dep, include_directories : include_directories('.'), diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index 8b062587..66b1e0d1 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -10,7 +10,7 @@ source_file = [ 'tvgSwStroke.cpp', ] -swengine_dep = declare_dependency( - include_directories : include_directories('.'), - sources : source_file -) +engine_dep += [declare_dependency( + include_directories : include_directories('.'), + sources : source_file +)] diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 79f7c187..ac91f499 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -17,6 +17,8 @@ #ifndef _TVG_COMMON_H_ #define _TVG_COMMON_H_ +#include "config.h" + #include #include #include diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 1af7eace..4502498e 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -18,9 +18,17 @@ #define _TVG_GLCANVAS_CPP_ #include "tvgCommon.h" -#include "tvgGlRenderer.h" #include "tvgCanvasImpl.h" +#ifdef THORVG_GL_RASTER_SUPPORT + #include "tvgGlRenderer.h" +#else + class GlRenderer : public RenderMethod + { + //Non Supported. Dummy Class */ + }; +#endif + /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ @@ -35,11 +43,16 @@ struct GlCanvas::Impl /* External Class Implementation */ /************************************************************************/ +#ifdef THORVG_GL_RASTER_SUPPORT GlCanvas::GlCanvas() : Canvas(GlRenderer::inst()), pImpl(make_unique()) +#else +GlCanvas::GlCanvas() : Canvas(nullptr), pImpl(make_unique()) +#endif { } + GlCanvas::~GlCanvas() { } @@ -47,6 +60,7 @@ GlCanvas::~GlCanvas() Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { +#ifdef THORVG_GL_RASTER_SUPPORT //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; @@ -54,15 +68,20 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; return Result::Success; +#endif + return Result::NonSupport; } unique_ptr GlCanvas::gen() noexcept { +#ifdef THORVG_GL_RASTER_SUPPORT auto canvas = unique_ptr(new GlCanvas); assert(canvas); return canvas; +#endif + return unique_ptr(nullptr); } diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index 857698d2..468178ec 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -18,10 +18,17 @@ #define _TVG_INITIALIZER_CPP_ #include "tvgCommon.h" -#include "tvgSwRenderer.h" -#include "tvgGlRenderer.h" #include "tvgLoaderMgr.h" +#ifdef THORVG_SW_RASTER_SUPPORT + #include "tvgSwRenderer.h" +#endif + +#ifdef THORVG_GL_RASTER_SUPPORT + #include "tvgGlRenderer.h" +#endif + + /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ @@ -32,14 +39,24 @@ Result Initializer::init(CanvasEngine engine) noexcept { + auto nonSupport = true; + if (engine == CanvasEngine::Sw) { - if (!SwRenderer::init()) return Result::InsufficientCondition; + #ifdef THORVG_SW_RASTER_SUPPORT + if (!SwRenderer::init()) return Result::InsufficientCondition; + nonSupport = false; + #endif } else if (engine == CanvasEngine::Gl) { - if (!GlRenderer::init()) return Result::InsufficientCondition; + #ifdef THORVG_GL_RASTER_SUPPORT + if (!GlRenderer::init()) return Result::InsufficientCondition; + nonSupport = false; + #endif } else { return Result::InvalidArguments; } + if (nonSupport) return Result::NonSupport; + if (!LoaderMgr::init()) return Result::Unknown; return Result::Success; @@ -48,16 +65,24 @@ Result Initializer::init(CanvasEngine engine) noexcept Result Initializer::term(CanvasEngine engine) noexcept { - //TODO: deinitialize modules + auto nonSupport = true; if (engine == CanvasEngine::Sw) { - if (!SwRenderer::term()) return Result::InsufficientCondition; + #ifdef THORVG_SW_RASTER_SUPPORT + if (!SwRenderer::term()) return Result::InsufficientCondition; + nonSupport = false; + #endif } else if (engine == CanvasEngine::Gl) { - if (!GlRenderer::term()) return Result::InsufficientCondition; + #ifdef THORVG_GL_RASTER_SUPPORT + if (!GlRenderer::term()) return Result::InsufficientCondition; + nonSupport = false; + #endif } else { return Result::InvalidArguments; } + if (nonSupport) return Result::NonSupport; + if (!LoaderMgr::term()) return Result::Unknown; return Result::Success; diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index a99838b7..ae657322 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -18,8 +18,10 @@ #define _TVG_LOADER_MGR_CPP_ #include "tvgCommon.h" -#include "tvgSvgLoader.h" +#ifdef THORVG_SVG_LOADER_SUPPORT + #include "tvgSvgLoader.h" +#endif static int initCnt = 0; @@ -45,8 +47,11 @@ bool LoaderMgr::term() unique_ptr LoaderMgr::loader(const char* path) { - //TODO: +#ifdef THORVG_SVG_LOADER_SUPPORT return unique_ptr(new SvgLoader); +#endif + cout << "Non supported format: " << path << endl; + return unique_ptr(nullptr); } #endif //_TVG_LOADER_MGR_CPP_ \ No newline at end of file diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index b0a3c846..e20271b8 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -51,15 +51,15 @@ class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; - virtual bool dispose(const Shape& shape, void *data) = 0; - virtual bool preRender() = 0; - virtual bool render(const Shape& shape, void *data) = 0; - virtual bool postRender() = 0; - virtual bool clear() = 0; - virtual bool flush() = 0; - virtual uint32_t ref() = 0; - virtual uint32_t unref() = 0; + virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { return nullptr; } + virtual bool dispose(const Shape& shape, void *data) { return false; } + virtual bool preRender() { return false; } + virtual bool render(const Shape& shape, void *data) { return false; } + virtual bool postRender() { return false; } + virtual bool clear() { return false; } + virtual bool flush() { return false; } + virtual uint32_t ref() { return 0; } + virtual uint32_t unref() { return 0; } }; struct RenderInitializer diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index a0bfdd04..4c61eaa6 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -18,9 +18,16 @@ #define _TVG_SWCANVAS_CPP_ #include "tvgCommon.h" -#include "tvgSwRenderer.h" #include "tvgCanvasImpl.h" +#ifdef THORVG_SW_RASTER_SUPPORT + #include "tvgSwRenderer.h" +#else + class SwRenderer : public RenderMethod + { + //Non Supported. Dummy Class */ + }; +#endif /************************************************************************/ /* Internal Class Implementation */ @@ -36,7 +43,11 @@ struct SwCanvas::Impl /* External Class Implementation */ /************************************************************************/ +#ifdef THORVG_SW_RASTER_SUPPORT SwCanvas::SwCanvas() : Canvas(SwRenderer::inst()), pImpl(make_unique()) +#else +SwCanvas::SwCanvas() : Canvas(nullptr), pImpl(make_unique()) +#endif { } @@ -48,6 +59,7 @@ SwCanvas::~SwCanvas() Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { +#ifdef THORVG_SW_RASTER_SUPPORT //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; @@ -55,15 +67,20 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; return Result::Success; +#endif + return Result::NonSupport; } unique_ptr SwCanvas::gen() noexcept { +#ifdef THORVG_SW_RASTER_SUPPORT auto canvas = unique_ptr(new SwCanvas); assert(canvas); - return canvas; + return canvas; +#endif + return unique_ptr(nullptr); } #endif /* _TVG_SWCANVAS_CPP_ */ diff --git a/src/loaders/meson.build b/src/loaders/meson.build index 3abf0fd4..aaf1324f 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -1,6 +1,10 @@ -subdir('svg_loader') +subloader_dep = [] + +if get_option('loaders').contains('svg') == true + subdir('svg_loader') +endif loader_dep = declare_dependency( - dependencies : svgloader_dep, + dependencies: subloader_dep, include_directories : include_directories('.'), ) diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build index de7adf76..d62762cf 100644 --- a/src/loaders/svg_loader/meson.build +++ b/src/loaders/svg_loader/meson.build @@ -10,7 +10,7 @@ source_file = [ 'tvgSvgSceneBuilder.cpp', ] -svgloader_dep = declare_dependency( - include_directories : include_directories('.'), - sources : source_file -) +subloader_dep += [declare_dependency( + include_directories : include_directories('.'), + sources : source_file +)] diff --git a/src/meson.build b/src/meson.build index faff2b38..23c4ad54 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,7 +5,7 @@ subdir('loaders') subdir('examples') thread_dep = meson.get_compiler('cpp').find_library('pthread') -thorvg_lib_dep = [ common_dep, loader_dep, thread_dep] +thorvg_lib_dep = [common_dep, loader_dep, thread_dep] thorvg_lib = library( 'thorvg', diff --git a/test/testAsync.cpp b/test/testAsync.cpp index bb890abf..df81020a 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -156,22 +156,27 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + 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(tvgEngine); - 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); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 6f5f6e1b..6765cb67 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -136,19 +136,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index b23b82ec..71dd6a01 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -125,19 +125,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 08075d25..59454900 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -179,28 +179,33 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); - Elm_Transit *transit = elm_transit_add(); + Elm_Transit *transit = elm_transit_add(); + + 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_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(tvgEngine); - 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); + cout << "engine is not supported" << endl; } - - 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(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 437ad1f4..67d0240c 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -142,28 +142,33 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); - Elm_Transit *transit = elm_transit_add(); + Elm_Transit *transit = elm_transit_add(); + + 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_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(tvgEngine); - 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); + cout << "engine is not supported" << endl; } - - 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(tvgEngine); + return 0; } diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index fd5a563f..1c1b8206 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -207,7 +207,7 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { elm_init(argc, argv); @@ -231,4 +231,9 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} + + } else { + cout << "engine is not supported" << endl; + } + return 0; +} \ No newline at end of file diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 45f38d75..826287b0 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -154,19 +154,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index ec46f2f9..88601351 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -114,19 +114,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } diff --git a/test/testPath.cpp b/test/testPath.cpp index d74b89d8..a6656a87 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -131,19 +131,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index ebf900c3..dd008270 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -168,19 +168,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } \ No newline at end of file diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index 71cfaaef..054bf12d 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -154,19 +154,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testScene.cpp b/test/testScene.cpp index bee2b54f..b796a5b8 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -161,19 +161,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index d5d538d5..aeaf11eb 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -203,28 +203,33 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); - Elm_Transit *transit = elm_transit_add(); + Elm_Transit *transit = elm_transit_add(); + + 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_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(tvgEngine); - 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); + cout << "engine is not supported" << endl; } - - 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(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testShape.cpp b/test/testShape.cpp index e5e4c572..391b55ff 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -104,19 +104,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testStroke.cpp b/test/testStroke.cpp index f4f7c8c0..f7c1a88f 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -151,19 +151,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 1856453a..bc3f9601 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -188,19 +188,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + return 0; } \ No newline at end of file diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 04b9ab0e..edb987b8 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -128,19 +128,24 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); - if (tvgEngine == tvg::CanvasEngine::Sw) { - createSwView(); } else { - createGlView(); + cout << "engine is not supported" << endl; } - - elm_run(); - elm_shutdown(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + return 0; +} \ No newline at end of file diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 65492b11..da7c87cd 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -170,28 +170,33 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); - Elm_Transit *transit = elm_transit_add(); + Elm_Transit *transit = elm_transit_add(); + + 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_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(tvgEngine); - 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); + cout << "engine is not supported" << endl; } - - 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(tvgEngine); -} + return 0; +} \ No newline at end of file diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 6bfbddcf..c3504356 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -131,28 +131,33 @@ int main(int argc, char **argv) } //Initialize ThorVG Engine - tvg::Initializer::init(tvgEngine); + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); - Elm_Transit *transit = elm_transit_add(); + Elm_Transit *transit = elm_transit_add(); + + 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_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(tvgEngine); - 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); + cout << "engine is not supported" << endl; } - - 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(tvgEngine); -} + return 0; +} \ No newline at end of file From f6444436557600ebecd36e1fd7a2acf1270bf74a Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 9 Jul 2020 13:23:41 +0900 Subject: [PATCH 149/244] SvgLoader: Support to linear, radial gradient Change-Id: Ida3f6ccca5f0d6ed1922b7ce99d2d2f3203f5ba9 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 55 +++-- src/loaders/svg_loader/tvgSvgLoaderCommon.h | 26 +-- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 209 +++++++++++++++++- test/svgs/lineargrad1.svg | 20 ++ test/svgs/radialgrad1.svg | 19 ++ 5 files changed, 279 insertions(+), 50 deletions(-) create mode 100644 test/svgs/lineargrad1.svg create mode 100644 test/svgs/radialgrad1.svg diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index f4ed3be9..f8f7c4ea 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -1365,11 +1365,18 @@ static SvgNode* _findChildById(SvgNode* node, const char* id) } -static vector _cloneGradStops(vector src) +static void _cloneGradStops(vector *dst, vector src) { - vector dst; - copy(src.begin(), src.end(), dst.begin()); - return dst; + for(vector::iterator itrStop = src.begin(); itrStop != src.end(); itrStop++) { + Fill::ColorStop *stop = (Fill::ColorStop *)malloc(sizeof(Fill::ColorStop)); + stop->r = (*itrStop)->r; + stop->g = (*itrStop)->g; + stop->b = (*itrStop)->b; + stop->a = (*itrStop)->a; + stop->offset = (*itrStop)->offset; + dst->push_back(stop); + } + } @@ -1381,8 +1388,8 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from) 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->id = from->id ? _copyId(from->id->c_str()) : nullptr; + grad->ref = from->ref ? _copyId(from->ref->c_str()) : nullptr; grad->spread = from->spread; grad->usePercentage = from->usePercentage; grad->userSpace = from->userSpace; @@ -1390,7 +1397,6 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from) 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)); @@ -1399,6 +1405,7 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from) memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient)); } + _cloneGradStops(&(grad->stops), from->stops); return grad; } @@ -1562,14 +1569,14 @@ FIND_FACTORY(Group, groupTags); FIND_FACTORY(Graphics, graphicsTags); -SvgGradientSpread _parseSpreadValue(const char* value) +FillSpread _parseSpreadValue(const char* value) { - SvgGradientSpread spread = SvgGradientSpread::Pad; + FillSpread spread = FillSpread::Pad; if (!strcmp(value, "reflect")) { - spread = SvgGradientSpread::Reflect; + spread = FillSpread::Reflect; } else if (!strcmp(value, "repeat")) { - spread = SvgGradientSpread::Repeat; + spread = FillSpread::Repeat; } return spread; @@ -1730,7 +1737,7 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char static bool _attrParseStops(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; - SvgGradientStop* stop = loader->svgParse->gradStop; + Fill::ColorStop* stop = loader->svgParse->gradStop; if (!strcmp(key, "offset")) { stop->offset = _toOffset(value); @@ -2008,7 +2015,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } loader->latestGradient = gradient; } else if (!strcmp(tagName, "stop")) { - SvgGradientStop* stop = (SvgGradientStop*)calloc(1, sizeof(SvgGradientStop)); + Fill::ColorStop* stop = (Fill::ColorStop*)calloc(1, sizeof(Fill::ColorStop)); loader->svgParse->gradStop = stop; /* default value for opacity */ stop->a = 255; @@ -2067,7 +2074,7 @@ static void _styleInherit(SvgStyleProperty* child, SvgStyleProperty* parent) 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 (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url->c_str()); } if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) { child->fill.opacity = parent->fill.opacity; @@ -2109,12 +2116,12 @@ static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle) } -static SvgStyleGradient* _gradientDup(vector gradList, const char* id) +static SvgStyleGradient* _gradientDup(vector gradList, string* id) { SvgStyleGradient* result = nullptr; for (vector::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { - if ((*itrGrad)->id->compare(string(id))) { + if (!((*itrGrad)->id->compare(*id))) { result = _cloneGradient(*itrGrad); break; } @@ -2122,9 +2129,9 @@ static SvgStyleGradient* _gradientDup(vector gradList, const if (result && result->ref) { for (vector::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { - if ((*itrGrad)->id->compare(*result->ref)) { + if (!((*itrGrad)->id->compare(*result->ref))) { if (!result->stops.empty()) { - result->stops = _cloneGradStops((*itrGrad)->stops); + _cloneGradStops(&(result->stops), (*itrGrad)->stops); } //TODO: Properly inherit other property break; @@ -2138,15 +2145,15 @@ static SvgStyleGradient* _gradientDup(vector gradList, const static void _updateGradient(SvgNode* node, vector gradList) { - if (node->child.empty()) { + 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()); + node->style->fill.paint.gradient = _gradientDup(gradList, node->style->fill.paint.url); } else if (node->style->stroke.paint.url) { - node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url->c_str()); + //node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url); } } } @@ -2161,7 +2168,7 @@ static void _freeGradientStyle(SvgStyleGradient* grad) free(grad->linear); if (grad->transform) free(grad->transform); - for(vector::iterator itrStop = grad->stops.begin(); itrStop != grad->stops.end(); itrStop++) { + for(vector::iterator itrStop = grad->stops.begin(); itrStop != grad->stops.end(); itrStop++) { free(*itrStop); } free(grad); @@ -2284,7 +2291,9 @@ bool SvgLoader::read() else { if (!loader->loaderData.gradients.empty()) { vector gradientList; - std::copy(loader->loaderData.gradients.begin(), loader->loaderData.gradients.end(), gradientList.begin()); + for(vector::iterator itrGrad = loader->loaderData.gradients.begin(); itrGrad != loader->loaderData.gradients.end(); itrGrad++) { + gradientList.push_back(*itrGrad); + } _updateGradient(loader->loaderData.doc, gradientList); gradientList.clear(); } diff --git a/src/loaders/svg_loader/tvgSvgLoaderCommon.h b/src/loaders/svg_loader/tvgSvgLoaderCommon.h index b5ae7bb2..2f1af74f 100644 --- a/src/loaders/svg_loader/tvgSvgLoaderCommon.h +++ b/src/loaders/svg_loader/tvgSvgLoaderCommon.h @@ -97,14 +97,6 @@ enum class SvgStyleType CompOp }; -enum class SvgGradientSpread -{ - Pad = 0, - Reflect, - Repeat, - Last -}; - enum class SvgFillRule { Winding = 0, @@ -221,7 +213,7 @@ struct SvgGradientStop struct SvgPaint { SvgStyleGradient* gradient; - string* url; + string *url; uint8_t r; uint8_t g; uint8_t b; @@ -238,13 +230,13 @@ struct SvgDash struct _SvgStyleGradient { SvgGradientType type; - string* id; - string* ref; - SvgGradientSpread spread; - vector stops; + string *id; + string *ref; + FillSpread spread; SvgRadialGradient* radial; SvgLinearGradient* linear; Matrix* transform; + vector stops; bool userSpace; bool usePercentage; }; @@ -286,8 +278,8 @@ struct _SvgNode SvgNodeType type; SvgNode* parent; vector child; - string* id; - SvgStyleProperty* style; + string *id; + SvgStyleProperty *style; Matrix* transform; union { SvgGNode g; @@ -309,7 +301,7 @@ struct SvgParser { SvgNode* node; SvgStyleGradient* styleGrad; - SvgGradientStop* gradStop; + Fill::ColorStop* gradStop; struct { int x, y; @@ -334,4 +326,4 @@ struct SvgLoaderData bool result = false; }; -#endif \ No newline at end of file +#endif diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 69e4a0a2..d7fcb82f 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -40,7 +40,188 @@ static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, fl } -unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) +unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh) +{ + Fill::ColorStop* stops; + int stopCount = 0; + float fillOpacity = 255.0f; + float gx, gy, gw, gh; + + auto fillGrad = LinearGradient::gen(); + + if (g->usePercentage) { + g->linear->x1 = g->linear->x1 * rw + rx; + g->linear->y1 = g->linear->y1 * rh + ry; + g->linear->x2 = g->linear->x2 * rw + rx; + g->linear->y2 = g->linear->y2 * rh + ry; + } + + //In case of objectBoundingBox it need proper scaling + if (!g->userSpace) { + float scaleX = 1.0, scaleReversedX = 1.0; + float scaleY = 1.0, scaleReversedY = 1.0; + + //Check the smallest size, find the scale value + if (rh > rw) { + scaleY = ((float)rw) / rh; + scaleReversedY = ((float)rh) / rw; + } else { + scaleX = ((float)rh) / rw; + scaleReversedX = ((float)rw) / rh; + } + + vg->bounds(&gx, &gy, &gw, &gh); + + float cy = ((float)gh) * 0.5 + gy; + float cy_scaled = (((float)gh) * 0.5) * scaleReversedY; + float cx = ((float)gw) * 0.5 + gx; + float cx_scaled = (((float)gw) * 0.5) * scaleReversedX; + + //= T(gx, gy) x S(scaleX, scaleY) x T(cx_scaled - cx, cy_scaled - cy) x (radial->x, radial->y) + g->linear->x1 = g->linear->x1 * scaleX + scaleX * (cx_scaled - cx) + gx; + g->linear->y1 = g->linear->y1 * scaleY + scaleY * (cy_scaled - cy) + gy; + g->linear->x2 = g->linear->x2 * scaleX + scaleX * (cx_scaled - cx) + gx; + g->linear->y2 = g->linear->y2 * scaleY + scaleY * (cy_scaled - cy) + gy; + } + + if (g->transform) { + float cy = ((float) rh) * 0.5 + ry; + float cx = ((float) rw) * 0.5 + rx; + + //Calc start point + //= T(x - cx, y - cy) x g->transform x T(cx, cy) + g->linear->x1 = cx * (g->transform->e11 + g->transform->e31 * (g->linear->x1 - cx)) + + cx * (g->transform->e12 + g->transform->e32 * (g->linear->x1 - cx)) + + cx * (g->transform->e13 + g->transform->e33 * (g->linear->x1 - cx)); + + g->linear->y1 = cy * (g->transform->e21 + g->transform->e31 * (g->linear->y1 - cy)) + + cy * (g->transform->e22 + g->transform->e32 * (g->linear->y1 - cy)) + + cy * (g->transform->e23 + g->transform->e33 * (g->linear->y1 - cy)); + + //Calc end point + g->linear->x2 = cx * (g->transform->e11 + g->transform->e31 * (g->linear->x2 - cx)) + + cx * (g->transform->e12 + g->transform->e32 * (g->linear->x2 - cx)) + + cx * (g->transform->e13 + g->transform->e33 * (g->linear->x2 - cx)); + + g->linear->y2 = cy * (g->transform->e21 + g->transform->e31 * (g->linear->y2 - cy)) + + cy * (g->transform->e22 + g->transform->e32 * (g->linear->y2 - cy)) + + cy * (g->transform->e23 + g->transform->e33 * (g->linear->y2 - cy)); + } + + fillGrad->linear(g->linear->x1, g->linear->y1, g->linear->x2, g->linear->y2); + fillGrad->spread(g->spread); + + //Update the stops + stopCount = g->stops.size(); + if (stopCount > 0) { + float opacity; + float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. + int i = 0; + stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); + for (vector::iterator itrStop = g->stops.begin(); itrStop != g->stops.end(); itrStop++) { + //Use premultiplied color + opacity = ((float)(*itrStop)->a / 255) * fopacity; + stops[i].r = ((*itrStop)->r * opacity); + stops[i].g = ((*itrStop)->g * opacity); + stops[i].b = ((*itrStop)->b * opacity); + stops[i].a = ((*itrStop)->a * fopacity); + stops[i].offset = (*itrStop)->offset; + i++; + } + fillGrad->colorStops(stops, stopCount); + free(stops); + } + return move(fillGrad); +} + + +unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh) +{ + Fill::ColorStop *stops; + int stopCount = 0; + float gx, gy, gw, gh; + int radius; + float fillOpacity = 255.0f; + + auto fillGrad = RadialGradient::gen(); + + radius = sqrt(pow(rw, 2) + pow(rh, 2)) / sqrt(2.0); + if (!g->userSpace) { + //That is according to Units in here + //https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html + int min = (rh > rw) ? rw : rh; + radius = sqrt(pow(min, 2) + pow(min, 2)) / sqrt(2.0); + } + + if (g->usePercentage) { + g->radial->cx = g->radial->cx * rw + rx; + g->radial->cy = g->radial->cy * rh + ry; + g->radial->r = g->radial->r * radius; + g->radial->fx = g->radial->fx * rw + rx; + g->radial->fy = g->radial->fy * rh + ry; + } + + //In case of objectBoundingBox it need proper scaling + if (!g->userSpace) { + float scaleX = 1.0, scaleReversedX = 1.0; + float scaleY = 1.0, scaleReversedY = 1.0; + + //Check the smallest size, find the scale value + if (rh > rw) { + scaleY = ((float)rw) / rh; + scaleReversedY = ((float)rh) / rw; + } else { + scaleX = ((float)rh) / rw; + scaleReversedX = ((float)rw) / rh; + } + + vg->bounds(&gx, &gy, &gw, &gh); + + float cy = ((float)gh) * 0.5 + gy; + float cy_scaled = (((float)gh) * 0.5) * scaleReversedY; + float cx = ((float)gw) * 0.5 + gx; + float cx_scaled = (((float)gw) * 0.5) * scaleReversedX; + + //= T(gx, gy) x S(scaleX, scaleY) x T(cx_scaled - cx, cy_scaled - cy) x (radial->x, radial->y) + g->radial->cx = g->radial->cx * scaleX + scaleX * (cx_scaled - cx) + gx; + g->radial->cy = g->radial->cy * scaleY + scaleY * (cy_scaled - cy) + gy; + } + + //TODO: Radial gradient transformation is not yet supported. + //if (g->transform) {} + + //TODO: Tvg is not support to focal + //if (g->radial->fx != 0 && g->radial->fy != 0) { + // fillGrad->radial(g->radial->fx, g->radial->fy, g->radial->r); + //} + fillGrad->radial(g->radial->cx, g->radial->cy, g->radial->r); + fillGrad->spread(g->spread); + + //Update the stops + stopCount = g->stops.size(); + if (stopCount > 0) { + float opacity; + float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. + int i = 0; + stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); + for (vector::iterator itrStop = g->stops.begin(); itrStop != g->stops.end(); itrStop++) { + //Use premultiplied color + opacity = ((float)(*itrStop)->a / 255) * fopacity; + stops[i].r = ((*itrStop)->r * opacity); + stops[i].g = ((*itrStop)->g * opacity); + stops[i].b = ((*itrStop)->b * opacity); + stops[i].a = ((*itrStop)->a * fopacity); + stops[i].offset = (*itrStop)->offset; + i++; + } + fillGrad->colorStops(stops, stopCount); + free(stops); + } + return move(fillGrad); +} + + +unique_ptr _applyProperty(SvgNode* node, unique_ptr vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -59,7 +240,15 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) if (style->fill.paint.none) { //Do nothing } else if (style->fill.paint.gradient) { - //TODO: Support gradient style + if (!style->fill.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh); + + if (style->fill.paint.gradient->type == SvgGradientType::Linear) { + auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg.get(), vx, vy, vw, vh); + vg->fill(move(linear)); + } else if (style->fill.paint.gradient->type == SvgGradientType::Radial) { + auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg.get(), vx, vy, vw, vh); + vg->fill(move(radial)); + } } else if (style->fill.paint.curColor) { //Apply the current style color float fa = ((float)style->fill.opacity / 255.0); @@ -113,9 +302,9 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) } -unique_ptr _shapeBuildHelper(SvgNode* node) +unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) { - auto shape = tvg::Shape::gen(); + auto shape = Shape::gen(); switch (node->type) { case SvgNodeType::Path: { if (node->node.path.path) { @@ -162,15 +351,15 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } } - shape = move(_applyProperty(node, move(shape))); + shape = move(_applyProperty(node, move(shape), vx, vy, vw, vh)); return shape; } -unique_ptr _sceneBuildHelper(SvgNode* node) +unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) { if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) { - auto scene = tvg::Scene::gen(); + auto scene = Scene::gen(); if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); @@ -180,8 +369,8 @@ unique_ptr _sceneBuildHelper(SvgNode* node) } 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)); + if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild, vx, vy, vw, vh)); + else scene->push(_shapeBuildHelper(*itrChild, vx, vy, vw, vh)); } return move(scene); } @@ -209,7 +398,7 @@ unique_ptr SvgSceneBuilder::build(SvgNode* node) viewBox.h = node->node.doc.vh; preserveAspect = node->node.doc.preserveAspect; staticViewBox = true; - return _sceneBuildHelper(node); + return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h); } diff --git a/test/svgs/lineargrad1.svg b/test/svgs/lineargrad1.svg new file mode 100644 index 00000000..343d161f --- /dev/null +++ b/test/svgs/lineargrad1.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/test/svgs/radialgrad1.svg b/test/svgs/radialgrad1.svg new file mode 100644 index 00000000..5cb6da8b --- /dev/null +++ b/test/svgs/radialgrad1.svg @@ -0,0 +1,19 @@ + + + + + + + + + From 84df3439dee7f37d7336e5ad52d17e91eeb4793b Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 9 Jul 2020 13:37:12 +0900 Subject: [PATCH 150/244] SvgLoader: Inherit parent opacity Change-Id: If52c6581845e9918dc13c4627080ba84d270a07b --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index d7fcb82f..4daf7d86 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -356,7 +356,7 @@ unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, } -unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) +unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh, int parentOpacity) { if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) { auto scene = Scene::gen(); @@ -367,9 +367,11 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) scene->rotate(fmod(z, 360.0)); if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) scene->translate(tx, ty); } + node->style->opacity = (node->style->opacity * parentOpacity) / 255; 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, vx, vy, vw, vh)); + child->style->opacity = (child->style->opacity * node->style->opacity) / 255; + if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild, vx, vy, vw, vh, node->style->opacity)); else scene->push(_shapeBuildHelper(*itrChild, vx, vy, vw, vh)); } return move(scene); @@ -398,7 +400,7 @@ unique_ptr SvgSceneBuilder::build(SvgNode* node) viewBox.h = node->node.doc.vh; preserveAspect = node->node.doc.preserveAspect; staticViewBox = true; - return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h); + return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h, 255); } From 581451ea8d593edecfd7d62a705d46110f11ac06 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 9 Jul 2020 15:40:21 +0900 Subject: [PATCH 151/244] SvgLoader: Fix typo (SCubic draw) Change-Id: Id54cf6a7ca66cdbc96cfb93143aacccab95de822 --- src/loaders/svg_loader/tvgSvgPath.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index ba01ae76..bd430272 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -328,9 +328,9 @@ static void _processCommand(vector* cmds, vector* pts, char case 's': case 'S': { Point p[3], ctrl; - if ((cmds->size() > 1) && (cmds->at(cmds->size() - 2) == PathCommand::CubicTo)) { + if ((cmds->size() > 1) && (cmds->at(cmds->size() - 1) == PathCommand::CubicTo)) { ctrl.x = 2 * cur->x - curCtl->x; - ctrl.y = 2 * cur->x - curCtl->y; + ctrl.y = 2 * cur->y - curCtl->y; } else { ctrl = *cur; } From e86d2ab686587280debc00080280ba87d82c1147 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 9 Jul 2020 16:36:30 +0900 Subject: [PATCH 152/244] SvgLoader/Parser: Fix typo Change-Id: Iced0f2196c52f7cc729d6f648f5df6affbda3357 --- 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 f4ed3be9..1ac2fd44 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -623,13 +623,13 @@ static Matrix* _parseTransformationMatrix(const char* value) 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 }; + tmp = { 1, 0, points[1], 0, 1, points[2], 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); tmp = { c, -s, 0, s, c, 0, 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); - tmp = { 1, 0, points[0], 0, 1, points[1], 0, 0, 1 }; + tmp = { 1, 0, -points[1], 0, 1, -points[2], 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); } else { goto error; From 9299c41a21379e7e7f447de6e67a84efd19d0d6e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 10 Jul 2020 09:31:12 +0900 Subject: [PATCH 153/244] svg_loader: code refactoring. simpler code is better for readibility. Change-Id: I4bc18bb184aea6fea0179bb38b445da5e0acba43 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 26 ++++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 7c0ff9dc..130a60cd 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -1367,16 +1367,11 @@ static SvgNode* _findChildById(SvgNode* node, const char* id) static void _cloneGradStops(vector *dst, vector src) { - for(vector::iterator itrStop = src.begin(); itrStop != src.end(); itrStop++) { - Fill::ColorStop *stop = (Fill::ColorStop *)malloc(sizeof(Fill::ColorStop)); - stop->r = (*itrStop)->r; - stop->g = (*itrStop)->g; - stop->b = (*itrStop)->b; - stop->a = (*itrStop)->a; - stop->offset = (*itrStop)->offset; + for (auto colorStop : src) { + auto stop = static_cast(malloc(sizeof(Fill::ColorStop))); + *stop = *colorStop; dst->push_back(stop); } - } @@ -1571,7 +1566,7 @@ FIND_FACTORY(Graphics, graphicsTags); FillSpread _parseSpreadValue(const char* value) { - FillSpread spread = FillSpread::Pad; + auto spread = FillSpread::Pad; if (!strcmp(value, "reflect")) { spread = FillSpread::Reflect; @@ -1737,7 +1732,7 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char static bool _attrParseStops(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; - Fill::ColorStop* stop = loader->svgParse->gradStop; + auto stop = loader->svgParse->gradStop; if (!strcmp(key, "offset")) { stop->offset = _toOffset(value); @@ -2015,7 +2010,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } loader->latestGradient = gradient; } else if (!strcmp(tagName, "stop")) { - Fill::ColorStop* stop = (Fill::ColorStop*)calloc(1, sizeof(Fill::ColorStop)); + auto stop = static_cast(calloc(1, sizeof(Fill::ColorStop))); loader->svgParse->gradStop = stop; /* default value for opacity */ stop->a = 255; @@ -2168,9 +2163,8 @@ static void _freeGradientStyle(SvgStyleGradient* grad) free(grad->linear); if (grad->transform) free(grad->transform); - for(vector::iterator itrStop = grad->stops.begin(); itrStop != grad->stops.end(); itrStop++) { - free(*itrStop); - } + for (auto colorStop : grad->stops) free(colorStop); + free(grad); } @@ -2291,8 +2285,8 @@ bool SvgLoader::read() else { if (!loader->loaderData.gradients.empty()) { vector gradientList; - for(vector::iterator itrGrad = loader->loaderData.gradients.begin(); itrGrad != loader->loaderData.gradients.end(); itrGrad++) { - gradientList.push_back(*itrGrad); + for (auto gradient : loader->loaderData.gradients) { + gradientList.push_back(gradient); } _updateGradient(loader->loaderData.doc, gradientList); gradientList.clear(); From 9e1ba8d2c0bd295513a18361e4c081d9802eba28 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 8 Jul 2020 16:05:58 +0900 Subject: [PATCH 154/244] sw_engine: introduce avx simd instruction avx is the cutting edge method for intel & amd cpus simd instruction. We are going to support this feature for the desktop environment (instead of sse) You can turn on this with configuration something like this: $meson . build -Dvectors=avx Current patch supports only for raster solid color Change-Id: I068ba30a1f63d480415e2762f8021fc8d6d28a39 --- meson.build | 4 ++++ meson_options.txt | 8 ++++++- src/lib/meson.build | 2 ++ src/lib/sw_engine/tvgSwCommon.h | 37 +++++++++++++++++++++++++------ src/lib/sw_engine/tvgSwFill.cpp | 6 +++-- src/lib/sw_engine/tvgSwRaster.cpp | 29 +++++++++++------------- src/loaders/meson.build | 1 + src/meson.build | 9 ++++++++ test/testPath.cpp | 2 +- 9 files changed, 71 insertions(+), 27 deletions(-) diff --git a/meson.build b/meson.build index c23bcb16..d1803a30 100644 --- a/meson.build +++ b/meson.build @@ -18,6 +18,10 @@ if get_option('loaders').contains('svg') == true config_h.set10('THORVG_SVG_LOADER_SUPPORT', true) endif +if get_option('vectors').contains('avx') == true + config_h.set10('THORVG_AVX_VECTOR_SUPPORT', true) +endif + configure_file( output: 'config.h', configuration: config_h diff --git a/meson_options.txt b/meson_options.txt index daf3923f..5a440fa0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,6 +6,12 @@ option('engines', option('loaders', type: 'array', - choices: ['svg'], + choices: ['', 'svg'], value: ['svg'], description: 'Enable Vector File Loader in thorvg') + +option('vectors', + type: 'array', + choices: ['', 'avx'], + value: [''], + description: 'Enable CPU Vectorization(SIMD) in thorvg') diff --git a/src/lib/meson.build b/src/lib/meson.build index 46d6a997..ad022618 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -2,10 +2,12 @@ engine_dep = [] if get_option('engines').contains('sw') == true subdir('sw_engine') + message('Enable SW Raster Engine') endif if get_option('engines').contains('gl') == true subdir('gl_engine') + message('Enable GL Raster Engine') endif source_file = [ diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 8d903423..5e474838 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -19,6 +19,10 @@ #include "tvgCommon.h" +#ifdef THORVG_AVX_VECTOR_SUPPORT + #include +#endif + #if 0 #include static double timeStamp() @@ -242,12 +246,6 @@ static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t } -static inline void COLOR_SET(uint32_t *dst, uint32_t val, uint32_t len) -{ - while (len--) *dst++ = val; -} - - int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -283,7 +281,7 @@ void strokeFree(SwStroke* stroke); bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); void fillReset(SwFill* fill); void fillFree(SwFill* fill); -void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias); @@ -294,4 +292,29 @@ bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterClear(Surface& surface); +inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +{ +#ifdef THORVG_AVX_VECTOR_SUPPORT + int32_t align = (8 - (offset % 8)) % 8; + //Vectorization + auto avxDst = (__m256i*)(dst + offset + align); + int32_t i = (len - align); + for (;i > 7; i -= 8, ++avxDst) { + *avxDst = _mm256_set1_epi32(val); + } + //Alignment + if (align > 0) { + if (align > len) align -= (align - len); + auto tmp = dst + offset; + for (; align > 0; --align, ++tmp) *tmp = val; + } + //Pack Leftovers + dst += offset + (len - i); + while (i-- > 0) *(dst++) = val; +#else + dst += offset; + while (len--) *dst++ = val; +#endif +} + #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 5992bcaa..1f72ee93 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -208,7 +208,7 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len) { if (fill->linear.len < FLT_EPSILON) return; @@ -220,10 +220,12 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); - COLOR_SET(dst, color, len); + rasterARGB32(dst, color, offset, len); return; } + dst += offset; + auto vMax = static_cast(INT32_MAX >> (FIXPT_BITS + 1)); auto vMin = -vMax; auto v = t + (inc * len); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 5a14822b..5819bb86 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -19,7 +19,6 @@ #include "tvgSwCommon.h" - /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ @@ -55,13 +54,12 @@ static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint3 static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t color) { - auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; - auto h = static_cast(region.max.y - region.min.y); + auto buffer = surface.buffer + (region.min.y * surface.stride); auto w = static_cast(region.max.x - region.min.x); + auto h = static_cast(region.max.y - region.min.y); for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface.stride]; - COLOR_SET(dst, color, w); + rasterARGB32(buffer + y * surface.stride, color, region.min.x, w); } return true; } @@ -95,10 +93,10 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) auto span = rle->spans; for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; if (span->coverage == 255) { - COLOR_SET(dst, color, span->len); + rasterARGB32(surface.buffer + span->y * surface.stride, color, span->x, span->len); } else { + auto dst = &surface.buffer[span->y * surface.stride + span->x]; auto src = COLOR_ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { @@ -127,7 +125,7 @@ static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, co for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface.stride]; - fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w); + fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w); for (uint32_t x = 0; x < w; ++x) { dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); } @@ -135,8 +133,7 @@ static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, co //Opaque Gradient } else { for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface.stride]; - fillFetchLinear(fill, dst, region.min.y + y, region.min.x, w); + fillFetchLinear(fill, buffer + y * surface.stride, region.min.y + y, region.min.x, 0, w); } } return true; @@ -188,7 +185,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF if (fill->translucent) { for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * surface.stride + span->x]; - fillFetchLinear(fill, buf, span->y, span->x, span->len); + fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); @@ -204,11 +201,11 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF //Opaque Gradient } else { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; if (span->coverage == 255) { - fillFetchLinear(fill, dst, span->y, span->x, span->len); + fillFetchLinear(fill, surface.buffer + span->y * surface.stride, span->y, span->x, span->x, span->len); } else { - fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto dst = &surface.buffer[span->y * surface.stride + span->x]; + fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); @@ -313,10 +310,10 @@ bool rasterClear(Surface& surface) if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; if (surface.w == surface.stride) { - COLOR_SET(surface.buffer, 0xff000000, surface.w * surface.h); + rasterARGB32(surface.buffer, 0x00000000, 0, surface.w * surface.h); } else { for (uint32_t i = 0; i < surface.h; i++) { - COLOR_SET(surface.buffer + surface.stride * i, 0xff000000, surface.w); + rasterARGB32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); } } return true; diff --git a/src/loaders/meson.build b/src/loaders/meson.build index aaf1324f..873cfa7f 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -2,6 +2,7 @@ subloader_dep = [] if get_option('loaders').contains('svg') == true subdir('svg_loader') + message('Enable SVG Loader') endif loader_dep = declare_dependency( diff --git a/src/meson.build b/src/meson.build index 23c4ad54..68738701 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,14 @@ compiler_flags = ['-DTVG_BUILD'] +cc = meson.get_compiler('cpp') +if (cc.get_id() != 'msvc') + if get_option('vectors').contains('avx') + compiler_flags += ['-mavx'] + message('Enable Advanced Vector Extension') + endif +endif + + subdir('lib') subdir('loaders') subdir('examples') diff --git a/test/testPath.cpp b/test/testPath.cpp index a6656a87..bcd5ab78 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -151,4 +151,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} From 9876d685cfbaefc1ba1e3b2f565f655b62326d93 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 13 Jul 2020 20:19:23 +0900 Subject: [PATCH 155/244] capi: support c interfaces this capi is under the beta, we quickly provide this working prototype for collaboration. Change-Id: Ie246abc306feb9a1305d1b593c4f3ef7f40ab5a9 --- .gitignore | 1 + inc/meson.build | 10 +- inc/thorvg_capi.h | 111 ++++++++++++++++++ meson.build | 4 + meson_options.txt | 6 + src/bindings/capi/meson.build | 8 ++ src/bindings/capi/tvgCapi.cpp | 214 ++++++++++++++++++++++++++++++++++ src/bindings/meson.build | 11 ++ src/meson.build | 3 +- test/makefile | 1 + test/testCapi.c | 73 ++++++++++++ 11 files changed, 438 insertions(+), 4 deletions(-) create mode 100644 inc/thorvg_capi.h create mode 100644 src/bindings/capi/meson.build create mode 100644 src/bindings/capi/tvgCapi.cpp create mode 100644 src/bindings/meson.build create mode 100644 test/testCapi.c diff --git a/.gitignore b/.gitignore index 9a645208..b796b5e9 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ testRadialGradient testGradientTransform testSvg testAsync +testCapi diff --git a/inc/meson.build b/inc/meson.build index c598ee5d..90e3fc4c 100644 --- a/inc/meson.build +++ b/inc/meson.build @@ -1,3 +1,7 @@ -install_headers([ - 'thorvg.h', - ]) +header_files = ['thorvg.h'] + +if get_option('bindings').contains('capi') == true + header_files += ['thorvg_capi.h'] +endif + +install_headers(header_files) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h new file mode 100644 index 00000000..d2f7f859 --- /dev/null +++ b/inc/thorvg_capi.h @@ -0,0 +1,111 @@ +#ifndef __THORVG_CAPI_H__ +#define __THORVG_CAPI_H__ + +#ifdef TVG_EXPORT + #undef TVG_EXPORT +#endif + +#ifdef TVG_BUILD + #define TVG_EXPORT __attribute__ ((visibility ("default"))) +#else + #define TVG_EXPORT +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _Tvg_Canvas Tvg_Canvas; +typedef struct _Tvg_Paint Tvg_Paint; + +#define TVG_ENGINE_SW (1 << 1) +#define TVG_ENGINE_GL (1 << 2) + +typedef enum { + TVG_RESULT_SUCCESS = 0, + TVG_RESULT_INVALID_ARGUMENT, + TVG_RESULT_INSUFFICIENT_CONDITION, + TVG_RESULT_FAILED_ALLOCATION, + TVG_RESULT_MEMORY_CORRUPTION, + TVG_RESULT_NOT_SUPPORTED, + TVG_RESULT_UNKNOWN +} Tvg_Result; + +typedef enum { + TVG_PATH_COMMAND_CLOSE = 0, + TVG_PATH_COMMAND_MOVE_TO, + TVG_PATH_COMMAND_LINE_TO, + TVG_PATH_COMMAND_CUBIC_TO +} Tvg_Path_Command; + +typedef enum { + TVG_STROKE_CAP_SQUARE = 0, + TVG_STROKE_CAP_ROUND, + TVG_STROKE_CAP_BUTT +} Tvg_Stroke_Cap; + +typedef enum { + TVG_STROKE_JOIN_BEVEL = 0, + TVG_STROKE_JOIN_ROUND, + TVG_STROKE_JOIN_MITER +} Tvg_Stroke_Join; + +typedef enum { + TVG_STROKE_FILL_PAD = 0, + TVG_STROKE_FILL_REFLECT, + TVG_STROKE_FILL_REPEAT +} Tvg_Stroke_Fill; + + +typedef struct +{ + float x, y; +} Tvg_Point; + +typedef struct +{ + float e11, e12, e13; + float e21, e22, e23; + float e31, e32, e33; +} Tvg_Matrix; + + + +TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method); +TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method); + +TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create(); +TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); + +TVG_EXPORT Tvg_Result tvg_canvas_destroy(Tvg_Canvas* canvas); +TVG_EXPORT Tvg_Result tvg_canvas_push(Tvg_Canvas* canvas, Tvg_Paint* paint); +TVG_EXPORT Tvg_Result tvg_canvas_reserve(Tvg_Canvas* canvas, uint32_t n); +TVG_EXPORT Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas); +TVG_EXPORT Tvg_Result tvg_canvas_update(Tvg_Canvas* canvas); +TVG_EXPORT Tvg_Result tvg_canvas_update_paint(Tvg_Canvas* canvas, Tvg_Paint* paint); +TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas, unsigned char async); +TVG_EXPORT Tvg_Result tvg_canvas_sync(Tvg_Canvas* canvas); + +TVG_EXPORT Tvg_Paint* tvg_shape_new(); +TVG_EXPORT Tvg_Result tvg_shape_del(Tvg_Paint* paint); +TVG_EXPORT Tvg_Result tvg_shape_reset(Tvg_Paint* paint); +TVG_EXPORT Tvg_Result tvg_shape_move_to(Tvg_Paint* paint, float x, float y); +TVG_EXPORT Tvg_Result tvg_shape_line_to(Tvg_Paint* paint, float x, float y); +TVG_EXPORT Tvg_Result tvg_shape_cubic_to(Tvg_Paint* paint, float cx1, float cy1, float cx2, float cy2, float x, float y); +TVG_EXPORT Tvg_Result tvg_shape_close(Tvg_Paint* paint); +TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, float w, float h, float rx, float ry); +TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry); +TVG_EXPORT Tvg_Result tvg_shape_append_path(Tvg_Paint* paint, const Tvg_Path_Command* cmds, uint32_t cmdCnt, const Tvg_Point* pts, uint32_t ptsCnt); +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_width(Tvg_Paint* paint, float width); +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* dashPattern, uint32_t cnt); +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap cap); +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join); +TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); + +#ifdef __cplusplus +} +#endif + +#endif //_THORVG_CAPI_H_ diff --git a/meson.build b/meson.build index d1803a30..6da6d269 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,10 @@ if get_option('vectors').contains('avx') == true config_h.set10('THORVG_AVX_VECTOR_SUPPORT', true) endif +if get_option('bindings').contains('capi') == true + config_h.set10('THORVG_CAPI_BINDING_SUPPORT', true) +endif + configure_file( output: 'config.h', configuration: config_h diff --git a/meson_options.txt b/meson_options.txt index 5a440fa0..59d0130d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -15,3 +15,9 @@ option('vectors', choices: ['', 'avx'], value: [''], description: 'Enable CPU Vectorization(SIMD) in thorvg') + +option('bindings', + type: 'array', + choices: ['', 'capi'], + value: ['capi'], + description: 'Enable C API binding') diff --git a/src/bindings/capi/meson.build b/src/bindings/capi/meson.build new file mode 100644 index 00000000..919442ae --- /dev/null +++ b/src/bindings/capi/meson.build @@ -0,0 +1,8 @@ +source_file = [ + 'tvgCapi.cpp', +] + +subbinding_dep += [declare_dependency( + include_directories : include_directories('.'), + sources : source_file +)] diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp new file mode 100644 index 00000000..37e01af8 --- /dev/null +++ b/src/bindings/capi/tvgCapi.cpp @@ -0,0 +1,214 @@ +#include +#include "thorvg_capi.h" + +using namespace std; +using namespace tvg; + +#ifdef __cplusplus +extern "C" { +#endif + +struct _Tvg_Canvas +{ + //Dummy for Direct Casting +}; + +struct _Tvg_Paint +{ + //Dummy for Direct Casting +}; + + +/************************************************************************/ +/* Engine API */ +/************************************************************************/ + +TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method) { + Result ret = Result::Success; + + if (engine_method & TVG_ENGINE_SW) ret = tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (ret != Result::Success) return (Tvg_Result) ret; + + if (engine_method & TVG_ENGINE_GL) ret = tvg::Initializer::init(tvg::CanvasEngine::Gl); + return (Tvg_Result) ret; +} + + +TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method) { + Result ret = Result::Success; + + if (engine_method & TVG_ENGINE_SW) ret = tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (ret != Result::Success) return (Tvg_Result) ret; + + if (engine_method & TVG_ENGINE_GL) ret = tvg::Initializer::init(tvg::CanvasEngine::Gl); + return (Tvg_Result) ret; +} + +/************************************************************************/ +/* Canvas API */ +/************************************************************************/ + +TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create() +{ + return (Tvg_Canvas*) SwCanvas::gen().release(); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_destroy(Tvg_Canvas* canvas) +{ + delete(canvas); + return TVG_RESULT_SUCCESS; +} + + +TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +{ + return (Tvg_Result) reinterpret_cast(canvas)->target(buffer, stride, w, h); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_push(Tvg_Canvas* canvas, Tvg_Paint* paint) +{ + return (Tvg_Result) reinterpret_cast(canvas)->push(unique_ptr((Paint*)paint)); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_reserve(Tvg_Canvas* canvas, uint32_t n) +{ + return (Tvg_Result) reinterpret_cast(canvas)->reserve(n); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas) +{ + return (Tvg_Result) reinterpret_cast(canvas)->clear(); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_update(Tvg_Canvas* canvas) +{ + return (Tvg_Result) reinterpret_cast(canvas)->update(); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_update_paint(Tvg_Canvas* canvas, Tvg_Paint* paint) +{ + return (Tvg_Result) reinterpret_cast(canvas)->update((Paint*) paint); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas, unsigned char async) +{ + return (Tvg_Result) reinterpret_cast(canvas)->draw(async); +} + + +TVG_EXPORT Tvg_Result tvg_canvas_sync(Tvg_Canvas* canvas) +{ + return (Tvg_Result) reinterpret_cast(canvas)->sync(); +} + + +/************************************************************************/ +/* Shape API */ +/************************************************************************/ + +TVG_EXPORT Tvg_Paint* tvg_shape_new() +{ + return (Tvg_Paint*) Shape::gen().release(); +} + + +TVG_EXPORT Tvg_Result tvg_shape_del(Tvg_Paint* paint) +{ + delete(paint); + return TVG_RESULT_SUCCESS; +} + + +TVG_EXPORT Tvg_Result tvg_shape_reset(Tvg_Paint* paint) +{ + return (Tvg_Result) reinterpret_cast(paint)->reset(); +} + + +TVG_EXPORT Tvg_Result tvg_shape_move_to(Tvg_Paint* paint, float x, float y) +{ + return (Tvg_Result) reinterpret_cast(paint)->moveTo(x, y); +} + + +TVG_EXPORT Tvg_Result tvg_shape_line_to(Tvg_Paint* paint, float x, float y) +{ + return (Tvg_Result) reinterpret_cast(paint)->lineTo(x, y); +} + + +TVG_EXPORT Tvg_Result tvg_shape_cubic_to(Tvg_Paint* paint, float cx1, float cy1, float cx2, float cy2, float x, float y) +{ + return (Tvg_Result) reinterpret_cast(paint)->cubicTo(cx1, cy1, cx2, cy2, x, y); +} + + +TVG_EXPORT Tvg_Result tvg_shape_close(Tvg_Paint* paint) +{ + return (Tvg_Result) reinterpret_cast(paint)->close(); +} + + +TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, float w, float h, float rx, float ry) +{ + return (Tvg_Result) reinterpret_cast(paint)->appendRect(x, y, w, h, rx, ry); +} + + +TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry) +{ + return (Tvg_Result) reinterpret_cast(paint)->appendCircle(cx, cy, rx, ry); +} + + +TVG_EXPORT Tvg_Result tvg_shape_append_path(Tvg_Paint* paint, const Tvg_Path_Command* cmds, uint32_t cmdCnt, const Tvg_Point* pts, uint32_t ptsCnt) +{ + return (Tvg_Result) reinterpret_cast(paint)->appendPath((PathCommand*)cmds, cmdCnt, (Point*)pts, ptsCnt); +} + + +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_width(Tvg_Paint* paint, float width) +{ + return (Tvg_Result) reinterpret_cast(paint)->stroke(width); +} + + +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (Tvg_Result) reinterpret_cast(paint)->stroke(r, g, b, a); +} + + +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* dashPattern, uint32_t cnt) +{ + return (Tvg_Result) reinterpret_cast(paint)->stroke(dashPattern, cnt); +} + + +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap cap) +{ + return (Tvg_Result) reinterpret_cast(paint)->stroke((StrokeCap)cap); +} + + +TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join) +{ + return (Tvg_Result) reinterpret_cast(paint)->stroke((StrokeJoin)join); +} + + +TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (Tvg_Result) reinterpret_cast(paint)->fill(r, g, b, a); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/bindings/meson.build b/src/bindings/meson.build new file mode 100644 index 00000000..2b3a1506 --- /dev/null +++ b/src/bindings/meson.build @@ -0,0 +1,11 @@ +subbinding_dep = [] + +if get_option('bindings').contains('capi') == true + subdir('capi') + message('Enable CAPI Bindings') +endif + +binding_dep = declare_dependency( + dependencies: subbinding_dep, + include_directories : include_directories('.'), +) diff --git a/src/meson.build b/src/meson.build index 68738701..ced59a59 100644 --- a/src/meson.build +++ b/src/meson.build @@ -11,10 +11,11 @@ endif subdir('lib') subdir('loaders') +subdir('bindings') subdir('examples') thread_dep = meson.get_compiler('cpp').find_library('pthread') -thorvg_lib_dep = [common_dep, loader_dep, thread_dep] +thorvg_lib_dep = [common_dep, loader_dep, binding_dep, thread_dep] thorvg_lib = library( 'thorvg', diff --git a/test/makefile b/test/makefile index 6455a0a2..ef9e28a6 100644 --- a/test/makefile +++ b/test/makefile @@ -18,3 +18,4 @@ all: 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 testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testCapi testCapi.c -g 'pkg-config --cflags --libs elementary thorvg` diff --git a/test/testCapi.c b/test/testCapi.c new file mode 100644 index 00000000..5b8b91bc --- /dev/null +++ b/test/testCapi.c @@ -0,0 +1,73 @@ +#include +#include + +#define WIDTH 800 +#define HEIGHT 800 + + +/************************************************************************/ +/* Capi Test Code */ +/************************************************************************/ + +static uint32_t buffer[WIDTH * HEIGHT]; + +void testCapi() +{ + tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL); + + Tvg_Canvas* canvas = tvg_swcanvas_create(); + tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT); + + Tvg_Paint* shape = tvg_shape_new(); + tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0); + tvg_shape_append_rect(shape, 100, 100, 300, 300, 100, 100); + tvg_shape_append_circle(shape, 400, 400, 100, 100); + tvg_shape_append_circle(shape, 400, 500, 170, 100); + tvg_shape_fill_color(shape, 255, 255, 0, 255); + tvg_canvas_push(canvas, shape); + + tvg_canvas_draw(canvas, 1); + tvg_canvas_sync(canvas); + + tvg_canvas_destroy(canvas); + + tvg_engine_term(TVG_ENGINE_SW | TVG_ENGINE_GL); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + +void win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + 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); + + 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_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); + + testCapi(); + + elm_run(); + elm_shutdown(); + + return 0; +} From 2501c50506da04fccf7dda3949b8313dc164c723 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 15 Jul 2020 16:18:55 +0900 Subject: [PATCH 156/244] capi: improve code template. Change-Id: Ia48a21fbd93103b371b41a13adf46d82b76803b1 --- inc/thorvg_capi.h | 39 ++++++++++++++++++++++++++++++++++- src/bindings/capi/tvgCapi.cpp | 17 +++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index d2f7f859..7c921841 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -1,3 +1,20 @@ +/* + * 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 __THORVG_CAPI_H__ #define __THORVG_CAPI_H__ @@ -22,6 +39,7 @@ typedef struct _Tvg_Paint Tvg_Paint; #define TVG_ENGINE_SW (1 << 1) #define TVG_ENGINE_GL (1 << 2) + typedef enum { TVG_RESULT_SUCCESS = 0, TVG_RESULT_INVALID_ARGUMENT, @@ -32,6 +50,7 @@ typedef enum { TVG_RESULT_UNKNOWN } Tvg_Result; + typedef enum { TVG_PATH_COMMAND_CLOSE = 0, TVG_PATH_COMMAND_MOVE_TO, @@ -39,18 +58,21 @@ typedef enum { TVG_PATH_COMMAND_CUBIC_TO } Tvg_Path_Command; + typedef enum { TVG_STROKE_CAP_SQUARE = 0, TVG_STROKE_CAP_ROUND, TVG_STROKE_CAP_BUTT } Tvg_Stroke_Cap; + typedef enum { TVG_STROKE_JOIN_BEVEL = 0, TVG_STROKE_JOIN_ROUND, TVG_STROKE_JOIN_MITER } Tvg_Stroke_Join; + typedef enum { TVG_STROKE_FILL_PAD = 0, TVG_STROKE_FILL_REFLECT, @@ -63,6 +85,7 @@ typedef struct float x, y; } Tvg_Point; + typedef struct { float e11, e12, e13; @@ -71,13 +94,23 @@ typedef struct } Tvg_Matrix; - +/************************************************************************/ +/* Engine API */ +/************************************************************************/ TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method); TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method); + +/************************************************************************/ +/* SwCanvas API */ +/************************************************************************/ TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create(); TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); + +/************************************************************************/ +/* Common Canvas API */ +/************************************************************************/ TVG_EXPORT Tvg_Result tvg_canvas_destroy(Tvg_Canvas* canvas); TVG_EXPORT Tvg_Result tvg_canvas_push(Tvg_Canvas* canvas, Tvg_Paint* paint); TVG_EXPORT Tvg_Result tvg_canvas_reserve(Tvg_Canvas* canvas, uint32_t n); @@ -87,6 +120,10 @@ TVG_EXPORT Tvg_Result tvg_canvas_update_paint(Tvg_Canvas* canvas, Tvg_Paint* pai TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas, unsigned char async); TVG_EXPORT Tvg_Result tvg_canvas_sync(Tvg_Canvas* canvas); + +/************************************************************************/ +/* Shape API */ +/************************************************************************/ TVG_EXPORT Tvg_Paint* tvg_shape_new(); TVG_EXPORT Tvg_Result tvg_shape_del(Tvg_Paint* paint); TVG_EXPORT Tvg_Result tvg_shape_reset(Tvg_Paint* paint); diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 37e01af8..6ba0e6da 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -1,3 +1,20 @@ +/* + * 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. + * + */ + #include #include "thorvg_capi.h" From 1b48bf10fe01e2026296c3eef6fe82e471889e56 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 9 Jul 2020 20:12:48 +0900 Subject: [PATCH 157/244] SvgLoader: Verify SVG resource Only tag is parsed first before data get in file open function. If the tag is found, the loaded file is valid and stores viewbox information. After that, the remaining content data is parsed in order with async. Change-Id: Idb934fbd5e190c7c523abe601a80745ccc767af1 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 87 ++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 9 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 130a60cd..9d58792b 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -1982,6 +1982,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, node = method(loader, nullptr, attrs, attrsLength); loader->doc = node; } else { + if (!strcmp(tagName, "svg")) return; //Already loadded (SvgNodeType::Doc) tag if (loader->stack.size() > 0) parent = loader->stack.at(loader->stack.size() - 1); node = method(loader, parent, attrs, attrsLength); } @@ -2223,6 +2224,64 @@ static void _freeSvgNode(SvgNode* node) } +static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const char* content, unsigned int length) +{ + const char* attrs = nullptr; + int sz = length; + char tagName[20] = ""; + FactoryMethod method; + SvgNode *node = nullptr; + int attrsLength = 0; + loader->level++; + attrs = simpleXmlFindAttributesTag(content, length); + + if (!attrs) { + //Parse the empty tag + attrs = content; + while ((attrs != nullptr) && *attrs != '>') attrs++; + } + + if (attrs) { + 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))) { + if (!loader->doc) { + if (strcmp(tagName, "svg")) return true; //Not a valid svg document + node = method(loader, nullptr, attrs, attrsLength); + loader->doc = node; + loader->stack.push_back(node); + return false; + } + } + return true; +} + + +static bool _svgLoaderParserForValidCheck(void* data, SimpleXMLType type, const char* content, unsigned int offset, unsigned int length) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + bool res = true;; + + switch (type) { + case SimpleXMLType::Open: + case SimpleXMLType::OpenEmpty: { + //If 'res' is false, it means tag is found. + res = _svgLoaderParserForValidCheckXmlOpen(loader, content, length); + break; + } + default: { + break; + } + } + + return res; +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -2254,12 +2313,25 @@ bool SvgLoader::open(const char* path) if (content.empty()) return false; } - //FIXME: Verify this resource is normal SVG, otherwise return false - //Also, return the brief resource info such as viewbox: - //this->vx = ? - //this->vy = ? - //this->vw = ? - //this->vh = ? + //For valid check, only tag is parsed first. + //If the tag is found, the loaded file is valid and stores viewbox information. + //After that, the remaining content data is parsed in order with async. + loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); + if (!loaderData.svgParse) return false; + + simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParserForValidCheck, &(loaderData)); + + if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) { + //Return the brief resource info such as viewbox: + this->vx = loaderData.doc->node.doc.vx; + this->vy = loaderData.doc->node.doc.vy; + this->vw = loaderData.doc->node.doc.vw; + this->vh = loaderData.doc->node.doc.vh; + + } else { + cout << "ERROR : No SVG File. There is no " <loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); - bool res = simpleXmlParse(loader->content.c_str(), loader->content.size(), true, _svgLoaderParser, &(loader->loaderData)); if (!res) return unique_ptr(nullptr); From a6344daa66ef53a74d1a72876aaead934e629c3a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 16 Jul 2020 13:45:27 +0900 Subject: [PATCH 158/244] sw_engine: fix wrong gradient fill transform. it missed the offset when transformed gradient positions. now it's fixed. Change-Id: I916bd88b40bc29ca57d31411b92e10fe357d720e --- src/lib/sw_engine/tvgSwFill.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 1f72ee93..fd857f9c 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -100,12 +100,12 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; - y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e31 + cx; + y1 = dx * transform->e21 + dy * transform->e22 + transform->e32 + cy; dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; - y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e31 + cx; + y2 = dx * transform->e21 + dy * transform->e22 + transform->e32 + cy; } fill->linear.dx = x2 - x1; From e3218a8a9aeac1123a9fcfcefe9df1083ec1fa28 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 16 Jul 2020 14:58:35 +0900 Subject: [PATCH 159/244] test: Fix typo in makefile ' -> ` Change-Id: Iafacfb78d8f788ef302e5ad7f1a1d9cfbd380ffb --- test/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/makefile b/test/makefile index ef9e28a6..e1a8afb0 100644 --- a/test/makefile +++ b/test/makefile @@ -18,4 +18,4 @@ all: 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 testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` - gcc -o testCapi testCapi.c -g 'pkg-config --cflags --libs elementary thorvg` + gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg` From 33b067eb0ad75366d5869d77162be975739b6425 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 16 Jul 2020 17:03:44 +0900 Subject: [PATCH 160/244] svg_loader: optimize data delivery. We know how this shape is passed, so don't use unique_ptr to save data size. Change-Id: I02410692199b9cee701c206246ceea5988d06726 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 4daf7d86..1e6ea328 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -221,7 +221,7 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Sha } -unique_ptr _applyProperty(SvgNode* node, unique_ptr vg, float vx, float vy, float vw, float vh) +void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -234,7 +234,7 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg, float vx, if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) vg->translate(tx, ty); } - if (node->type == SvgNodeType::Doc) return vg; + if (node->type == SvgNodeType::Doc) return; //If fill property is nullptr then do nothing if (style->fill.paint.none) { @@ -243,10 +243,10 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg, float vx, if (!style->fill.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh); if (style->fill.paint.gradient->type == SvgGradientType::Linear) { - auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg.get(), vx, vy, vw, vh); + auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, vx, vy, vw, vh); vg->fill(move(linear)); } else if (style->fill.paint.gradient->type == SvgGradientType::Radial) { - auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg.get(), vx, vy, vw, vh); + auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg, vx, vy, vw, vh); vg->fill(move(radial)); } } else if (style->fill.paint.curColor) { @@ -267,7 +267,7 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg, float vx, vg->fill(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa); } - if (node->type == SvgNodeType::G) return vg; + if (node->type == SvgNodeType::G) return; //Apply the stroke style property vg->stroke(style->stroke.width); @@ -298,7 +298,6 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg, float vx, float fa = ((float)style->opacity / 255.0); vg->stroke(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa); } - return vg; } @@ -351,7 +350,7 @@ unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, break; } } - shape = move(_applyProperty(node, move(shape), vx, vy, vw, vh)); + _applyProperty(node, shape.get(), vx, vy, vw, vh); return shape; } From 231b3779b1bd75bed86ab88c000bb45928913d23 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 16 Jul 2020 17:09:48 +0900 Subject: [PATCH 161/244] svg_loader: code refactoring keep clean & neat code. Change-Id: Ia17139a291fc9934fe2f8d5e51417c44ec50f2ed --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 1e6ea328..64d34b96 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -118,14 +118,14 @@ unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Sha float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. int i = 0; stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); - for (vector::iterator itrStop = g->stops.begin(); itrStop != g->stops.end(); itrStop++) { + for (auto colorStop : g->stops) { //Use premultiplied color - opacity = ((float)(*itrStop)->a / 255) * fopacity; - stops[i].r = ((*itrStop)->r * opacity); - stops[i].g = ((*itrStop)->g * opacity); - stops[i].b = ((*itrStop)->b * opacity); - stops[i].a = ((*itrStop)->a * fopacity); - stops[i].offset = (*itrStop)->offset; + opacity = ((float)colorStop->a / 255.0f) * fopacity; + stops[i].r = colorStop->r * opacity; + stops[i].g = colorStop->g * opacity; + stops[i].b = colorStop->b * opacity; + stops[i].a = colorStop->a * fopacity; + stops[i].offset = colorStop->offset; i++; } fillGrad->colorStops(stops, stopCount); @@ -204,14 +204,14 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Sha float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. int i = 0; stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); - for (vector::iterator itrStop = g->stops.begin(); itrStop != g->stops.end(); itrStop++) { + for (auto colorStop : g->stops) { //Use premultiplied color - opacity = ((float)(*itrStop)->a / 255) * fopacity; - stops[i].r = ((*itrStop)->r * opacity); - stops[i].g = ((*itrStop)->g * opacity); - stops[i].b = ((*itrStop)->b * opacity); - stops[i].a = ((*itrStop)->a * fopacity); - stops[i].offset = (*itrStop)->offset; + opacity = ((float)colorStop->a / 255.0f) * fopacity; + stops[i].r = colorStop->r * opacity; + stops[i].g = colorStop->g * opacity; + stops[i].b = colorStop->b * opacity; + stops[i].a = colorStop->a * fopacity; + stops[i].offset = colorStop->offset; i++; } fillGrad->colorStops(stops, stopCount); @@ -366,12 +366,11 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) scene->rotate(fmod(z, 360.0)); if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) scene->translate(tx, ty); } - node->style->opacity = (node->style->opacity * parentOpacity) / 255; - for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { - SvgNode* child = *itrChild; - child->style->opacity = (child->style->opacity * node->style->opacity) / 255; - if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild, vx, vy, vw, vh, node->style->opacity)); - else scene->push(_shapeBuildHelper(*itrChild, vx, vy, vw, vh)); + node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; + for (auto child : node->child) { + child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; + if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); + else scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); } return move(scene); } From ca6417ec8d848b67d75a3242c4a00501284ef6a3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 16 Jul 2020 17:17:16 +0900 Subject: [PATCH 162/244] svg_loader: code refactoring. leave to shape to handle non-effective values. Change-Id: I4193653710498e0ea31b0ff88fd8f0f8f0238e0e --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 64d34b96..c6513681 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -229,9 +229,9 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); - if (!(fabsf(s - 1) <= FLT_EPSILON)) vg->scale(s); - if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) vg->rotate(fmod(z, 360.0)); - if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) vg->translate(tx, ty); + vg->scale(s); + vg->rotate(z); + vg->translate(tx, ty); } if (node->type == SvgNodeType::Doc) return; @@ -362,9 +362,9 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); - if (!(fabsf(s - 1) <= FLT_EPSILON)) scene->scale(s); - if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) scene->rotate(fmod(z, 360.0)); - if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) scene->translate(tx, ty); + scene->scale(s); + scene->rotate(z); + scene->translate(tx, ty); } node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; for (auto child : node->child) { From 3b385d1d5496d27217582c11a34c659e5ac601de Mon Sep 17 00:00:00 2001 From: Pranay Kumar Samanta Date: Wed, 15 Jul 2020 19:02:27 +0530 Subject: [PATCH 163/244] gl_engine: Fix crash in animation callback. Refactor test samples draw function. Fix open shape drawing. Change-Id: I9ca2cb3951f2229f36292b69221451e0eaf5b6a1 --- src/lib/gl_engine/tvgGlGeometry.cpp | 8 ++++---- src/lib/gl_engine/tvgGlRenderer.cpp | 5 +++-- test/testAsync.cpp | 6 ------ test/testBlending.cpp | 6 ------ test/testBoundary.cpp | 6 ------ test/testCustomTransform.cpp | 6 ------ test/testDirectUpdate.cpp | 6 ------ test/testGradientTransform.cpp | 6 ------ test/testLinearGradient.cpp | 6 ------ test/testMultiShapes.cpp | 6 ------ test/testPath.cpp | 6 ------ test/testPathCopy.cpp | 6 ------ test/testRadialGradient.cpp | 6 ------ test/testScene.cpp | 6 ------ test/testSceneTransform.cpp | 6 ------ test/testShape.cpp | 6 ------ test/testStroke.cpp | 6 ------ test/testStrokeLine.cpp | 6 ------ test/testSvg.cpp | 6 ------ test/testTransform.cpp | 6 ------ test/testUpdate.cpp | 6 ------ 21 files changed, 7 insertions(+), 120 deletions(-) mode change 100644 => 100755 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlRenderer.cpp mode change 100644 => 100755 test/testAsync.cpp mode change 100644 => 100755 test/testBlending.cpp mode change 100644 => 100755 test/testBoundary.cpp mode change 100644 => 100755 test/testCustomTransform.cpp mode change 100644 => 100755 test/testDirectUpdate.cpp mode change 100644 => 100755 test/testGradientTransform.cpp mode change 100644 => 100755 test/testLinearGradient.cpp mode change 100644 => 100755 test/testMultiShapes.cpp mode change 100644 => 100755 test/testPath.cpp mode change 100644 => 100755 test/testPathCopy.cpp mode change 100644 => 100755 test/testRadialGradient.cpp mode change 100644 => 100755 test/testScene.cpp mode change 100644 => 100755 test/testSceneTransform.cpp mode change 100644 => 100755 test/testShape.cpp mode change 100644 => 100755 test/testStroke.cpp mode change 100644 => 100755 test/testStrokeLine.cpp mode change 100644 => 100755 test/testSvg.cpp mode change 100644 => 100755 test/testTransform.cpp mode change 100644 => 100755 test/testUpdate.cpp diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp old mode 100644 new mode 100755 index 59b730bd..eba6fbff --- a/src/lib/gl_engine/tvgGlGeometry.cpp +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -84,11 +84,11 @@ bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpda size_t fPoint = 0; size_t sPoint = 1; - for (size_t i = 0; i < nPoints - 1; ++i) + for (size_t i = 0; i < nPoints; ++i) { fPoint = i; sPoint = i + 1; - if (sPoint == nPoints - 1) + if (fPoint == nPoints - 1) sPoint = 0; GlPoint normal = getNormal(aaPts[fPoint].orgPt, aaPts[sPoint].orgPt); @@ -96,8 +96,8 @@ bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpda normalInfo[fPoint].normal1 = normal; normalInfo[sPoint].normal2 = normal; } - normalInfo[nPoints - 1].normal1 = normalInfo[0].normal1; - normalInfo[nPoints - 1].normal2 = normalInfo[0].normal2; + normalInfo[0].normal2 = normalInfo[0].normal1; + normalInfo[nPoints - 1].normal1 = normalInfo[nPoints - 1].normal2; for (uint32_t i = 0; i < nPoints; ++i) { diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100644 new mode 100755 index bef3871b..d9acf619 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -64,8 +64,9 @@ bool GlRenderer::flush() bool GlRenderer::preRender() { - //TODO: called just before render() - + // Blend function for pre multiplied alpha + GL_CHECK(glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); + GL_CHECK(glEnable(GL_BLEND)); return true; } diff --git a/test/testAsync.cpp b/test/testAsync.cpp old mode 100644 new mode 100755 index df81020a..4530f1d9 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -113,14 +113,8 @@ void initGLview(Evas_Object *obj) 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->sync(); } diff --git a/test/testBlending.cpp b/test/testBlending.cpp old mode 100644 new mode 100755 index 6765cb67..7db82019 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -101,14 +101,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp old mode 100644 new mode 100755 index 71dd6a01..a2bb1d8e --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -90,14 +90,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp old mode 100644 new mode 100755 index 59454900..00a3bc30 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -139,14 +139,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp old mode 100644 new mode 100755 index 67d0240c..164ff612 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -102,14 +102,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp old mode 100644 new mode 100755 index 1c1b8206..a97ec70d --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -167,14 +167,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp old mode 100644 new mode 100755 index 826287b0..90656fce --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -119,14 +119,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp old mode 100644 new mode 100755 index 88601351..d81f7098 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -79,14 +79,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testPath.cpp b/test/testPath.cpp old mode 100644 new mode 100755 index bcd5ab78..b3a265ea --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -96,14 +96,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp old mode 100644 new mode 100755 index dd008270..724b8b4f --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -133,14 +133,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp old mode 100644 new mode 100755 index 054bf12d..c80cb03f --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -119,14 +119,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testScene.cpp b/test/testScene.cpp old mode 100644 new mode 100755 index b796a5b8..c835a921 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -126,14 +126,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp old mode 100644 new mode 100755 index aeaf11eb..9597101d --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -163,14 +163,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testShape.cpp b/test/testShape.cpp old mode 100644 new mode 100755 index 391b55ff..7788817f --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -69,14 +69,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testStroke.cpp b/test/testStroke.cpp old mode 100644 new mode 100755 index f7c1a88f..36f2a948 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -116,14 +116,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp old mode 100644 new mode 100755 index bc3f9601..894c6950 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -153,14 +153,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testSvg.cpp b/test/testSvg.cpp old mode 100644 new mode 100755 index edb987b8..65fe9d7a --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -93,14 +93,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testTransform.cpp b/test/testTransform.cpp old mode 100644 new mode 100755 index da7c87cd..6d0edbf1 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -130,14 +130,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp old mode 100644 new mode 100755 index c3504356..0d007381 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -91,14 +91,8 @@ void initGLview(Evas_Object *obj) 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); if (glCanvas->draw() == tvg::Result::Success) { glCanvas->sync(); From dd1f7875f62178564817309d4bfb19ada835a946 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 17 Jul 2020 16:56:05 +0900 Subject: [PATCH 164/244] updated AUTHORS Change-Id: If9412e0598bdfa59dc142aacaec1cb5ae3f5401d --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 3e778fef..348597a9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ Hermet Park Prudhvi Raj Vasireddi Junsu Choi +Pranay Samanta From 56c0235dc5b43261f376d9164f93dcdca5af6f4d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 17 Jul 2020 16:57:02 +0900 Subject: [PATCH 165/244] test: changed file permission. Change-Id: I8172152f700d10fa1d8c84473d45ff484c0b36d8 --- test/testAsync.cpp | 0 test/testBlending.cpp | 0 test/testBoundary.cpp | 0 test/testCustomTransform.cpp | 0 test/testDirectUpdate.cpp | 0 test/testGradientTransform.cpp | 0 test/testLinearGradient.cpp | 0 test/testMultiShapes.cpp | 0 test/testPath.cpp | 0 test/testPathCopy.cpp | 0 test/testRadialGradient.cpp | 0 test/testScene.cpp | 0 test/testSceneTransform.cpp | 0 test/testShape.cpp | 0 test/testStroke.cpp | 0 test/testStrokeLine.cpp | 0 test/testSvg.cpp | 0 test/testTransform.cpp | 0 test/testUpdate.cpp | 0 19 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 test/testAsync.cpp mode change 100755 => 100644 test/testBlending.cpp mode change 100755 => 100644 test/testBoundary.cpp mode change 100755 => 100644 test/testCustomTransform.cpp mode change 100755 => 100644 test/testDirectUpdate.cpp mode change 100755 => 100644 test/testGradientTransform.cpp mode change 100755 => 100644 test/testLinearGradient.cpp mode change 100755 => 100644 test/testMultiShapes.cpp mode change 100755 => 100644 test/testPath.cpp mode change 100755 => 100644 test/testPathCopy.cpp mode change 100755 => 100644 test/testRadialGradient.cpp mode change 100755 => 100644 test/testScene.cpp mode change 100755 => 100644 test/testSceneTransform.cpp mode change 100755 => 100644 test/testShape.cpp mode change 100755 => 100644 test/testStroke.cpp mode change 100755 => 100644 test/testStrokeLine.cpp mode change 100755 => 100644 test/testSvg.cpp mode change 100755 => 100644 test/testTransform.cpp mode change 100755 => 100644 test/testUpdate.cpp diff --git a/test/testAsync.cpp b/test/testAsync.cpp old mode 100755 new mode 100644 diff --git a/test/testBlending.cpp b/test/testBlending.cpp old mode 100755 new mode 100644 diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp old mode 100755 new mode 100644 diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp old mode 100755 new mode 100644 diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp old mode 100755 new mode 100644 diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp old mode 100755 new mode 100644 diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp old mode 100755 new mode 100644 diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp old mode 100755 new mode 100644 diff --git a/test/testPath.cpp b/test/testPath.cpp old mode 100755 new mode 100644 diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp old mode 100755 new mode 100644 diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp old mode 100755 new mode 100644 diff --git a/test/testScene.cpp b/test/testScene.cpp old mode 100755 new mode 100644 diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp old mode 100755 new mode 100644 diff --git a/test/testShape.cpp b/test/testShape.cpp old mode 100755 new mode 100644 diff --git a/test/testStroke.cpp b/test/testStroke.cpp old mode 100755 new mode 100644 diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp old mode 100755 new mode 100644 diff --git a/test/testSvg.cpp b/test/testSvg.cpp old mode 100755 new mode 100644 diff --git a/test/testTransform.cpp b/test/testTransform.cpp old mode 100755 new mode 100644 diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp old mode 100755 new mode 100644 From a5d1542e4478b19e6b5b44869bc677ec0ffa930a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 17 Jul 2020 17:15:16 +0900 Subject: [PATCH 166/244] test: ++code safety added null check for exceptional case. Change-Id: I12a5e9724149f607188b67a84e46a033a16270f7 --- test/testAsync.cpp | 2 ++ test/testBlending.cpp | 2 ++ test/testBoundary.cpp | 2 ++ test/testCommon.h | 3 +-- test/testCustomTransform.cpp | 6 +++++- test/testDirectUpdate.cpp | 4 ++++ test/testGradientTransform.cpp | 6 +++++- test/testLinearGradient.cpp | 2 ++ test/testMultiShapes.cpp | 2 ++ test/testPath.cpp | 2 ++ test/testPathCopy.cpp | 4 +++- test/testRadialGradient.cpp | 4 +++- test/testScene.cpp | 4 +++- test/testSceneTransform.cpp | 6 +++++- test/testShape.cpp | 4 +++- test/testStroke.cpp | 4 +++- test/testStrokeLine.cpp | 4 +++- test/testSvg.cpp | 4 +++- test/testTransform.cpp | 6 +++++- test/testUpdate.cpp | 6 +++++- 20 files changed, 63 insertions(+), 14 deletions(-) diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 4530f1d9..edc6dde7 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -10,6 +10,8 @@ static unsigned cnt = 0; bool tvgUpdateCmds(tvg::Canvas* canvas) { + if (!canvas) return false; + auto t = ecore_time_get(); //Explicitly clear all retained paint nodes. diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 7db82019..5477b3b6 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + canvas->reserve(5); //Prepare Round Rectangle diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index a2bb1d8e..57a3d6c6 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + canvas->reserve(5); //reserve 5 shape nodes (optional) //Prepare Shape1 diff --git a/test/testCommon.h b/test/testCommon.h index f1769566..13ac86ab 100644 --- a/test/testCommon.h +++ b/test/testCommon.h @@ -12,14 +12,13 @@ using namespace std; /************************************************************************/ void tvgSwTest(uint32_t* buffer); +void drawSwView(void* data, Eo* obj); 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]; diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 00a3bc30..f95e41ef 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -7,6 +7,8 @@ tvg::Shape* pShape = nullptr; void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Shape1 auto shape = tvg::Shape::gen(); @@ -33,6 +35,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { + if (!canvas) return; + /* Update shape directly. You can update only necessary properties of this shape, while retaining other properties. */ @@ -202,4 +206,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 164ff612..3c275b62 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -7,6 +7,8 @@ tvg::Shape* pShape = nullptr; void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Shape auto shape = tvg::Shape::gen(); @@ -26,6 +28,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { + if (!canvas) return; + /* Update shape directly. You can update only necessary properties of this shape, while retaining other properties. */ diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index a97ec70d..4fa426be 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -9,6 +9,8 @@ tvg::Shape* pShape3 = nullptr; void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Shape1 auto shape = tvg::Shape::gen(); @@ -83,6 +85,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { + if (!canvas) return; + /* Update shape directly. You can update only necessary properties of this shape, while retaining other properties. */ @@ -230,4 +234,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 90656fce..f98fc970 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index d81f7098..5a6d34f9 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle diff --git a/test/testPath.cpp b/test/testPath.cpp index b3a265ea..52c56efb 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Star auto shape1 = tvg::Shape::gen(); diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 724b8b4f..0ae364b7 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + /* Star */ //Prepare Path Commands @@ -182,4 +184,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index c80cb03f..a6c10ba1 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle @@ -168,4 +170,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testScene.cpp b/test/testScene.cpp index c835a921..5b12020e 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Create a Scene auto scene = tvg::Scene::gen(); scene->reserve(3); //reserve 3 shape nodes (optional) @@ -175,4 +177,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 9597101d..0d0be8e7 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -8,6 +8,8 @@ tvg::Scene* pScene2 = nullptr; void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Create a Scene1 auto scene = tvg::Scene::gen(); pScene1 = scene.get(); @@ -90,6 +92,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { + if (!canvas) return; + /* Update scene directly. You can update only necessary properties of this scene, while retaining other properties. */ @@ -226,4 +230,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testShape.cpp b/test/testShape.cpp index 7788817f..88519d05 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 200, 200, 0, 0); //x, y, w, h, rx, ry @@ -118,4 +120,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 36f2a948..91748727 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Shape 1 auto shape1 = tvg::Shape::gen(); shape1->appendRect(50, 50, 200, 200, 0, 0); @@ -165,4 +167,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 894c6950..445f8406 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Test for Stroke Width for (int i = 0; i < 10; ++i) { auto shape = tvg::Shape::gen(); @@ -202,4 +204,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 65fe9d7a..b8eb2ba2 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -31,6 +31,8 @@ void svgDirCallback(const char* name, const char* path, void* data) void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Background auto shape = tvg::Shape::gen(); shape->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry @@ -142,4 +144,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 6d0edbf1..7529d140 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -9,6 +9,8 @@ tvg::Shape* pShape3 = nullptr; void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Shape1 auto shape = tvg::Shape::gen(); @@ -46,6 +48,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { + if (!canvas) return; + /* Update shape directly. You can update only necessary properties of this shape, while retaining other properties. */ @@ -193,4 +197,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 0d007381..9c213436 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -6,6 +6,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) { + if (!canvas) return; + //Shape auto shape = tvg::Shape::gen(); shape->appendRect(-100, -100, 200, 200, 0, 0); @@ -15,6 +17,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { + if (!canvas) return; + //Explicitly clear all retained paint nodes. if (canvas->clear() != tvg::Result::Success) return; @@ -154,4 +158,4 @@ int main(int argc, char **argv) cout << "engine is not supported" << endl; } return 0; -} \ No newline at end of file +} From 2ba529c8fb071bce45cbdb644a3186e920240aa1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 16 Jul 2020 20:42:42 +0900 Subject: [PATCH 167/244] common transformation: fix transformation multiply Change-Id: Ibc95fab0abfc07aa7f0c4ff6c74785d4f73d02c7 --- src/lib/sw_engine/tvgSwFill.cpp | 12 +++--- src/lib/sw_engine/tvgSwShape.cpp | 4 +- src/lib/tvgRender.cpp | 31 ++++++++------- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 38 +------------------ test/svgs/duke.svg | 25 ++++++++++++ test/testCustomTransform.cpp | 12 +++--- 6 files changed, 56 insertions(+), 66 deletions(-) create mode 100644 test/svgs/duke.svg diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index fd857f9c..43514bc4 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -100,12 +100,12 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->e11 + dy * transform->e12 + transform->e31 + cx; - y1 = dx * transform->e21 + dy * transform->e22 + transform->e32 + cy; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e13 + cx; + y1 = dx * transform->e21 + dy * transform->e22 + transform->e23 + cy; dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->e11 + dy * transform->e12 + transform->e31 + cx; - y2 = dx * transform->e21 + dy * transform->e22 + transform->e32 + cy; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e13 + cx; + y2 = dx * transform->e21 + dy * transform->e22 + transform->e23 + cy; } fill->linear.dx = x2 - x1; @@ -131,8 +131,8 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr if (radius < FLT_EPSILON) return true; if (transform) { - auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; - auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; + auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e13; + auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e23; fill->radial.cx = tx; fill->radial.cy = ty; radius *= transform->e33; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 66655b03..026dae0e 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -239,8 +239,8 @@ static void _transformOutline(SwOutline* outline, const Matrix* transform) for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; - auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23; auto pt = Point{round(tx), round(ty)}; outline->pts[i] = TO_SWPOINT(&pt); } diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index c1212c68..4317aaca 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -66,7 +66,6 @@ bool RenderTransform::update() //scale m.e11 *= factor; m.e22 *= factor; - m.e33 *= factor; //rotation if (fabsf(degree) > FLT_EPSILON) { @@ -78,19 +77,19 @@ bool RenderTransform::update() auto t12 = m.e11 * -sinVal + m.e12 * cosVal; auto t21 = m.e21 * cosVal + m.e22 * sinVal; auto t22 = m.e21 * -sinVal + m.e22 * cosVal; - auto t31 = m.e31 * cosVal + m.e32 * sinVal; - auto t32 = m.e31 * -sinVal + m.e32 * cosVal; + auto t13 = m.e13 * cosVal + m.e23 * sinVal; + auto t23 = m.e13 * -sinVal + m.e23 * cosVal; m.e11 = t11; m.e12 = t12; m.e21 = t21; m.e22 = t22; - m.e31 = t31; - m.e32 = t32; + m.e13 = t13; + m.e23 = t23; } - m.e31 += x; - m.e32 += y; + m.e13 += x; + m.e23 += y; return true; } @@ -105,17 +104,17 @@ RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransfo { assert(lhs && rhs); - auto dx = rhs->x * lhs->factor; - auto dy = rhs->y * lhs->factor; - auto tx = dx * lhs->m.e11 + dy * lhs->m.e12 + lhs->m.e13; - auto ty = dx * lhs->m.e21 + dy * lhs->m.e22 + lhs->m.e23; + m.e11 = lhs->m.e11 * rhs->m.e11 + lhs->m.e12 * rhs->m.e21 + lhs->m.e13 * rhs->m.e31; + m.e12 = lhs->m.e11 * rhs->m.e12 + lhs->m.e12 * rhs->m.e22 + lhs->m.e13 * rhs->m.e32; + m.e13 = lhs->m.e11 * rhs->m.e13 + lhs->m.e12 * rhs->m.e23 + lhs->m.e13 * rhs->m.e33; - x = lhs->x + tx; - y = lhs->y + ty; - degree = lhs->degree + rhs->degree; - factor = lhs->factor * rhs->factor; + m.e21 = lhs->m.e21 * rhs->m.e11 + lhs->m.e22 * rhs->m.e21 + lhs->m.e23 * rhs->m.e31; + m.e22 = lhs->m.e21 * rhs->m.e12 + lhs->m.e22 * rhs->m.e22 + lhs->m.e23 * rhs->m.e32; + m.e23 = lhs->m.e21 * rhs->m.e13 + lhs->m.e22 * rhs->m.e23 + lhs->m.e23 * rhs->m.e33; - update(); + m.e31 = lhs->m.e31 * rhs->m.e11 + lhs->m.e32 * rhs->m.e21 + lhs->m.e33 * rhs->m.e31; + m.e32 = lhs->m.e31 * rhs->m.e12 + lhs->m.e32 * rhs->m.e22 + lhs->m.e33 * rhs->m.e32; + m.e33 = lhs->m.e31 * rhs->m.e13 + lhs->m.e32 * rhs->m.e23 + lhs->m.e33 * rhs->m.e33; } #endif //_TVG_RENDER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index c6513681..53f00932 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -20,26 +20,6 @@ #include "tvgSvgSceneBuilder.h" - -static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, float* z) -{ - float rz, si, cs, zcs, zsi; - - *tx = m->e13; - *ty = m->e23; - - cs = m->e11; - si = m->e21; - rz = atan2(si, cs); - *z = rz * (180.0f / M_PI); - zcs = cosf(-1.0f * rz); - zsi = sinf(-1.0f * rz); - m->e11 = m->e11 * zcs + m->e12 * zsi; - m->e22 = m->e21 * (-1 * zsi) + m->e22 * zcs; - *s = m->e11 > m->e22 ? m->e11 : m->e22; -} - - unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh) { Fill::ColorStop* stops; @@ -225,15 +205,7 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa { SvgStyleProperty* style = node->style; - //Apply the transformation - if (node->transform) { - float tx = 0, ty = 0, s = 0, z = 0; - _getTransformationData(node->transform, &tx, &ty, &s, &z); - vg->scale(s); - vg->rotate(z); - vg->translate(tx, ty); - } - + if (node->transform) vg->transform(*node->transform); if (node->type == SvgNodeType::Doc) return; //If fill property is nullptr then do nothing @@ -359,13 +331,7 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, { if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) { auto scene = Scene::gen(); - if (node->transform) { - float tx = 0, ty = 0, s = 0, z = 0; - _getTransformationData(node->transform, &tx, &ty, &s, &z); - scene->scale(s); - scene->rotate(z); - scene->translate(tx, ty); - } + if (node->transform) scene->transform(*node->transform); node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; for (auto child : node->child) { child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; diff --git a/test/svgs/duke.svg b/test/svgs/duke.svg new file mode 100644 index 00000000..64cdcf8e --- /dev/null +++ b/test/svgs/duke.svg @@ -0,0 +1,25 @@ + + + + + diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index f95e41ef..4803ef16 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -61,19 +61,19 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) auto t12 = m.e11 * -sinVal + m.e12 * cosVal; auto t21 = m.e21 * cosVal + m.e22 * sinVal; auto t22 = m.e21 * -sinVal + m.e22 * cosVal; - auto t31 = m.e31 * cosVal + m.e32 * sinVal; - auto t32 = m.e31 * -sinVal + m.e32 * cosVal; + auto t13 = m.e31 * cosVal + m.e32 * sinVal; + auto t23 = m.e31 * -sinVal + m.e32 * cosVal; m.e11 = t11; m.e12 = t12; m.e21 = t21; m.e22 = t22; - m.e31 = t31; - m.e32 = t32; + m.e13 = t13; + m.e23 = t23; //translate - m.e31 = progress * 300.0f + 300.0f; - m.e32 = progress * -100.0f + 300.0f; + m.e13 = progress * 300.0f + 300.0f; + m.e23 = progress * -100.0f + 300.0f; pShape->transform(m); From 6cfb3cdb6c469301c8538e77a51b0281a88ead82 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 20 Jul 2020 11:44:32 +0900 Subject: [PATCH 168/244] test: replaced svg resources. Change-Id: I30ab48ecc0bbae158baecce1f6173fc36ecfbbb6 --- test/svgs/rect.svg | 7 ------- test/svgs/shape.svg | 18 ------------------ test/svgs/wikimedia.svg | 5 +++++ test/svgs/yinyang.svg | 6 ++++++ 4 files changed, 11 insertions(+), 25 deletions(-) delete mode 100644 test/svgs/rect.svg delete mode 100644 test/svgs/shape.svg create mode 100644 test/svgs/wikimedia.svg create mode 100644 test/svgs/yinyang.svg diff --git a/test/svgs/rect.svg b/test/svgs/rect.svg deleted file mode 100644 index 2e829058..00000000 --- a/test/svgs/rect.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/test/svgs/shape.svg b/test/svgs/shape.svg deleted file mode 100644 index a0b3677a..00000000 --- a/test/svgs/shape.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/test/svgs/wikimedia.svg b/test/svgs/wikimedia.svg new file mode 100644 index 00000000..ad2c2115 --- /dev/null +++ b/test/svgs/wikimedia.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test/svgs/yinyang.svg b/test/svgs/yinyang.svg new file mode 100644 index 00000000..3c64a6c7 --- /dev/null +++ b/test/svgs/yinyang.svg @@ -0,0 +1,6 @@ + + + + + + From 27ca82c140e0bdff0cf7646d61a650a7562356bb Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 21 Jul 2020 10:42:22 +0900 Subject: [PATCH 169/244] SvgLoader: Support display=none feature If display is none, scene does not create a child shape, and shape does not draw fills and strokes. Change-Id: I8af72c904be00107dff115429e27df7ba4cb83b6 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 53f00932..3b88d960 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -206,7 +206,7 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa SvgStyleProperty* style = node->style; if (node->transform) vg->transform(*node->transform); - if (node->type == SvgNodeType::Doc) return; + if (node->type == SvgNodeType::Doc || !node->display) return; //If fill property is nullptr then do nothing if (style->fill.paint.none) { @@ -333,10 +333,12 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, auto scene = Scene::gen(); if (node->transform) scene->transform(*node->transform); node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; - for (auto child : node->child) { - child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; - if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); - else scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + if (node->display) { + for (auto child : node->child) { + child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; + if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); + else scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + } } return move(scene); } From 96477c0a24f4112170ff4d084518a735d8f6483e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 21 Jul 2020 17:18:48 +0900 Subject: [PATCH 170/244] sw_engine: revise outline transform sw_engine simulates floating point by integer bit shifting, it loses the accuracy while converting the number data. This occurs the inacculated curve points result if it scales up very large size. So we transform points before converting data in order to avoid losing the numbers less decimal point. Change-Id: I0172e83f06b1a19143a2f65f667dc193e9a4396a --- src/lib/sw_engine/tvgSwCommon.h | 10 +-- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 101 +++++++++++++--------------- 3 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 5e474838..36391660 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -207,12 +207,6 @@ struct SwShape }; -static inline SwPoint TO_SWPOINT(const Point* pt) -{ - return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; -} - - static inline SwCoord TO_SWCOORD(float val) { return SwCoord(val * 64); @@ -261,12 +255,12 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); -bool shapeGenOutline(SwShape& shape, const Shape* sdata); +bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform); bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias); void shapeDelOutline(SwShape& shape); void shapeResetStroke(SwShape& shape, const Shape* sdata); -bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip); +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape& shape); void shapeDelStroke(SwShape& shape); bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index adc3e9f5..7c3ca8d1 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -212,7 +212,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (strokeAlpha > 0) { shapeResetStroke(task->shape, task->sdata); - if (!shapeGenStrokeRle(task->shape, task->sdata, task->clip)) return; + if (!shapeGenStrokeRle(task->shape, task->sdata, task->transform, task->clip)) return; } else { shapeDelStroke(task->shape); } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 026dae0e..d302fd7d 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -96,13 +96,25 @@ static void _outlineEnd(SwOutline& outline) } -static void _outlineMoveTo(SwOutline& outline, const Point* to) +static inline SwPoint _transform(const Point* to, const Matrix* transform) +{ + if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; + + auto tx = round(to->x * transform->e11 + to->y * transform->e12 + transform->e13); + auto ty = round(to->x * transform->e21 + to->y * transform->e22 + transform->e23); + + return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; +} + + +static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform) { assert(to); _growOutlinePoint(outline, 1); - outline.pts[outline.ptsCnt] = TO_SWPOINT(to); + outline.pts[outline.ptsCnt] = _transform(to, transform); + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; if (outline.ptsCnt > 0) { @@ -115,33 +127,33 @@ static void _outlineMoveTo(SwOutline& outline, const Point* to) } -static void _outlineLineTo(SwOutline& outline, const Point* to) +static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix* transform) { assert(to); _growOutlinePoint(outline, 1); - outline.pts[outline.ptsCnt] = TO_SWPOINT(to); + outline.pts[outline.ptsCnt] = _transform(to, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } -static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to) +static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) { assert(ctrl1 && ctrl2 && to); _growOutlinePoint(outline, 3); - outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1); + outline.pts[outline.ptsCnt] = _transform(ctrl1, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; - outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2); + outline.pts[outline.ptsCnt] = _transform(ctrl2, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; - outline.pts[outline.ptsCnt] = TO_SWPOINT(to); + outline.pts[outline.ptsCnt] = _transform(to, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } @@ -230,24 +242,7 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi } -static void _transformOutline(SwOutline* outline, const Matrix* transform) -{ - if (!transform) return; - - assert(outline); - - for(uint32_t i = 0; i < outline->ptsCnt; ++i) { - auto dx = static_cast(outline->pts[i].x >> 6); - auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13; - auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23; - auto pt = Point{round(tx), round(ty)}; - outline->pts[i] = TO_SWPOINT(&pt); - } -} - - -static void _dashLineTo(SwDashStroke& dash, const Point* to) +static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* transform) { _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); @@ -258,8 +253,8 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) if (len < dash.curLen) { dash.curLen -= len; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &dash.ptCur); - _outlineLineTo(*dash.outline, to); + _outlineMoveTo(*dash.outline, &dash.ptCur, transform); + _outlineLineTo(*dash.outline, to, transform); } } else { while (len > dash.curLen) { @@ -268,8 +263,8 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) _lineSplitAt(cur, dash.curLen, left, right);; dash.curIdx = (dash.curIdx + 1) % dash.cnt; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &left.pt1); - _outlineLineTo(*dash.outline, &left.pt2); + _outlineMoveTo(*dash.outline, &left.pt1, transform); + _outlineLineTo(*dash.outline, &left.pt2, transform); } dash.curLen = dash.pattern[dash.curIdx]; dash.curOpGap = !dash.curOpGap; @@ -278,9 +273,9 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) } //leftovers dash.curLen -= len; - if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &cur.pt1); - _outlineLineTo(*dash.outline, &cur.pt2); + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &cur.pt1, transform); + _outlineLineTo(*dash.outline, &cur.pt2, transform); } if (dash.curLen < 1) { //move to next dash @@ -293,7 +288,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) } -static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to) +static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) { _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); @@ -304,8 +299,8 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct if (len < dash.curLen) { dash.curLen -= len; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &dash.ptCur); - _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to); + _outlineMoveTo(*dash.outline, &dash.ptCur, transform); + _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform); } } else { while (len > dash.curLen) { @@ -314,8 +309,8 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct bezSplitAt(cur, dash.curLen, left, right); dash.curIdx = (dash.curIdx + 1) % dash.cnt; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &left.start); - _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end); + _outlineMoveTo(*dash.outline, &left.start, transform); + _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end, transform); } dash.curLen = dash.pattern[dash.curIdx]; dash.curOpGap = !dash.curOpGap; @@ -325,8 +320,8 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct //leftovers dash.curLen -= len; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &cur.start); - _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end); + _outlineMoveTo(*dash.outline, &cur.start, transform); + _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end, transform); } if (dash.curLen < 1) { //move to next dash @@ -339,7 +334,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct } -SwOutline* _genDashOutline(const Shape* sdata) +SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) { assert(sdata); @@ -405,7 +400,7 @@ SwOutline* _genDashOutline(const Shape* sdata) while (cmdCnt-- > 0) { switch(*cmds) { case PathCommand::Close: { - _dashLineTo(dash, &dash.ptStart); + _dashLineTo(dash, &dash.ptStart, transform); break; } case PathCommand::MoveTo: { @@ -418,12 +413,12 @@ SwOutline* _genDashOutline(const Shape* sdata) break; } case PathCommand::LineTo: { - _dashLineTo(dash, pts); + _dashLineTo(dash, pts, transform); ++pts; break; } case PathCommand::CubicTo: { - _dashCubicTo(dash, pts, pts + 1, pts + 2); + _dashCubicTo(dash, pts, pts + 1, pts + 2, transform); pts += 3; break; } @@ -465,9 +460,7 @@ bool _fastTrack(const SwOutline* outline) bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) { - if (!shapeGenOutline(shape, sdata)) return false; - - _transformOutline(shape.outline, transform); + if (!shapeGenOutline(shape, sdata, transform)) return false; if (!_updateBBox(shape.outline, shape.bbox)) return false; @@ -510,7 +503,7 @@ void shapeReset(SwShape& shape) } -bool shapeGenOutline(SwShape& shape, const Shape* sdata) +bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform) { assert(sdata); @@ -571,17 +564,17 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata) break; } case PathCommand::MoveTo: { - _outlineMoveTo(*outline, pts); + _outlineMoveTo(*outline, pts, transform); ++pts; break; } case PathCommand::LineTo: { - _outlineLineTo(*outline, pts); + _outlineLineTo(*outline, pts, transform); ++pts; break; } case PathCommand::CubicTo: { - _outlineCubicTo(*outline, pts, pts + 1, pts + 2); + _outlineCubicTo(*outline, pts, pts + 1, pts + 2, transform); pts += 3; break; } @@ -638,7 +631,7 @@ void shapeResetStroke(SwShape& shape, const Shape* sdata) } -bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip) { assert(sdata); @@ -646,12 +639,12 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) //Dash Style Stroke if (sdata->strokeDash(nullptr) > 0) { - shapeOutline = _genDashOutline(sdata); + shapeOutline = _genDashOutline(sdata, transform); if (!shapeOutline) return false; //Normal Style stroke } else { if (!shape.outline) { - if (!shapeGenOutline(shape, sdata)) return false; + if (!shapeGenOutline(shape, sdata, transform)) return false; } shapeOutline = shape.outline; } From 5dcafb8b89928d36821a5c92573df2009b6ae821 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 22 Jul 2020 18:45:11 +0900 Subject: [PATCH 171/244] comon: code refactoring renamed internal variable for better readibility. Change-Id: I07dc66c4bd63f2aec8036aab14ec3ed608820fbc --- src/lib/tvgRender.cpp | 6 +++--- src/lib/tvgRender.h | 2 +- src/lib/tvgSceneImpl.h | 4 ++-- src/lib/tvgShapeImpl.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4317aaca..89edcb1e 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -48,7 +48,7 @@ bool RenderTransform::update() //Init Status if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && - fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { + fabsf(degree) <= FLT_EPSILON && fabsf(scale - 1) <= FLT_EPSILON) { return false; } @@ -64,8 +64,8 @@ bool RenderTransform::update() m.e33 = 1.0f; //scale - m.e11 *= factor; - m.e22 *= factor; + m.e11 *= scale; + m.e22 *= scale; //rotation if (fabsf(degree) > FLT_EPSILON) { diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index e20271b8..576961e4 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -36,7 +36,7 @@ struct RenderTransform float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree - float factor = 1.0f; //scale factor + float scale = 1.0f; //scale factor bool overriding = false; //user transform? bool update(); diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index a70991c6..9972d72f 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -166,13 +166,13 @@ struct Scene::Impl bool scale(float factor) { if (rTransform) { - if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; rTransform = new RenderTransform(); if (!rTransform) return false; } - rTransform->factor = factor; + rTransform->scale = factor; flag |= RenderUpdateFlag::Transform; return true; diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index fa670f01..54d37a3b 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -105,13 +105,13 @@ struct Shape::Impl bool scale(float factor) { if (rTransform) { - if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; rTransform = new RenderTransform(); if (!rTransform) return false; } - rTransform->factor = factor; + rTransform->scale = factor; if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; return true; From 4d72eeda1556e179ecf7b60bc2a7829a476ef8e8 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 21 Jul 2020 20:24:25 +0900 Subject: [PATCH 172/244] sw_engine: revise scale transform logic. Basically, stroke width size is linear, engine couldn't apply scale factor from the matrix which contains 2 dimensional values. Thus, we can apply it if the scale factor of x/y is identical. Otherwise, we should transform every stroke points in the stroking process. That scenario can be improved with another patch. Change-Id: I070dcf29d2e42f21e182bdf4239781464158ef73 --- src/lib/sw_engine/tvgSwCommon.h | 5 +++-- src/lib/sw_engine/tvgSwRenderer.cpp | 4 ++-- src/lib/sw_engine/tvgSwShape.cpp | 4 ++-- src/lib/sw_engine/tvgSwStroke.cpp | 11 +++++++++-- src/lib/tvgRender.h | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 36391660..b1d38af8 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -156,6 +156,7 @@ struct SwStroke bool firstPt; bool openSubPath; bool handleWideStrokes; + bool preScaled; }; struct SwDashStroke @@ -259,7 +260,7 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias); void shapeDelOutline(SwShape& shape); -void shapeResetStroke(SwShape& shape, const Shape* sdata); +void shapeResetStroke(SwShape& shape, const Shape* sdata, const Matrix* transform); bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape& shape); void shapeDelStroke(SwShape& shape); @@ -267,7 +268,7 @@ bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transfor void shapeResetFill(SwShape& shape); void shapeDelFill(SwShape& shape); -void strokeReset(SwStroke& stroke, const Shape* shape); +void strokeReset(SwStroke& stroke, const Shape* shape, const Matrix* transform); bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 7c3ca8d1..aac6d8ef 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -211,7 +211,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* //Stroke if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (strokeAlpha > 0) { - shapeResetStroke(task->shape, task->sdata); + shapeResetStroke(task->shape, task->sdata, task->transform); if (!shapeGenStrokeRle(task->shape, task->sdata, task->transform, task->clip)) return; } else { shapeDelStroke(task->shape); @@ -257,4 +257,4 @@ SwRenderer* SwRenderer::inst() return static_cast(RenderInitializer::inst(renderInit)); } -#endif /* _TVG_SW_RENDERER_CPP_ */ +#endif /* _TVG_SW_RENDERER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d302fd7d..c3aced89 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -618,13 +618,13 @@ void shapeDelStroke(SwShape& shape) } -void shapeResetStroke(SwShape& shape, const Shape* sdata) +void shapeResetStroke(SwShape& shape, const Shape* sdata, const Matrix* transform) { if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); auto stroke = shape.stroke; assert(stroke); - strokeReset(*stroke, sdata); + strokeReset(*stroke, sdata, transform); rleFree(shape.strokeRle); shape.strokeRle = nullptr; diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index d45ddd8e..abaf4554 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -818,11 +818,18 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, const Shape* sdata) +void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); - stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); + //If x/y scale factor is identical, we can scale width size simply. + auto scale = 1.0f; + if (transform && fabsf(transform->e11 - transform->e22) < FLT_EPSILON) { + scale = transform->e11; + stroke.preScaled = true; + } + + stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5 * scale); stroke.cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 576961e4..6a0897e8 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -32,7 +32,7 @@ enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, struct RenderTransform { - Matrix m; //3x3 Matrix Elements + Matrix m; //3x3 Matrix Elements float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree From 62aa24d9adcb1c84b623b1bdfe6197b6234a1160 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 23 Jul 2020 10:14:46 +0900 Subject: [PATCH 173/244] SvgLoader: Fix opacity propagation Remove duplicate opacity calculation of the scene. Change-Id: I1253ea290e78fdbf946a492ebfcaaa082fbfc121 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 3b88d960..4d7a27a7 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -335,9 +335,11 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; if (node->display) { for (auto child : node->child) { - child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); - else scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + else { + child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; + scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + } } } return move(scene); From f1aab529589fa4ff0bbafe86965d9e25ec40e3b0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 22 Jul 2020 20:31:57 +0900 Subject: [PATCH 174/244] sw_engine: support bidirectional stroke scaling. if the transform scale factor for x/y is not identical, it keeps its both xy scale factor then apply them for stroking calculation. Change-Id: I519dfce3ce7b4a12c13da1801d6a00e139e7400f --- src/lib/sw_engine/tvgSwCommon.h | 5 ++- src/lib/sw_engine/tvgSwShape.cpp | 22 +++++------ src/lib/sw_engine/tvgSwStroke.cpp | 64 ++++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index b1d38af8..bad159b1 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -153,10 +153,13 @@ struct SwStroke SwStrokeBorder borders[2]; + float sx; + float sy; + bool firstPt; bool openSubPath; bool handleWideStrokes; - bool preScaled; + bool postScale; }; struct SwDashStroke diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index c3aced89..2165f424 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -30,6 +30,17 @@ struct Line }; +static SwPoint _transform(const Point* to, const Matrix* transform) +{ + if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; + + auto tx = round(to->x * transform->e11 + to->y * transform->e12 + transform->e13); + auto ty = round(to->x * transform->e21 + to->y * transform->e22 + transform->e23); + + return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; +} + + static float _lineLength(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. @@ -96,17 +107,6 @@ static void _outlineEnd(SwOutline& outline) } -static inline SwPoint _transform(const Point* to, const Matrix* transform) -{ - if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; - - auto tx = round(to->x * transform->e11 + to->y * transform->e12 + transform->e13); - auto ty = round(to->x * transform->e21 + to->y * transform->e22 + transform->e23); - - return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; -} - - static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform) { assert(to); diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index abaf4554..53fae90a 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -34,6 +34,15 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s) } +static inline void SCALE(SwStroke& stroke, SwPoint& pt) +{ + if (stroke.postScale) { + pt.x = pt.x * stroke.sx; + pt.y = pt.y * stroke.sy; + } +} + + static void _growBorder(SwStrokeBorder* border, uint32_t newPts) { assert(border); @@ -132,11 +141,12 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl } -static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff) +static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff, SwStroke& stroke) { constexpr SwFixed ARC_CUBIC_ANGLE = SW_ANGLE_PI / 2; SwPoint a = {radius, 0}; mathRotate(a, angleStart); + SCALE(stroke, a); a += center; auto total = angleDiff; @@ -157,6 +167,7 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius //compute end point SwPoint b = {radius, 0}; mathRotate(b, next); + SCALE(stroke, b); b += center; //compute first and second control points @@ -164,10 +175,12 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius SwPoint a2 = {length, 0}; mathRotate(a2, angle + rotate); + SCALE(stroke, a2); a2 += a; SwPoint b2 = {length, 0}; mathRotate(b2, next - rotate); + SCALE(stroke, b2); b2 += b; //add cubic arc @@ -224,7 +237,7 @@ static void _arcTo(SwStroke& stroke, int32_t side) auto total = mathDiff(stroke.angleIn, stroke.angleOut); if (total == SW_ANGLE_PI) total = -rotate * 2; - _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total); + _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total, stroke); border->movable = false; } @@ -268,6 +281,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (bevel) { SwPoint delta = {stroke.width, 0}; mathRotate(delta, stroke.angleOut + rotate); + SCALE(stroke, delta); delta += stroke.center; border->movable = false; _borderLineTo(border, delta, false); @@ -276,6 +290,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) auto length = mathDivide(stroke.width, thcos); SwPoint delta = {length, 0}; mathRotate(delta, phi); + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); @@ -284,6 +299,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (lineLength == 0) { delta = {stroke.width, 0}; mathRotate(delta, stroke.angleOut + rotate); + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); } @@ -312,15 +328,16 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (!intersect) { delta = {stroke.width, 0}; mathRotate(delta, stroke.angleOut + rotate); + SCALE(stroke, delta); delta += stroke.center; border->movable = false; } else { //compute median angle auto phi = stroke.angleIn + theta; auto thcos = mathCos(theta); - auto length = mathDivide(stroke.width, thcos); - delta = {length, 0}; + delta = {mathDivide(stroke.width, thcos), 0}; mathRotate(delta, phi + rotate); + SCALE(stroke, delta); delta += stroke.center; } @@ -353,6 +370,7 @@ void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { SwPoint delta = {stroke.width, 0}; mathRotate(delta, startAngle + SW_ANGLE_PI2); + SCALE(stroke, delta); auto pt = stroke.center + delta; auto border = stroke.borders; @@ -383,6 +401,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) delta = {stroke.width, 0}; mathRotate(delta, angle + SW_ANGLE_PI2); + SCALE(stroke, delta); //process corner if necessary if (stroke.firstPt) { @@ -428,9 +447,9 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl } SwPoint bezStack[37]; //TODO: static? - auto firstArc = true; auto limit = bezStack + 32; auto arc = bezStack; + auto firstArc = true; arc[0] = to; arc[1] = ctrl2; arc[2] = ctrl1; @@ -494,15 +513,18 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //compute control points SwPoint _ctrl1 = {length1, 0}; mathRotate(_ctrl1, phi1 + rotate); + SCALE(stroke, _ctrl1); _ctrl1 += arc[2]; SwPoint _ctrl2 = {length2, 0}; mathRotate(_ctrl2, phi2 + rotate); + SCALE(stroke, _ctrl2); _ctrl2 += arc[1]; //compute end point SwPoint _end = {stroke.width, 0}; mathRotate(_end, angleOut + rotate); + SCALE(stroke, _end); _end += arc[0]; if (stroke.handleWideStrokes) { @@ -526,6 +548,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl SwPoint delta = {alen, 0}; mathRotate(delta, beta); + SCALE(stroke, delta); delta += _start; //circumnavigate the negative sector backwards @@ -557,25 +580,28 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) { - if (stroke.cap == StrokeCap::Square) { + if (stroke.cap == StrokeCap::Square) { auto rotate = SIDE_TO_ROTATE(side); auto border = stroke.borders + side; SwPoint delta = {stroke.width, 0}; mathRotate(delta, angle); + SCALE(stroke, delta); SwPoint delta2 = {stroke.width, 0}; mathRotate(delta2, angle + rotate); + SCALE(stroke, delta2); delta += stroke.center + delta2; _borderLineTo(border, delta, false); delta = {stroke.width, 0}; mathRotate(delta, angle); + SCALE(stroke, delta); delta2 = {stroke.width, 0}; mathRotate(delta2, angle - rotate); - + SCALE(stroke, delta2); delta += delta2 + stroke.center; _borderLineTo(border, delta, false); @@ -593,14 +619,14 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) SwPoint delta = {stroke.width, 0}; mathRotate(delta, angle + rotate); - + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); delta = {stroke.width, 0}; mathRotate(delta, angle - rotate); - + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); @@ -822,11 +848,23 @@ void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); - //If x/y scale factor is identical, we can scale width size simply. auto scale = 1.0f; - if (transform && fabsf(transform->e11 - transform->e22) < FLT_EPSILON) { - scale = transform->e11; - stroke.preScaled = true; + + if (transform) { + //Fast Track: if x/y scale factor is identical, we can scale width size simply. + auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); + if (fabsf(sx - sy) < FLT_EPSILON) { + scale = sx; + stroke.postScale = false; + //Try scaling stroke with normal approach. + } else { + stroke.postScale = true; + stroke.sx = sx; + stroke.sy = sy; + } + } else { + stroke.postScale = false; } stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5 * scale); From 5fdc1f7fc86b9a9667741491c63d060ecfb15dd6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 24 Jul 2020 11:03:20 +0900 Subject: [PATCH 175/244] sw_engine: revise stroke scaling logic. previous fast track logic is useless, it actually doesn't helpful for performance, just increase the code complexity. Change-Id: Ib6ad204edfb241d74c41413dfec7ab42fb02af81 --- src/lib/sw_engine/tvgSwCommon.h | 4 +--- src/lib/sw_engine/tvgSwStroke.cpp | 27 ++++++--------------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index bad159b1..5f7ec46a 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -153,13 +153,11 @@ struct SwStroke SwStrokeBorder borders[2]; - float sx; - float sy; + float sx, sy; bool firstPt; bool openSubPath; bool handleWideStrokes; - bool postScale; }; struct SwDashStroke diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 53fae90a..15cbf021 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -36,10 +36,8 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s) static inline void SCALE(SwStroke& stroke, SwPoint& pt) { - if (stroke.postScale) { - pt.x = pt.x * stroke.sx; - pt.y = pt.y * stroke.sy; - } + pt.x *= stroke.sx; + pt.y *= stroke.sy; } @@ -548,7 +546,6 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl SwPoint delta = {alen, 0}; mathRotate(delta, beta); - SCALE(stroke, delta); delta += _start; //circumnavigate the negative sector backwards @@ -848,26 +845,14 @@ void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); - auto scale = 1.0f; - if (transform) { - //Fast Track: if x/y scale factor is identical, we can scale width size simply. - auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); - auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); - if (fabsf(sx - sy) < FLT_EPSILON) { - scale = sx; - stroke.postScale = false; - //Try scaling stroke with normal approach. - } else { - stroke.postScale = true; - stroke.sx = sx; - stroke.sy = sy; - } + stroke.sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + stroke.sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); } else { - stroke.postScale = false; + stroke.sx = stroke.sy = 1.0f; } - stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5 * scale); + stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); stroke.cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... From 76a7c900bebceb7735712366cb7571b2fa105874 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 23 Jul 2020 20:56:05 +0900 Subject: [PATCH 176/244] sw_engine gradient: support x/y scale for radial gradient Change-Id: Id725637e261642d0e92d100c73841278b7f44c1c --- src/lib/sw_engine/tvgSwCommon.h | 2 ++ src/lib/sw_engine/tvgSwFill.cpp | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 5f7ec46a..469ce0f1 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -193,6 +193,8 @@ struct SwFill uint32_t* ctable; FillSpread spread; + float sx, sy; + bool translucent; }; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 43514bc4..0ac93833 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -130,12 +130,25 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; if (radius < FLT_EPSILON) return true; + fill->sx = 1.0f; + fill->sy = 1.0f; + if (transform) { auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e13; auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e23; fill->radial.cx = tx; fill->radial.cy = ty; - radius *= transform->e33; + + auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); + + //FIXME; Scale + Rotation is not working properly + radius *= sx; + + if (fabsf(sx - sy) > FLT_EPSILON) { + fill->sx = sx; + fill->sy = sy; + } } fill->radial.a = radius * radius; @@ -190,8 +203,8 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fill->radial.a < FLT_EPSILON) return; //Rotation - auto rx = x + 0.5f - fill->radial.cx; - auto ry = y + 0.5f - fill->radial.cy; + auto rx = (x + 0.5f - fill->radial.cx) * fill->sy; + auto ry = (y + 0.5f - fill->radial.cy) * fill->sx; auto inv2a = fill->radial.inv2a; auto rxy = rx * rx + ry * ry; auto rxryPlus = 2 * rx; From bee94d48fee5c2d17716d63f5b15d79c45feab36 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 24 Jul 2020 21:09:24 +0900 Subject: [PATCH 177/244] sw_engine gradient: support x/y scale for linear gradient Change-Id: Ic58e7cc61a3c90307b6cfb629eb8af69b75fb903 --- src/lib/sw_engine/tvgSwFill.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 0ac93833..266acaa8 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -96,16 +96,18 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; if (transform) { + auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); auto cx = (x2 - x1) * 0.5f + x1; auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->e11 + dy * transform->e12 + transform->e13 + cx; - y1 = dx * transform->e21 + dy * transform->e22 + transform->e23 + cy; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e13 + (cx * sx); + y1 = dx * transform->e21 + dy * transform->e22 + transform->e23 + (cy * sy); dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->e11 + dy * transform->e12 + transform->e13 + cx; - y2 = dx * transform->e21 + dy * transform->e22 + transform->e23 + cy; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e13 + (cx * sx); + y2 = dx * transform->e21 + dy * transform->e22 + transform->e23 + (cy * sy); } fill->linear.dx = x2 - x1; @@ -116,7 +118,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr fill->linear.dx /= fill->linear.len; fill->linear.dy /= fill->linear.len; - fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; + fill->linear.offset = -fill->linear.dx * x1 -fill->linear.dy * y1; return true; } @@ -158,20 +160,23 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr } -static inline uint32_t _clamp(const SwFill* fill, uint32_t pos) +static inline uint32_t _clamp(const SwFill* fill, int32_t pos) { switch (fill->spread) { case FillSpread::Pad: { if (pos >= GRADIENT_STOP_SIZE) pos = GRADIENT_STOP_SIZE - 1; + else if (pos < 0) pos = 0; break; } case FillSpread::Repeat: { + if (pos < 0) pos = GRADIENT_STOP_SIZE + pos; pos = pos % GRADIENT_STOP_SIZE; break; } case FillSpread::Reflect: { auto limit = GRADIENT_STOP_SIZE * 2; pos = pos % limit; + if (pos < 0) pos = limit + pos; if (pos >= GRADIENT_STOP_SIZE) pos = (limit - pos - 1); break; } @@ -180,16 +185,16 @@ static inline uint32_t _clamp(const SwFill* fill, uint32_t pos) } -static inline uint32_t _fixedPixel(const SwFill* fill, uint32_t pos) +static inline uint32_t _fixedPixel(const SwFill* fill, int32_t pos) { - auto i = (pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; + int32_t i = (pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; return fill->ctable[_clamp(fill, i)]; } static inline uint32_t _pixel(const SwFill* fill, float pos) { - auto i = static_cast(pos * (GRADIENT_STOP_SIZE - 1) + 0.5f); + auto i = static_cast(pos * (GRADIENT_STOP_SIZE - 1) + 0.5f); return fill->ctable[_clamp(fill, i)]; } @@ -226,13 +231,13 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fill->linear.len < FLT_EPSILON) return; //Rotation - auto rx = x + 0.5f; - auto ry = y + 0.5f; - auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); - auto inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); + float rx = x + 0.5f; + float ry = y + 0.5f; + float t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); + float inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); if (fabsf(inc) < FLT_EPSILON) { - auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); + auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); rasterARGB32(dst, color, offset, len); return; } From 87a6b5219f4c61ce747f71a76845b0d641917299 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Mon, 27 Jul 2020 14:07:03 +0200 Subject: [PATCH 178/244] capi: Added wrapper for tvg::Shape::scale Change-Id: Ie8380478d9e5bf99c924f3b93cfbb3d80ff55611 --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 7c921841..d7f98ecf 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -140,6 +140,7 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* d TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap cap); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join); TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 6ba0e6da..2e4e8666 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -226,6 +226,11 @@ TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t return (Tvg_Result) reinterpret_cast(paint)->fill(r, g, b, a); } +TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor) +{ + return (Tvg_Result) reinterpret_cast(paint)->scale(factor); +} + #ifdef __cplusplus } #endif \ No newline at end of file From 52ece17fc37f69535f8b0b278fc36e80868b5166 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Mon, 27 Jul 2020 14:08:01 +0200 Subject: [PATCH 179/244] capi: Added wrapper for tvg::Shape::rotate Change-Id: I2cef6600586c037caaf8d2f45fc6d78e93dce925 --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index d7f98ecf..9d32483f 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -141,6 +141,7 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join); TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); +TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 2e4e8666..bd83ccd1 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -231,6 +231,11 @@ TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor) return (Tvg_Result) reinterpret_cast(paint)->scale(factor); } +TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree) +{ + return (Tvg_Result) reinterpret_cast(paint)->rotate(degree); +} + #ifdef __cplusplus } #endif \ No newline at end of file From ba17287419a739a3d2f0fb86d5af7ecb323d727e Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Mon, 27 Jul 2020 14:08:51 +0200 Subject: [PATCH 180/244] capi: Added wrapper for tvg::Shape::translate Change-Id: Idcf672926c489148f15c654f85b4d6c3ff8cde80 --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 9d32483f..efb135b8 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -142,6 +142,7 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Joi TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); +TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index bd83ccd1..5c6fd59d 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -236,6 +236,11 @@ TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree) return (Tvg_Result) reinterpret_cast(paint)->rotate(degree); } +TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y) +{ + return (Tvg_Result) reinterpret_cast(paint)->translate(x, y); +} + #ifdef __cplusplus } #endif \ No newline at end of file From 621d60712684d7f82e9776ff1af07cc566fcf965 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 28 Jul 2020 20:46:11 +0900 Subject: [PATCH 181/244] updated AUTHORS Change-Id: Ia3b91f2dff139b80c5e968be2a0ecb725e6b62bd --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 348597a9..1299d6b8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,3 +2,4 @@ Hermet Park Prudhvi Raj Vasireddi Junsu Choi Pranay Samanta +Mateusz Palkowski From d2d4a2a3e7f959531f69516fb3828b7df7fc84f9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 28 Jul 2020 20:57:18 +0900 Subject: [PATCH 182/244] gl_engine: updated file permission. please keep 664 for files. Change-Id: Iaddd87b0d35a74bc8c6cbf330fecbd28e14ad57a --- src/lib/gl_engine/tvgGlGeometry.cpp | 0 src/lib/gl_engine/tvgGlRenderer.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.cpp diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100755 new mode 100644 From 8a924cbd78a1e019e9af48e4d021963c0942c8d1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 29 Jul 2020 13:40:11 +0900 Subject: [PATCH 183/244] sw_engine: fix out of cell memory. we can adjust cell size if the cell memory is out. the main rle logic missed the exception handling. Change-Id: I4419eefefccafd788729111eafeb65aa4e6a20e9 --- src/lib/sw_engine/tvgSwRle.cpp | 39 ++++++++++++++++------------------ 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 6ee6f7c2..d88a8372 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -625,17 +625,15 @@ invalid_outline: } -static bool _genRle(RleWorker& rw) +static int _genRle(RleWorker& rw) { - bool ret = false; - if (setjmp(rw.jmpBuf) == 0) { - ret = _decomposeOutline(rw); + auto ret = _decomposeOutline(rw); if (!rw.invalid) _recordCell(rw); - } else { - cout << "Lack of Cell Memory" << endl; + if (ret) return 0; //success + else return 1; //fail } - return ret; + return -1; //lack of cell memory } @@ -646,14 +644,9 @@ static bool _genRle(RleWorker& rw) SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias) { - //Please adjust when you out of cell memory (default: 16384L) - constexpr auto RENDER_POOL_SIZE = 163840L * 2; + constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 40; - assert(outline); - assert(outline->cntrs && outline->pts); - assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); - //TODO: We can preserve several static workers in advance RleWorker rw; Cell buffer[RENDER_POOL_SIZE / sizeof(Cell)]; @@ -693,6 +686,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& auto min = rw.cellMin.y; auto yMax = rw.cellMax.y; SwCoord max; + int ret; for (int n = 0; n < bandCnt; ++n, min = max) { max = min + rw.bandSize; @@ -706,8 +700,8 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.yCells = static_cast(rw.buffer); rw.yCnt = band->max - band->min; - auto cellStart = sizeof(Cell*) * (int)rw.yCnt; - auto cellMod = cellStart % sizeof(Cell); + int cellStart = sizeof(Cell*) * (int)rw.yCnt; + int cellMod = cellStart % sizeof(Cell); if (cellMod > 0) cellStart += sizeof(Cell) - cellMod; @@ -722,7 +716,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.maxCells = cellsMax - rw.cells; if (rw.maxCells < 2) goto reduce_bands; - for (auto y = 0; y < rw.yCnt; ++y) + for (int y = 0; y < rw.yCnt; ++y) rw.yCells[y] = nullptr; rw.cellsCnt = 0; @@ -731,11 +725,14 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.cellMax.y = band->max; rw.cellYCnt = band->max - band->min; - if (!_genRle(rw)) goto error; - - _sweep(rw); - --band; - continue; + ret = _genRle(rw); + if (ret == 0) { + _sweep(rw); + --band; + continue; + } else if (ret == 1) { + goto error; + } reduce_bands: /* render pool overflow: we will reduce the render band by half */ From 9e0c4666af8e7411595136853fb30d9a65e3ab7a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 29 Jul 2020 14:25:18 +0900 Subject: [PATCH 184/244] common: revise transform interfaces. transform interfaces are getting duplicated in derived classes. we moved to the super for smaller apis count. Applied strategy pattern to hide the inheritance. Change-Id: I7b0c3ff9317e9bf3c97bb0c849bf55e79ee9a591 --- inc/thorvg.h | 23 +++++-------- src/lib/meson.build | 1 + src/lib/tvgCommon.h | 1 + src/lib/tvgPaint.cpp | 74 ++++++++++++++++++++++++++++++++++++++++ src/lib/tvgPaint.h | 77 ++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgScene.cpp | 57 ++----------------------------- src/lib/tvgSceneImpl.h | 6 ++++ src/lib/tvgShape.cpp | 58 ++----------------------------- src/lib/tvgShapeImpl.h | 6 ++++ 9 files changed, 177 insertions(+), 126 deletions(-) create mode 100644 src/lib/tvgPaint.cpp create mode 100644 src/lib/tvgPaint.h diff --git a/inc/thorvg.h b/inc/thorvg.h index bdca5a20..c8dafafa 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -97,9 +97,16 @@ struct Matrix class TVG_EXPORT Paint { public: - virtual ~Paint() {} + virtual ~Paint(); + + Result rotate(float degree) noexcept; + Result scale(float factor) noexcept; + Result translate(float x, float y) noexcept; + Result transform(const Matrix& m) noexcept; + Result bounds(float* x, float* y, float* w, float* h) const noexcept; _TVG_DECALRE_IDENTIFIER(); + _TVG_DECLARE_PRIVATE(Paint); }; @@ -243,18 +250,11 @@ public: Result fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; Result fill(std::unique_ptr f) noexcept; - //Transform - Result rotate(float degree) noexcept; - Result scale(float factor) noexcept; - Result translate(float x, float y) noexcept; - Result transform(const Matrix& m) noexcept; - //Getters uint32_t pathCommands(const PathCommand** cmds) const noexcept; uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; const Fill* fill() const noexcept; - Result bounds(float* x, float* y, float* w, float* h) const noexcept; float strokeWidth() const noexcept; Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; @@ -287,13 +287,6 @@ public: Result reserve(uint32_t size) noexcept; Result load(const std::string& path) noexcept; - Result rotate(float degree) noexcept; - Result scale(float factor) noexcept; - Result translate(float x, float y) noexcept; - Result transform(const Matrix& m) noexcept; - - Result bounds(float* x, float* y, float* w, float* h) const noexcept; - static std::unique_ptr gen() noexcept; _TVG_DECLARE_ACCESSOR(Canvas); diff --git a/src/lib/meson.build b/src/lib/meson.build index ad022618..64cedbd6 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -27,6 +27,7 @@ source_file = [ 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', 'tvgLoaderMgr.cpp', + 'tvgPaint.cpp', 'tvgRadialGradient.cpp', 'tvgRender.cpp', 'tvgScene.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index ac91f499..3c390b1b 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -43,6 +43,7 @@ using namespace tvg; #include "tvgLoader.h" #include "tvgLoaderMgr.h" #include "tvgRender.h" +#include "tvgPaint.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" #include "tvgSceneImpl.h" diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp new file mode 100644 index 00000000..7eeca198 --- /dev/null +++ b/src/lib/tvgPaint.cpp @@ -0,0 +1,74 @@ +/* + * 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_PAINT_CPP_ +#define _TVG_PAINT_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +Paint :: Paint() : pImpl(make_unique()) +{ +} + + +Paint :: ~Paint() +{ +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +Result Paint::rotate(float degree) noexcept +{ + if (pImpl.get()->ts->rotate(degree)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::scale(float factor) noexcept +{ + if (pImpl.get()->ts->scale(factor)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::translate(float x, float y) noexcept +{ + if (pImpl.get()->ts->translate(x, y)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::transform(const Matrix& m) noexcept +{ + if (pImpl.get()->ts->transform(m)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept +{ + if (pImpl.get()->ts->bounds(x, y, w, h)) return Result::Success; + return Result::InsufficientCondition; +} + +#endif //_TVG_PAINT_CPP_ \ No newline at end of file diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h new file mode 100644 index 00000000..cd0933b0 --- /dev/null +++ b/src/lib/tvgPaint.h @@ -0,0 +1,77 @@ +/* + * 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_PAINT_H_ +#define _TVG_PAINT_H_ + +namespace tvg +{ + struct ITransformMethod + { + virtual ~ITransformMethod(){} + virtual bool rotate(float degree) = 0; + virtual bool scale(float factor) = 0; + virtual bool translate(float x, float y) = 0; + virtual bool transform(const Matrix& m) = 0; + virtual bool bounds(float* x, float* y, float* w, float* h) const = 0; + }; + + struct Paint::Impl + { + ITransformMethod* ts = nullptr; + + ~Impl() { + if (ts) delete(ts); + } + }; + + + template + struct TransformMethod : ITransformMethod + { + T* _inst = nullptr; + + TransformMethod(T* inst) : _inst(inst) {} + ~TransformMethod(){} + + bool rotate(float degree) override + { + return _inst->rotate(degree); + } + + bool scale(float factor) override + { + return _inst->scale(factor); + } + + bool translate(float x, float y) override + { + return _inst->translate(x, y); + } + + bool transform(const Matrix& m) override + { + return _inst->transform(m); + } + + bool bounds(float* x, float* y, float* w, float* h) const override + { + return _inst->bounds(x, y, w, h); + } + }; +} + +#endif //_TVG_PAINT_H_ \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 1980d96a..78ca868b 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -26,6 +26,8 @@ Scene::Scene() : pImpl(make_unique()) { _id = PAINT_ID_SCENE; + + Paint::pImpl.get()->ts = pImpl.get()->transformMethod(); } @@ -64,61 +66,6 @@ Result Scene::reserve(uint32_t size) noexcept } -Result Scene::scale(float factor) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->scale(factor)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::rotate(float degree) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->rotate(degree)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::translate(float x, float y) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->translate(x, y)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::transform(const Matrix& m) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->transform(m)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - - return Result::Success; -} - - Result Scene::load(const std::string& path) noexcept { if (path.empty()) return Result::InvalidArguments; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 9972d72f..08b42d36 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -231,6 +231,12 @@ struct Scene::Impl if (!loader->read()) return Result::Unknown; return Result::Success; } + + ITransformMethod* transformMethod() + { + return new TransformMethod(this); + } + }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 36aefedd..c822f942 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -25,7 +25,6 @@ /************************************************************************/ constexpr auto PATH_KAPPA = 0.552284f; - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -33,6 +32,8 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { _id = PAINT_ID_SHAPE; + + Paint::pImpl.get()->ts = pImpl.get()->transformMethod(); } @@ -280,61 +281,6 @@ const Fill* Shape::fill() const noexcept } -Result Shape::scale(float factor) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->scale(factor)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::rotate(float degree) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->rotate(degree)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::translate(float x, float y) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->translate(x, y)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::transform(const Matrix& m) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->transform(m)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::bounds(float* x, float* y, float* w, float* h) const noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - - return Result::Success; -} - - Result Shape::stroke(float width) noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 54d37a3b..c38916a6 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -235,6 +235,12 @@ struct Shape::Impl return true; } + + + ITransformMethod* transformMethod() + { + return new TransformMethod(this); + } }; #endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file From cd699738b60a2d128e0f1c4fceeab3ef9aadb009 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Wed, 29 Jul 2020 12:23:18 +0200 Subject: [PATCH 185/244] capi: Added wrapper for tvg::Shape::transform (fixed) Change-Id: Ibbb867e828a07af90f38ed506894d026004fa53d --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index efb135b8..96724dc8 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -143,6 +143,7 @@ TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y); +TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 5c6fd59d..1972bd09 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -241,6 +241,11 @@ TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y) return (Tvg_Result) reinterpret_cast(paint)->translate(x, y); } +TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m) +{ + return (Tvg_Result) reinterpret_cast(paint)->transform(*(reinterpret_cast(m))); +} + #ifdef __cplusplus } #endif \ No newline at end of file From afc7bc8c2fcbf978940afa2c5ffe25dc4896ed9e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 29 Jul 2020 19:47:28 +0900 Subject: [PATCH 186/244] common: code refactoring remove exceptional handling which is inevitable scenario. Change-Id: I761a59a38f4578291ee8bc044c5ca989feedbe79 --- src/lib/tvgCanvas.cpp | 29 ++------ src/lib/tvgCommon.h | 1 + src/lib/tvgFill.cpp | 18 ++--- src/lib/tvgLinearGradient.cpp | 22 +++--- src/lib/tvgPaint.cpp | 10 +-- src/lib/tvgRadialGradient.cpp | 21 ++---- src/lib/tvgScene.cpp | 15 +--- src/lib/tvgShape.cpp | 124 +++++++++------------------------- 8 files changed, 67 insertions(+), 173 deletions(-) diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 01fcae1f..d110aee5 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -36,59 +36,44 @@ Canvas::~Canvas() Result Canvas::reserve(uint32_t n) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - impl->paints.reserve(n); + IMPL->paints.reserve(n); return Result::Success; } Result Canvas::push(unique_ptr paint) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - return impl->push(move(paint)); + return IMPL->push(move(paint)); } Result Canvas::clear() noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - return impl->clear(); + return IMPL->clear(); } Result Canvas::draw(bool async) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - return impl->draw(); + return IMPL->draw(); } Result Canvas::update() noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - return impl->update(); + return IMPL->update(); } Result Canvas::update(Paint* paint) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - return impl->update(paint); + return IMPL->update(paint); } Result Canvas::sync() noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (impl->renderer->flush()) return Result::Success; + if (IMPL->renderer->flush()) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 3c390b1b..2e5bd132 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -30,6 +30,7 @@ using namespace std; using namespace tvg; +#define IMPL pImpl.get() #define SCENE_IMPL scene->pImpl.get() #define SHAPE_IMPL shape->pImpl.get() diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp index bfef7a6d..fe3ef3f7 100644 --- a/src/lib/tvgFill.cpp +++ b/src/lib/tvgFill.cpp @@ -54,7 +54,6 @@ Fill::~Fill() Result Fill::colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept { auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; if (cnt == 0) { if (impl->colorStops) { @@ -78,21 +77,15 @@ Result Fill::colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept { - auto impl = pImpl.get(); - if (!impl) return 0; + if (colorStops) *colorStops = IMPL->colorStops; - if (colorStops) *colorStops = impl->colorStops; - - return impl->cnt; + return IMPL->cnt; } Result Fill::spread(FillSpread s) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - impl->spread = s; + IMPL->spread = s; return Result::Success; } @@ -100,10 +93,7 @@ Result Fill::spread(FillSpread s) noexcept FillSpread Fill::spread() const noexcept { - auto impl = pImpl.get(); - assert(impl); - - return impl->spread; + return IMPL->spread; } #endif /* _TVG_FILL_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp index 4499454f..88be20cb 100644 --- a/src/lib/tvgLinearGradient.cpp +++ b/src/lib/tvgLinearGradient.cpp @@ -49,13 +49,10 @@ Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept if (fabsf(x2 - x1) < FLT_EPSILON && fabsf(y2 - y1) < FLT_EPSILON) return Result::InvalidArguments; - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - impl->x1 = x1; - impl->y1 = y1; - impl->x2 = x2; - impl->y2 = y2; + IMPL->x1 = x1; + IMPL->y1 = y1; + IMPL->x2 = x2; + IMPL->y2 = y2; return Result::Success; } @@ -63,13 +60,10 @@ Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (x1) *x1 = impl->x1; - if (x2) *x2 = impl->x2; - if (y1) *y1 = impl->y1; - if (y2) *y2 = impl->y2; + if (x1) *x1 = IMPL->x1; + if (x2) *x2 = IMPL->x2; + if (y1) *y1 = IMPL->y1; + if (y2) *y2 = IMPL->y2; return Result::Success; } diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 7eeca198..b33b764d 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -39,35 +39,35 @@ Paint :: ~Paint() Result Paint::rotate(float degree) noexcept { - if (pImpl.get()->ts->rotate(degree)) return Result::Success; + if (IMPL->ts->rotate(degree)) return Result::Success; return Result::FailedAllocation; } Result Paint::scale(float factor) noexcept { - if (pImpl.get()->ts->scale(factor)) return Result::Success; + if (IMPL->ts->scale(factor)) return Result::Success; return Result::FailedAllocation; } Result Paint::translate(float x, float y) noexcept { - if (pImpl.get()->ts->translate(x, y)) return Result::Success; + if (IMPL->ts->translate(x, y)) return Result::Success; return Result::FailedAllocation; } Result Paint::transform(const Matrix& m) noexcept { - if (pImpl.get()->ts->transform(m)) return Result::Success; + if (IMPL->ts->transform(m)) return Result::Success; return Result::FailedAllocation; } Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept { - if (pImpl.get()->ts->bounds(x, y, w, h)) return Result::Success; + if (IMPL->ts->bounds(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp index 895cccb2..154e1631 100644 --- a/src/lib/tvgRadialGradient.cpp +++ b/src/lib/tvgRadialGradient.cpp @@ -46,15 +46,11 @@ RadialGradient::~RadialGradient() Result RadialGradient::radial(float cx, float cy, float radius) noexcept { - if (radius < FLT_EPSILON) - return Result::InvalidArguments; + if (radius < FLT_EPSILON) return Result::InvalidArguments; - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - impl->cx = cx; - impl->cy = cy; - impl->radius = radius; + IMPL->cx = cx; + IMPL->cy = cy; + IMPL->radius = radius; return Result::Success; } @@ -62,12 +58,9 @@ Result RadialGradient::radial(float cx, float cy, float radius) noexcept Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (cx) *cx = impl->cx; - if (cy) *cy = impl->cy; - if (radius) *radius = impl->radius; + if (cx) *cx = IMPL->cx; + if (cy) *cy = IMPL->cy; + if (radius) *radius = IMPL->radius; return Result::Success; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 78ca868b..adbbe092 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -44,12 +44,9 @@ unique_ptr Scene::gen() noexcept Result Scene::push(unique_ptr paint) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - auto p = paint.release(); if (!p) return Result::MemoryCorruption; - impl->paints.push_back(p); + IMPL->paints.push_back(p); return Result::Success; } @@ -57,10 +54,7 @@ Result Scene::push(unique_ptr paint) noexcept Result Scene::reserve(uint32_t size) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - impl->paints.reserve(size); + IMPL->paints.reserve(size); return Result::Success; } @@ -70,10 +64,7 @@ Result Scene::load(const std::string& path) noexcept { if (path.empty()) return Result::InvalidArguments; - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - return impl->load(path); + return IMPL->load(path); } #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index c822f942..ddd3ef0f 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -50,12 +50,9 @@ unique_ptr Shape::gen() noexcept Result Shape::reset() noexcept { - auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; + IMPL->path->reset(); - impl->path->reset(); - - impl->flag |= RenderUpdateFlag::Path; + IMPL->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -65,12 +62,9 @@ uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { if (!cmds) return 0; - auto impl = pImpl.get(); - if (!impl || !impl->path) return 0; + *cmds = IMPL->path->cmds; - *cmds = impl->path->cmds; - - return impl->path->cmdCnt; + return IMPL->path->cmdCnt; } @@ -78,12 +72,9 @@ uint32_t Shape::pathCoords(const Point** pts) const noexcept { if (!pts) return 0; - auto impl = pImpl.get(); - if (!impl || !impl->path) return 0; + *pts = IMPL->path->pts; - *pts = impl->path->pts; - - return impl->path->ptsCnt; + return IMPL->path->ptsCnt; } @@ -91,13 +82,10 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* { if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments; - auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; + IMPL->path->grow(cmdCnt, ptsCnt); + IMPL->path->append(cmds, cmdCnt, pts, ptsCnt); - impl->path->grow(cmdCnt, ptsCnt); - impl->path->append(cmds, cmdCnt, pts, ptsCnt); - - impl->flag |= RenderUpdateFlag::Path; + IMPL->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -105,12 +93,9 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* Result Shape::moveTo(float x, float y) noexcept { - auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; + IMPL->path->moveTo(x, y); - impl->path->moveTo(x, y); - - impl->flag |= RenderUpdateFlag::Path; + IMPL->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -118,12 +103,9 @@ Result Shape::moveTo(float x, float y) noexcept Result Shape::lineTo(float x, float y) noexcept { - auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; + IMPL->path->lineTo(x, y); - impl->path->lineTo(x, y); - - impl->flag |= RenderUpdateFlag::Path; + IMPL->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -131,12 +113,9 @@ Result Shape::lineTo(float x, float y) noexcept Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { - auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; + IMPL->path->cubicTo(cx1, cy1, cx2, cy2, x, y); - impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); - - impl->flag |= RenderUpdateFlag::Path; + IMPL->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -144,12 +123,9 @@ Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float Result Shape::close() noexcept { - auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; + IMPL->path->close(); - impl->path->close(); - - impl->flag |= RenderUpdateFlag::Path; + IMPL->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -158,7 +134,6 @@ Result Shape::close() noexcept Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept { auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; auto rxKappa = rx * PATH_KAPPA; auto ryKappa = ry * PATH_KAPPA; @@ -180,7 +155,6 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) noexcept { auto impl = pImpl.get(); - if (!impl || !impl->path) return Result::MemoryCorruption; auto halfW = w * 0.5f; auto halfH = h * 0.5f; @@ -225,7 +199,6 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; impl->color[0] = r; impl->color[1] = g; @@ -246,7 +219,6 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept Result Shape::fill(unique_ptr f) noexcept { auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; auto p = f.release(); if (!p) return Result::MemoryCorruption; @@ -262,7 +234,6 @@ Result Shape::fill(unique_ptr f) noexcept Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; if (r) *r = impl->color[0]; if (g) *g = impl->color[1]; @@ -274,19 +245,13 @@ Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcep const Fill* Shape::fill() const noexcept { - auto impl = pImpl.get(); - if (!impl) return nullptr; - - return impl->fill; + return IMPL->fill; } Result Shape::stroke(float width) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->strokeWidth(width)) return Result::FailedAllocation; + if (!IMPL->strokeWidth(width)) return Result::FailedAllocation; return Result::Success; } @@ -294,20 +259,14 @@ Result Shape::stroke(float width) noexcept float Shape::strokeWidth() const noexcept { - auto impl = pImpl.get(); - if (!impl) return 0; - - if (!impl->stroke) return 0; - return impl->stroke->width; + if (!IMPL->stroke) return 0; + return IMPL->stroke->width; } Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->strokeColor(r, g, b, a)) return Result::FailedAllocation; + if (!IMPL->strokeColor(r, g, b, a)) return Result::FailedAllocation; return Result::Success; } @@ -316,7 +275,6 @@ Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; if (!impl->stroke) return Result::InsufficientCondition; @@ -333,10 +291,7 @@ Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept { if (cnt < 2 || !dashPattern) return Result::InvalidArguments; - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->strokeDash(dashPattern, cnt)) return Result::FailedAllocation; + if (!IMPL->strokeDash(dashPattern, cnt)) return Result::FailedAllocation; return Result::Success; } @@ -344,22 +299,16 @@ Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept uint32_t Shape::strokeDash(const float** dashPattern) const noexcept { - auto impl = pImpl.get(); - assert(impl); + if (!IMPL->stroke) return 0; - if (!impl->stroke) return 0; - - if (dashPattern) *dashPattern = impl->stroke->dashPattern; - return impl->stroke->dashCnt; + if (dashPattern) *dashPattern = IMPL->stroke->dashPattern; + return IMPL->stroke->dashCnt; } Result Shape::stroke(StrokeCap cap) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->strokeCap(cap)) return Result::FailedAllocation; + if (!IMPL->strokeCap(cap)) return Result::FailedAllocation; return Result::Success; } @@ -367,10 +316,7 @@ Result Shape::stroke(StrokeCap cap) noexcept Result Shape::stroke(StrokeJoin join) noexcept { - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->strokeJoin(join)) return Result::FailedAllocation; + if (!IMPL->strokeJoin(join)) return Result::FailedAllocation; return Result::Success; } @@ -378,23 +324,17 @@ Result Shape::stroke(StrokeJoin join) noexcept StrokeCap Shape::strokeCap() const noexcept { - auto impl = pImpl.get(); - assert(impl); + if (!IMPL->stroke) return StrokeCap::Square; - if (!impl->stroke) return StrokeCap::Square; - - return impl->stroke->cap; + return IMPL->stroke->cap; } StrokeJoin Shape::strokeJoin() const noexcept { - auto impl = pImpl.get(); - assert(impl); + if (!IMPL->stroke) return StrokeJoin::Bevel; - if (!impl->stroke) return StrokeJoin::Bevel; - - return impl->stroke->join; + return IMPL->stroke->join; } From 8ed9edd33e4c167f9f6b51cac6588511e796130c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 29 Jul 2020 20:41:34 +0900 Subject: [PATCH 187/244] common: code refactoring keep consistency of internal functions among the paint type methods. Change-Id: I98a42ac398ddc5aaf49ac59e5cbb1790266bd612 --- src/lib/tvgCanvasImpl.h | 14 +++++++------- src/lib/tvgSceneImpl.h | 12 ++++++------ src/lib/tvgShape.cpp | 2 +- src/lib/tvgShapeImpl.h | 17 +++++++++-------- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 94737c92..5960f02c 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -59,10 +59,10 @@ struct Canvas::Impl if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); - if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; + if (!SCENE_IMPL->dispose(*renderer)) return Result::InsufficientCondition; } else { auto shape = static_cast(paint); - if (!SHAPE_IMPL->dispose(*shape, *renderer)) return Result::InsufficientCondition; + if (!SHAPE_IMPL->dispose(*renderer)) return Result::InsufficientCondition; } delete(paint); } @@ -79,10 +79,10 @@ struct Canvas::Impl if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); - if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; + if (!SCENE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; } else { auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return Result::InsufficientCondition; + if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; } } return Result::Success; @@ -95,10 +95,10 @@ struct Canvas::Impl if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); - if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; + if (!SCENE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; } else { auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(*shape, *renderer)) return Result::InsufficientCondition; + if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; } return Result::Success; } @@ -116,7 +116,7 @@ struct Canvas::Impl if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; } else { auto shape = static_cast(paint); - if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; + if(!SHAPE_IMPL->render(*renderer)) return Result::InsufficientCondition; } } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 08b42d36..b8d71f24 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -37,16 +37,16 @@ struct Scene::Impl if (rTransform) delete(rTransform); } - bool clear(RenderMethod& renderer) + bool dispose(RenderMethod& renderer) { for (auto paint : paints) { if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); - if (!SCENE_IMPL->clear(renderer)) return false; + if (!SCENE_IMPL->dispose(renderer)) return false; } else { auto shape = static_cast(paint); - if (!SHAPE_IMPL->dispose(*shape, renderer)) return false; + if (!SHAPE_IMPL->dispose(renderer)) return false; } delete(paint); } @@ -64,13 +64,13 @@ struct Scene::Impl if (!SCENE_IMPL->update(renderer, transform, flag)) return false; } else { auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(*shape, renderer, transform, flag)) return false; + if (!SHAPE_IMPL->update(renderer, transform, flag)) return false; } } return true; } - bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) + bool update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t pFlag) { if (loader) { auto scene = loader->data(); @@ -114,7 +114,7 @@ struct Scene::Impl if(!SCENE_IMPL->render(renderer)) return false; } else { auto shape = static_cast(paint); - if(!SHAPE_IMPL->render(*shape, renderer)) return false; + if(!SHAPE_IMPL->render(renderer)) return false; } } return true; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index ddd3ef0f..648c0eed 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -29,7 +29,7 @@ constexpr auto PATH_KAPPA = 0.552284f; /* External Class Implementation */ /************************************************************************/ -Shape :: Shape() : pImpl(make_unique()) +Shape :: Shape() : pImpl(make_unique(this)) { _id = PAINT_ID_SHAPE; diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index c38916a6..b733bd52 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -48,9 +48,10 @@ struct Shape::Impl uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a uint32_t flag = RenderUpdateFlag::None; void *edata = nullptr; //engine data + Shape *shape = nullptr; - Impl() : path(new ShapePath) + Impl(Shape* s) : path(new ShapePath), shape(s) { } @@ -62,17 +63,17 @@ struct Shape::Impl if (rTransform) delete(rTransform); } - bool dispose(Shape& shape, RenderMethod& renderer) + bool dispose(RenderMethod& renderer) { - return renderer.dispose(shape, edata); + return renderer.dispose(*shape, edata); } - bool render(Shape& shape, RenderMethod& renderer) + bool render(RenderMethod& renderer) { - return renderer.render(shape, edata); + return renderer.render(*shape, edata); } - bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) + bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) { if (flag & RenderUpdateFlag::Transform) { if (!rTransform) return false; @@ -84,10 +85,10 @@ struct Shape::Impl if (rTransform && pTransform) { RenderTransform outTransform(pTransform, rTransform); - edata = renderer.prepare(shape, edata, &outTransform, static_cast(pFlag | flag)); + edata = renderer.prepare(*shape, edata, &outTransform, static_cast(pFlag | flag)); } else { auto outTransform = pTransform ? pTransform : rTransform; - edata = renderer.prepare(shape, edata, outTransform, static_cast(pFlag | flag)); + edata = renderer.prepare(*shape, edata, outTransform, static_cast(pFlag | flag)); } flag = RenderUpdateFlag::None; From 80d47fd7d342828ab06bc710ee234514552f9fbb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Jul 2020 13:40:18 +0900 Subject: [PATCH 188/244] common: revise canvas interfaces. 1. removed async option which doesn't work currently, rather than it, we can add async option in initiailizer class. 2. removed update() method. Instead, we can call update(paint = nullptr); which has exactly same behavior. Change-Id: I7909a50d804b97baf413a2ff6365a3cf79a3689e --- inc/thorvg.h | 3 +-- inc/thorvg_capi.h | 2 +- src/bindings/capi/tvgCapi.cpp | 6 +++--- src/lib/tvgCanvas.cpp | 8 +------- src/lib/tvgCanvasImpl.h | 30 ++++++++++++++---------------- test/testCapi.c | 2 +- 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index c8dafafa..6475890e 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -157,9 +157,8 @@ public: Result reserve(uint32_t n) noexcept; virtual Result push(std::unique_ptr paint) noexcept; virtual Result clear() noexcept; - virtual Result update() noexcept; virtual Result update(Paint* paint) noexcept; - virtual Result draw(bool async = true) noexcept; + virtual Result draw() noexcept; virtual Result sync() noexcept; _TVG_DECLARE_ACCESSOR(Scene); diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index efb135b8..7189599b 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -117,7 +117,7 @@ TVG_EXPORT Tvg_Result tvg_canvas_reserve(Tvg_Canvas* canvas, uint32_t n); TVG_EXPORT Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas); TVG_EXPORT Tvg_Result tvg_canvas_update(Tvg_Canvas* canvas); TVG_EXPORT Tvg_Result tvg_canvas_update_paint(Tvg_Canvas* canvas, Tvg_Paint* paint); -TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas, unsigned char async); +TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas); TVG_EXPORT Tvg_Result tvg_canvas_sync(Tvg_Canvas* canvas); diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 5c6fd59d..55fdecc7 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -104,7 +104,7 @@ TVG_EXPORT Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas) TVG_EXPORT Tvg_Result tvg_canvas_update(Tvg_Canvas* canvas) { - return (Tvg_Result) reinterpret_cast(canvas)->update(); + return (Tvg_Result) reinterpret_cast(canvas)->update(nullptr); } @@ -114,9 +114,9 @@ TVG_EXPORT Tvg_Result tvg_canvas_update_paint(Tvg_Canvas* canvas, Tvg_Paint* pai } -TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas, unsigned char async) +TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas) { - return (Tvg_Result) reinterpret_cast(canvas)->draw(async); + return (Tvg_Result) reinterpret_cast(canvas)->draw(); } diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index d110aee5..e9db4610 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -53,18 +53,12 @@ Result Canvas::clear() noexcept } -Result Canvas::draw(bool async) noexcept +Result Canvas::draw() noexcept { return IMPL->draw(); } -Result Canvas::update() noexcept -{ - return IMPL->update(); -} - - Result Canvas::update(Paint* paint) noexcept { return IMPL->update(paint); diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 5960f02c..77af3d57 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -71,11 +71,12 @@ struct Canvas::Impl return Result::Success; } - Result update() + Result update(Paint* paint) { if (!renderer) return Result::InsufficientCondition; - for(auto paint: paints) { + //Update single paint node + if (paint) { if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); @@ -84,21 +85,18 @@ struct Canvas::Impl auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; } - } - return Result::Success; - } - - Result update(Paint* paint) - { - if (!renderer) return Result::InsufficientCondition; - - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; + //Update retained all paint nodes } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; + for(auto paint: paints) { + if (paint->id() == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); + if (!SCENE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; + } else { + auto shape = static_cast(paint); + if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; + } + } } return Result::Success; } diff --git a/test/testCapi.c b/test/testCapi.c index 5b8b91bc..6a46e97e 100644 --- a/test/testCapi.c +++ b/test/testCapi.c @@ -26,7 +26,7 @@ void testCapi() tvg_shape_fill_color(shape, 255, 255, 0, 255); tvg_canvas_push(canvas, shape); - tvg_canvas_draw(canvas, 1); + tvg_canvas_draw(canvas); tvg_canvas_sync(canvas); tvg_canvas_destroy(canvas); From 8dca270a30d3ad116ee34fbacfd4026fbb9501a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Jul 2020 14:47:04 +0900 Subject: [PATCH 189/244] common: code refactoring for simplicity. Introduce internal PaintMethod since there more derived paint classes are coming. This PaintMethod is a sort of Strategy Pattern method. Change-Id: I29c49f5d4ddbfb9e429d4976636b20b39914ee20 --- inc/thorvg.h | 7 ++----- src/lib/tvgCanvasImpl.h | 36 ++++++--------------------------- src/lib/tvgCommon.h | 3 --- src/lib/tvgPaint.cpp | 10 ++++----- src/lib/tvgPaint.h | 45 ++++++++++++++++++++++++++++++----------- src/lib/tvgScene.cpp | 4 +--- src/lib/tvgSceneImpl.h | 38 +++++----------------------------- src/lib/tvgShape.cpp | 4 +--- src/lib/tvgShapeImpl.h | 2 +- 9 files changed, 54 insertions(+), 95 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 6475890e..36fed956 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -105,8 +105,9 @@ public: Result transform(const Matrix& m) noexcept; Result bounds(float* x, float* y, float* w, float* h) const noexcept; - _TVG_DECALRE_IDENTIFIER(); _TVG_DECLARE_PRIVATE(Paint); + _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_ACCESSOR(Scene); }; @@ -161,7 +162,6 @@ public: virtual Result draw() noexcept; virtual Result sync() noexcept; - _TVG_DECLARE_ACCESSOR(Scene); _TVG_DECLARE_PRIVATE(Canvas); }; @@ -264,8 +264,6 @@ public: static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(Shape); - _TVG_DECLARE_ACCESSOR(Canvas); - _TVG_DECLARE_ACCESSOR(Scene); }; @@ -288,7 +286,6 @@ public: static std::unique_ptr gen() noexcept; - _TVG_DECLARE_ACCESSOR(Canvas); _TVG_DECLARE_PRIVATE(Scene); }; diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 77af3d57..a1b9b784 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -56,14 +56,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for (auto paint : paints) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->dispose(*renderer)) return Result::InsufficientCondition; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->dispose(*renderer)) return Result::InsufficientCondition; - } + paint->IMPL->method->dispose(*renderer); delete(paint); } paints.clear(); @@ -77,24 +70,14 @@ struct Canvas::Impl //Update single paint node if (paint) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; + if (!paint->IMPL->method->update(*renderer, nullptr, RenderUpdateFlag::None)) { + return Result::InsufficientCondition; } //Update retained all paint nodes } else { for(auto paint: paints) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) return Result::InsufficientCondition; + if (!paint->IMPL->method->update(*renderer, nullptr, RenderUpdateFlag::None)) { + return Result::InsufficientCondition; } } } @@ -108,14 +91,7 @@ struct Canvas::Impl if (!renderer->preRender()) return Result::InsufficientCondition; for(auto paint: paints) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; - } else { - auto shape = static_cast(paint); - if(!SHAPE_IMPL->render(*renderer)) return Result::InsufficientCondition; - } + if(!paint->IMPL->method->render(*renderer)) return Result::InsufficientCondition; } if (!renderer->postRender()) return Result::InsufficientCondition; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2e5bd132..4cec18fe 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -34,9 +34,6 @@ using namespace tvg; #define SCENE_IMPL scene->pImpl.get() #define SHAPE_IMPL shape->pImpl.get() -#define PAINT_ID_SHAPE 0 -#define PAINT_ID_SCENE 1 - #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index b33b764d..cbd68c62 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -39,35 +39,35 @@ Paint :: ~Paint() Result Paint::rotate(float degree) noexcept { - if (IMPL->ts->rotate(degree)) return Result::Success; + if (IMPL->method->rotate(degree)) return Result::Success; return Result::FailedAllocation; } Result Paint::scale(float factor) noexcept { - if (IMPL->ts->scale(factor)) return Result::Success; + if (IMPL->method->scale(factor)) return Result::Success; return Result::FailedAllocation; } Result Paint::translate(float x, float y) noexcept { - if (IMPL->ts->translate(x, y)) return Result::Success; + if (IMPL->method->translate(x, y)) return Result::Success; return Result::FailedAllocation; } Result Paint::transform(const Matrix& m) noexcept { - if (IMPL->ts->transform(m)) return Result::Success; + if (IMPL->method->transform(m)) return Result::Success; return Result::FailedAllocation; } Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept { - if (IMPL->ts->bounds(x, y, w, h)) return Result::Success; + if (IMPL->method->bounds(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index cd0933b0..31dcbf47 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -19,57 +19,78 @@ namespace tvg { - struct ITransformMethod + struct PaintMethod { - virtual ~ITransformMethod(){} + virtual ~PaintMethod(){} + + virtual bool dispose(RenderMethod& renderer) = 0; + virtual bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) = 0; + virtual bool render(RenderMethod& renderer) = 0; + virtual bool rotate(float degree) = 0; virtual bool scale(float factor) = 0; virtual bool translate(float x, float y) = 0; virtual bool transform(const Matrix& m) = 0; virtual bool bounds(float* x, float* y, float* w, float* h) const = 0; + }; struct Paint::Impl { - ITransformMethod* ts = nullptr; + PaintMethod* method = nullptr; ~Impl() { - if (ts) delete(ts); + if (method) delete(method); } }; template - struct TransformMethod : ITransformMethod + struct TransformMethod : PaintMethod { - T* _inst = nullptr; + T* inst = nullptr; - TransformMethod(T* inst) : _inst(inst) {} + TransformMethod(T* inst) : inst(_inst) {} ~TransformMethod(){} bool rotate(float degree) override { - return _inst->rotate(degree); + return inst->rotate(degree); } bool scale(float factor) override { - return _inst->scale(factor); + return inst->scale(factor); } bool translate(float x, float y) override { - return _inst->translate(x, y); + return inst->translate(x, y); } bool transform(const Matrix& m) override { - return _inst->transform(m); + return inst->transform(m); } bool bounds(float* x, float* y, float* w, float* h) const override { - return _inst->bounds(x, y, w, h); + return inst->bounds(x, y, w, h); + } + + bool dispose(RenderMethod& renderer) + { + return inst->dispose(renderer); + } + + bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) + { + return inst->update(renderer, pTransform, pFlag); + } + + bool render(RenderMethod& renderer) + { + return inst->render(renderer); } }; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index adbbe092..4d043646 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,9 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - _id = PAINT_ID_SCENE; - - Paint::pImpl.get()->ts = pImpl.get()->transformMethod(); + Paint::IMPL->method = IMPL->transformMethod(); } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index b8d71f24..bd497144 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -40,14 +40,7 @@ struct Scene::Impl bool dispose(RenderMethod& renderer) { for (auto paint : paints) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->dispose(renderer)) return false; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->dispose(renderer)) return false; - } + paint->IMPL->method->dispose(renderer); delete(paint); } paints.clear(); @@ -58,14 +51,7 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->update(renderer, transform, flag)) return false; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->update(renderer, transform, flag)) return false; - } + if (!paint->IMPL->method->update(renderer, transform, flag)) return false; } return true; } @@ -108,14 +94,7 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if(!SCENE_IMPL->render(renderer)) return false; - } else { - auto shape = static_cast(paint); - if(!SHAPE_IMPL->render(renderer)) return false; - } + if(!paint->IMPL->method->render(renderer)) return false; } return true; } @@ -139,14 +118,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->id() == PAINT_ID_SCENE) { - //We know renderer type, avoid dynamic_cast for performance. - auto scene = static_cast(paint); - if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; - } + if (paint->IMPL->method->bounds(&x2, &y2, &w2, &h2)) return false; //Merge regions if (x2 < x) x = x2; @@ -232,7 +204,7 @@ struct Scene::Impl return Result::Success; } - ITransformMethod* transformMethod() + PaintMethod* transformMethod() { return new TransformMethod(this); } diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 648c0eed..f42c1605 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -31,9 +31,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique(this)) { - _id = PAINT_ID_SHAPE; - - Paint::pImpl.get()->ts = pImpl.get()->transformMethod(); + Paint::IMPL->method = IMPL->transformMethod(); } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index b733bd52..955deb64 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -238,7 +238,7 @@ struct Shape::Impl } - ITransformMethod* transformMethod() + PaintMethod* transformMethod() { return new TransformMethod(this); } From 39b77361c5598c90faa32222b996f90756521600 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Jul 2020 15:10:59 +0900 Subject: [PATCH 190/244] common: code refactoring. changed just internal variable & method names. no logical changes. Change-Id: I01782ec59dec3ff2232e03de7b3863100d9cc27f --- src/lib/tvgCanvasImpl.h | 8 ++++---- src/lib/tvgPaint.cpp | 10 +++++----- src/lib/tvgPaint.h | 24 +++++++++++++++++------- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 14 ++++---------- src/lib/tvgShape.cpp | 2 +- src/lib/tvgShapeImpl.h | 6 ------ 7 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index a1b9b784..27767350 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -56,7 +56,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for (auto paint : paints) { - paint->IMPL->method->dispose(*renderer); + paint->IMPL->method()->dispose(*renderer); delete(paint); } paints.clear(); @@ -70,13 +70,13 @@ struct Canvas::Impl //Update single paint node if (paint) { - if (!paint->IMPL->method->update(*renderer, nullptr, RenderUpdateFlag::None)) { + if (!paint->IMPL->method()->update(*renderer, nullptr, RenderUpdateFlag::None)) { return Result::InsufficientCondition; } //Update retained all paint nodes } else { for(auto paint: paints) { - if (!paint->IMPL->method->update(*renderer, nullptr, RenderUpdateFlag::None)) { + if (!paint->IMPL->method()->update(*renderer, nullptr, RenderUpdateFlag::None)) { return Result::InsufficientCondition; } } @@ -91,7 +91,7 @@ struct Canvas::Impl if (!renderer->preRender()) return Result::InsufficientCondition; for(auto paint: paints) { - if(!paint->IMPL->method->render(*renderer)) return Result::InsufficientCondition; + if(!paint->IMPL->method()->render(*renderer)) return Result::InsufficientCondition; } if (!renderer->postRender()) return Result::InsufficientCondition; diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index cbd68c62..8aa62d20 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -39,35 +39,35 @@ Paint :: ~Paint() Result Paint::rotate(float degree) noexcept { - if (IMPL->method->rotate(degree)) return Result::Success; + if (IMPL->method()->rotate(degree)) return Result::Success; return Result::FailedAllocation; } Result Paint::scale(float factor) noexcept { - if (IMPL->method->scale(factor)) return Result::Success; + if (IMPL->method()->scale(factor)) return Result::Success; return Result::FailedAllocation; } Result Paint::translate(float x, float y) noexcept { - if (IMPL->method->translate(x, y)) return Result::Success; + if (IMPL->method()->translate(x, y)) return Result::Success; return Result::FailedAllocation; } Result Paint::transform(const Matrix& m) noexcept { - if (IMPL->method->transform(m)) return Result::Success; + if (IMPL->method()->transform(m)) return Result::Success; return Result::FailedAllocation; } Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept { - if (IMPL->method->bounds(x, y, w, h)) return Result::Success; + if (IMPL->method()->bounds(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 31dcbf47..45e4c019 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -19,9 +19,9 @@ namespace tvg { - struct PaintMethod + struct StrategyMethod { - virtual ~PaintMethod(){} + virtual ~StrategyMethod(){} virtual bool dispose(RenderMethod& renderer) = 0; virtual bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) = 0; @@ -37,21 +37,31 @@ namespace tvg struct Paint::Impl { - PaintMethod* method = nullptr; + StrategyMethod* smethod = nullptr; ~Impl() { - if (method) delete(method); + if (smethod) delete(smethod); + } + + void method(StrategyMethod* method) + { + smethod = method; + } + + StrategyMethod* method() + { + return smethod; } }; template - struct TransformMethod : PaintMethod + struct PaintMethod : StrategyMethod { T* inst = nullptr; - TransformMethod(T* inst) : inst(_inst) {} - ~TransformMethod(){} + PaintMethod(T* _inst) : inst(_inst) {} + ~PaintMethod(){} bool rotate(float degree) override { diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 4d043646..d34d57a2 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - Paint::IMPL->method = IMPL->transformMethod(); + Paint::IMPL->method(new PaintMethod(IMPL)); } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index bd497144..0ba1f1f1 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -40,7 +40,7 @@ struct Scene::Impl bool dispose(RenderMethod& renderer) { for (auto paint : paints) { - paint->IMPL->method->dispose(renderer); + paint->IMPL->method()->dispose(renderer); delete(paint); } paints.clear(); @@ -51,7 +51,7 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (!paint->IMPL->method->update(renderer, transform, flag)) return false; + if (!paint->IMPL->method()->update(renderer, transform, flag)) return false; } return true; } @@ -94,7 +94,7 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if(!paint->IMPL->method->render(renderer)) return false; + if(!paint->IMPL->method()->render(renderer)) return false; } return true; } @@ -118,7 +118,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->IMPL->method->bounds(&x2, &y2, &w2, &h2)) return false; + if (paint->IMPL->method()->bounds(&x2, &y2, &w2, &h2)) return false; //Merge regions if (x2 < x) x = x2; @@ -203,12 +203,6 @@ struct Scene::Impl if (!loader->read()) return Result::Unknown; return Result::Success; } - - PaintMethod* transformMethod() - { - return new TransformMethod(this); - } - }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index f42c1605..7d266142 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -31,7 +31,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique(this)) { - Paint::IMPL->method = IMPL->transformMethod(); + Paint::IMPL->method(new PaintMethod(IMPL)); } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 955deb64..a7755da1 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -236,12 +236,6 @@ struct Shape::Impl return true; } - - - PaintMethod* transformMethod() - { - return new TransformMethod(this); - } }; #endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file From ec6e5618e234c4fd88b3c1d79e4c6686321d4cba Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Jul 2020 16:50:29 +0900 Subject: [PATCH 191/244] common picture: introduce picture feature which is for vector file extensions. Now Scene is only specialized for composition of Paint objects. Change-Id: I16426913f029c89e9f9ac4d5e0afed11d1a228d0 --- inc/thorvg.h | 24 +++++- src/lib/meson.build | 2 + src/lib/tvgCommon.h | 5 -- src/lib/tvgPicture.cpp | 57 +++++++++++++ src/lib/tvgPictureImpl.h | 179 +++++++++++++++++++++++++++++++++++++++ src/lib/tvgScene.cpp | 10 +-- src/lib/tvgSceneImpl.h | 71 +++++----------- src/lib/tvgShape.cpp | 1 - src/lib/tvgShapeImpl.h | 1 + test/testSvg.cpp | 8 +- 10 files changed, 288 insertions(+), 70 deletions(-) create mode 100644 src/lib/tvgPicture.cpp create mode 100644 src/lib/tvgPictureImpl.h diff --git a/inc/thorvg.h b/inc/thorvg.h index 36fed956..7c725bc7 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -267,6 +267,28 @@ public: }; +/** + * @class Picture + * + * @ingroup ThorVG + * + * @brief description... + * + */ +class TVG_EXPORT Picture final : public Paint +{ +public: + ~Picture(); + + Result load(const std::string& path) noexcept; + Result size(float* w, float* h) const noexcept; + + static std::unique_ptr gen() noexcept; + + _TVG_DECLARE_PRIVATE(Picture); +}; + + /** * @class Scene * @@ -282,11 +304,11 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; - Result load(const std::string& path) noexcept; static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(Scene); + _TVG_DECLARE_ACCESSOR(Picture); }; diff --git a/src/lib/meson.build b/src/lib/meson.build index 64cedbd6..631016dd 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -16,6 +16,7 @@ source_file = [ 'tvgBezier.h', 'tvgLoader.h', 'tvgLoaderMgr.h', + 'tvgPictureImpl.h', 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', @@ -28,6 +29,7 @@ source_file = [ 'tvgLinearGradient.cpp', 'tvgLoaderMgr.cpp', 'tvgPaint.cpp', + 'tvgPicture.cpp', 'tvgRadialGradient.cpp', 'tvgRender.cpp', 'tvgScene.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 4cec18fe..dddac620 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -31,8 +31,6 @@ using namespace std; using namespace tvg; #define IMPL pImpl.get() -#define SCENE_IMPL scene->pImpl.get() -#define SHAPE_IMPL shape->pImpl.get() #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 @@ -42,8 +40,5 @@ using namespace tvg; #include "tvgLoaderMgr.h" #include "tvgRender.h" #include "tvgPaint.h" -#include "tvgShapePath.h" -#include "tvgShapeImpl.h" -#include "tvgSceneImpl.h" #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp new file mode 100644 index 00000000..6d6ae473 --- /dev/null +++ b/src/lib/tvgPicture.cpp @@ -0,0 +1,57 @@ +/* + * 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_PICTURE_CPP_ +#define _TVG_PICTURE_CPP_ + +#include "tvgPictureImpl.h" + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +Picture::Picture() : pImpl(make_unique()) +{ + Paint::IMPL->method(new PaintMethod(IMPL)); +} + + +Picture::~Picture() +{ +} + + +unique_ptr Picture::gen() noexcept +{ + return unique_ptr(new Picture); +} + + +Result Picture::load(const std::string& path) noexcept +{ + if (path.empty()) return Result::InvalidArguments; + + return IMPL->load(path); +} + + +Result Picture::size(float* w, float* h) const noexcept +{ + if (IMPL->size(w, h)) return Result::Success; + return Result::InsufficientCondition; +} + +#endif /* _TVG_PICTURE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h new file mode 100644 index 00000000..b72c556c --- /dev/null +++ b/src/lib/tvgPictureImpl.h @@ -0,0 +1,179 @@ +/* + * 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_PICTURE_IMPL_H_ +#define _TVG_PICTURE_IMPL_H_ + +#include "tvgCommon.h" +#include "tvgSceneImpl.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct Picture::Impl +{ + unique_ptr loader = nullptr; + Scene* scene = nullptr; + RenderTransform *rTransform = nullptr; + uint32_t flag = RenderUpdateFlag::None; + + ~Impl() + { + if (rTransform) delete(rTransform); + } + + bool dispose(RenderMethod& renderer) + { + if (!scene) return false; + + scene->IMPL->dispose(renderer); + delete(scene); + + return true; + } + + bool update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t pFlag) + { + if (loader) { + auto scene = loader->data(); + if (scene) { + this->scene = scene.release(); + if (!this->scene) return false; + loader->close(); + } + } + + if (!scene) return false; + + if (flag & RenderUpdateFlag::Transform) { + if (!rTransform) return false; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; + } + } + + auto ret = true; + + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); + ret = scene->IMPL->update(renderer, &outTransform, flag); + } else { + auto outTransform = pTransform ? pTransform : rTransform; + ret = scene->IMPL->update(renderer, outTransform, flag); + } + + flag = RenderUpdateFlag::None; + + return ret; + } + + bool render(RenderMethod &renderer) + { + if (!scene) return false; + return scene->IMPL->render(renderer); + } + + + bool size(float* w, float* h) + { + if (loader) { + if (w) *w = loader->vw; + if (h) *h = loader->vh; + return true; + } + + return false; + } + + bool bounds(float* x, float* y, float* w, float* h) + { + if (!scene) return false; + return scene->IMPL->bounds(x, y, w, h); + } + + bool scale(float factor) + { + if (rTransform) { + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; + } else { + if (fabsf(factor) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->scale = factor; + flag |= RenderUpdateFlag::Transform; + + return true; + } + + bool rotate(float degree) + { + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; + } else { + if (fabsf(degree) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->degree = degree; + flag |= RenderUpdateFlag::Transform; + + return true; + } + + bool translate(float x, float y) + { + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; + } else { + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->x = x; + rTransform->y = y; + flag |= RenderUpdateFlag::Transform; + + return true; + } + + + bool transform(const Matrix& m) + { + if (!rTransform) { + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->override(m); + flag |= RenderUpdateFlag::Transform; + + return true; + } + + + Result load(const string& path) + { + if (loader) loader->close(); + loader = LoaderMgr::loader(path.c_str()); + if (!loader || !loader->open(path.c_str())) return Result::NonSupport; + if (!loader->read()) return Result::Unknown; + return Result::Success; + } +}; + +#endif //_TVG_PICTURE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index d34d57a2..ff3aca81 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -17,7 +17,7 @@ #ifndef _TVG_SCENE_CPP_ #define _TVG_SCENE_CPP_ -#include "tvgCommon.h" +#include "tvgSceneImpl.h" /************************************************************************/ /* External Class Implementation */ @@ -57,12 +57,4 @@ Result Scene::reserve(uint32_t size) noexcept return Result::Success; } - -Result Scene::load(const std::string& path) noexcept -{ - if (path.empty()) return Result::InvalidArguments; - - return IMPL->load(path); -} - #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 0ba1f1f1..84bdd7e0 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -28,12 +28,9 @@ struct Scene::Impl vector paints; RenderTransform *rTransform = nullptr; uint32_t flag = RenderUpdateFlag::None; - unique_ptr loader = nullptr; ~Impl() { - //Are you sure clear() prior to this? - assert(paints.empty()); if (rTransform) delete(rTransform); } @@ -58,16 +55,6 @@ struct Scene::Impl bool update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t pFlag) { - if (loader) { - auto scene = loader->data(); - if (scene) { - auto p = scene.release(); - if (!p) return false; - paints.push_back(p); - loader->close(); - } - } - if (flag & RenderUpdateFlag::Transform) { if (!rTransform) return false; if (!rTransform->update()) { @@ -101,37 +88,31 @@ struct Scene::Impl bool bounds(float* px, float* py, float* pw, float* ph) { - if (loader) { - if (px) *px = loader->vx; - if (py) *py = loader->vy; - if (pw) *pw = loader->vw; - if (ph) *ph = loader->vh; - } else { - auto x = FLT_MAX; - auto y = FLT_MAX; - auto w = 0.0f; - auto h = 0.0f; + auto x = FLT_MAX; + auto y = FLT_MAX; + auto w = 0.0f; + auto h = 0.0f; - for(auto paint: paints) { - auto x2 = FLT_MAX; - auto y2 = FLT_MAX; - auto w2 = 0.0f; - auto h2 = 0.0f; + for(auto paint: paints) { + auto x2 = FLT_MAX; + auto y2 = FLT_MAX; + auto w2 = 0.0f; + auto h2 = 0.0f; - if (paint->IMPL->method()->bounds(&x2, &y2, &w2, &h2)) return false; + if (paint->IMPL->method()->bounds(&x2, &y2, &w2, &h2)) return false; - //Merge regions - if (x2 < x) x = x2; - if (x + w < x2 + w2) w = (x2 + w2) - x; - if (y2 < y) y = x2; - if (y + h < y2 + h2) h = (y2 + h2) - y; - } - - if (px) *px = x; - if (py) *py = y; - if (pw) *pw = w; - if (ph) *ph = h; + //Merge regions + if (x2 < x) x = x2; + if (x + w < x2 + w2) w = (x2 + w2) - x; + if (y2 < y) y = x2; + if (y + h < y2 + h2) h = (y2 + h2) - y; } + + if (px) *px = x; + if (py) *py = y; + if (pw) *pw = w; + if (ph) *ph = h; + return true; } @@ -193,16 +174,6 @@ struct Scene::Impl return true; } - - - Result load(const string& path) - { - if (loader) loader->close(); - loader = LoaderMgr::loader(path.c_str()); - if (!loader || !loader->open(path.c_str())) return Result::NonSupport; - if (!loader->read()) return Result::Unknown; - return Result::Success; - } }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 7d266142..59718d8e 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -17,7 +17,6 @@ #ifndef _TVG_SHAPE_CPP_ #define _TVG_SHAPE_CPP_ -#include "tvgCommon.h" #include "tvgShapeImpl.h" /************************************************************************/ diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index a7755da1..2a7005eb 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -18,6 +18,7 @@ #define _TVG_SHAPE_IMPL_H_ #include "tvgCommon.h" +#include "tvgShapePath.h" /************************************************************************/ /* Internal Class Implementation */ diff --git a/test/testSvg.cpp b/test/testSvg.cpp index b8eb2ba2..5f053701 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -14,15 +14,15 @@ void svgDirCallback(const char* name, const char* path, void* data) { tvg::Canvas* canvas = static_cast(data); - auto scene = tvg::Scene::gen(); + auto picture = tvg::Picture::gen(); char buf[PATH_MAX]; sprintf(buf,"%s/%s", path, name); - if (scene->load(buf) != tvg::Result::Success) return; + if (picture->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)); + picture->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(picture)); count++; From e9a4e2ccb6d85c39145901f0097177d7ff516509 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Jul 2020 19:17:55 +0900 Subject: [PATCH 192/244] common: code refactoring remove duplicated code among the Paint types. Change-Id: Ia7c09f29531e6aef73d2ba1f951f8dfdf488deb8 --- inc/thorvg.h | 12 ++-- src/lib/tvgCanvasImpl.h | 8 +-- src/lib/tvgPaint.cpp | 10 +-- src/lib/tvgPaint.h | 129 +++++++++++++++++++++++++++++---------- src/lib/tvgPictureImpl.h | 126 ++++++-------------------------------- src/lib/tvgSceneImpl.h | 101 ++---------------------------- src/lib/tvgShapeImpl.h | 83 +------------------------ 7 files changed, 138 insertions(+), 331 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 7c725bc7..622c302e 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -48,8 +48,10 @@ protected: \ A() = delete; \ ~A() = delete -#define _TVG_DECLARE_ACCESSOR(A) \ - friend A +#define _TVG_DECLARE_ACCESSOR() \ + friend Canvas; \ + friend Scene; \ + friend Picture #define _TVG_DECALRE_IDENTIFIER() \ auto id() const { return _id; } \ @@ -61,6 +63,7 @@ namespace tvg class RenderMethod; class Scene; +class Picture; class Canvas; @@ -105,9 +108,8 @@ public: Result transform(const Matrix& m) noexcept; Result bounds(float* x, float* y, float* w, float* h) const noexcept; + _TVG_DECLARE_ACCESSOR(); _TVG_DECLARE_PRIVATE(Paint); - _TVG_DECLARE_ACCESSOR(Canvas); - _TVG_DECLARE_ACCESSOR(Scene); }; @@ -166,7 +168,6 @@ public: }; - /** * @class LinearGradient * @@ -308,7 +309,6 @@ public: static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(Scene); - _TVG_DECLARE_ACCESSOR(Picture); }; diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 27767350..adcd472e 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -56,7 +56,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for (auto paint : paints) { - paint->IMPL->method()->dispose(*renderer); + paint->IMPL->dispose(*renderer); delete(paint); } paints.clear(); @@ -70,13 +70,13 @@ struct Canvas::Impl //Update single paint node if (paint) { - if (!paint->IMPL->method()->update(*renderer, nullptr, RenderUpdateFlag::None)) { + if (!paint->IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) { return Result::InsufficientCondition; } //Update retained all paint nodes } else { for(auto paint: paints) { - if (!paint->IMPL->method()->update(*renderer, nullptr, RenderUpdateFlag::None)) { + if (!paint->IMPL->update(*renderer, nullptr, RenderUpdateFlag::None)) { return Result::InsufficientCondition; } } @@ -91,7 +91,7 @@ struct Canvas::Impl if (!renderer->preRender()) return Result::InsufficientCondition; for(auto paint: paints) { - if(!paint->IMPL->method()->render(*renderer)) return Result::InsufficientCondition; + if(!paint->IMPL->render(*renderer)) return Result::InsufficientCondition; } if (!renderer->postRender()) return Result::InsufficientCondition; diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 8aa62d20..dacbffb7 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -39,35 +39,35 @@ Paint :: ~Paint() Result Paint::rotate(float degree) noexcept { - if (IMPL->method()->rotate(degree)) return Result::Success; + if (IMPL->rotate(degree)) return Result::Success; return Result::FailedAllocation; } Result Paint::scale(float factor) noexcept { - if (IMPL->method()->scale(factor)) return Result::Success; + if (IMPL->scale(factor)) return Result::Success; return Result::FailedAllocation; } Result Paint::translate(float x, float y) noexcept { - if (IMPL->method()->translate(x, y)) return Result::Success; + if (IMPL->translate(x, y)) return Result::Success; return Result::FailedAllocation; } Result Paint::transform(const Matrix& m) noexcept { - if (IMPL->method()->transform(m)) return Result::Success; + if (IMPL->transform(m)) return Result::Success; return Result::FailedAllocation; } Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept { - if (IMPL->method()->bounds(x, y, w, h)) return Result::Success; + if (IMPL->bounds(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 45e4c019..7d43df01 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -24,23 +24,20 @@ namespace tvg virtual ~StrategyMethod(){} virtual bool dispose(RenderMethod& renderer) = 0; - virtual bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) = 0; + virtual bool update(RenderMethod& renderer, const RenderTransform* transform, RenderUpdateFlag pFlag) = 0; virtual bool render(RenderMethod& renderer) = 0; - - virtual bool rotate(float degree) = 0; - virtual bool scale(float factor) = 0; - virtual bool translate(float x, float y) = 0; - virtual bool transform(const Matrix& m) = 0; virtual bool bounds(float* x, float* y, float* w, float* h) const = 0; - }; struct Paint::Impl { StrategyMethod* smethod = nullptr; + RenderTransform *rTransform = nullptr; + uint32_t flag = RenderUpdateFlag::None; ~Impl() { if (smethod) delete(smethod); + if (rTransform) delete(rTransform); } void method(StrategyMethod* method) @@ -48,9 +45,99 @@ namespace tvg smethod = method; } - StrategyMethod* method() + bool rotate(float degree) { - return smethod; + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; + } else { + if (fabsf(degree) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->degree = degree; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; + } + + bool scale(float factor) + { + if (rTransform) { + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; + } else { + if (fabsf(factor) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->scale = factor; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; + } + + bool translate(float x, float y) + { + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; + } else { + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->x = x; + rTransform->y = y; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; + } + + bool transform(const Matrix& m) + { + if (!rTransform) { + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->override(m); + flag |= RenderUpdateFlag::Transform; + + return true; + } + + bool bounds(float* x, float* y, float* w, float* h) const + { + return smethod->bounds(x, y, w, h); + } + + bool dispose(RenderMethod& renderer) + { + return smethod->dispose(renderer); + } + + bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) + { + if (flag & RenderUpdateFlag::Transform) { + if (!rTransform) return false; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; + } + } + + auto newFlag = static_cast(pFlag | flag); + flag = RenderUpdateFlag::None; + + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); + return smethod->update(renderer, &outTransform, newFlag); + } else { + auto outTransform = pTransform ? pTransform : rTransform; + return smethod->update(renderer, outTransform, newFlag); + } + } + + bool render(RenderMethod& renderer) + { + return smethod->render(renderer); } }; @@ -63,26 +150,6 @@ namespace tvg PaintMethod(T* _inst) : inst(_inst) {} ~PaintMethod(){} - bool rotate(float degree) override - { - return inst->rotate(degree); - } - - bool scale(float factor) override - { - return inst->scale(factor); - } - - bool translate(float x, float y) override - { - return inst->translate(x, y); - } - - bool transform(const Matrix& m) override - { - return inst->transform(m); - } - bool bounds(float* x, float* y, float* w, float* h) const override { return inst->bounds(x, y, w, h); @@ -93,9 +160,9 @@ namespace tvg return inst->dispose(renderer); } - bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) + bool update(RenderMethod& renderer, const RenderTransform* transform, RenderUpdateFlag flag) { - return inst->update(renderer, pTransform, pFlag); + return inst->update(renderer, transform, flag); } bool render(RenderMethod& renderer) diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index b72c556c..098176d2 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -18,7 +18,6 @@ #define _TVG_PICTURE_IMPL_H_ #include "tvgCommon.h" -#include "tvgSceneImpl.h" /************************************************************************/ /* Internal Class Implementation */ @@ -27,145 +26,54 @@ struct Picture::Impl { unique_ptr loader = nullptr; - Scene* scene = nullptr; - RenderTransform *rTransform = nullptr; - uint32_t flag = RenderUpdateFlag::None; - - ~Impl() - { - if (rTransform) delete(rTransform); - } + Paint* paint = nullptr; bool dispose(RenderMethod& renderer) { - if (!scene) return false; + if (!paint) return false; - scene->IMPL->dispose(renderer); - delete(scene); + paint->IMPL->dispose(renderer); + delete(paint); return true; } - bool update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t pFlag) + bool update(RenderMethod &renderer, const RenderTransform* transform, RenderUpdateFlag flag) { if (loader) { auto scene = loader->data(); if (scene) { - this->scene = scene.release(); - if (!this->scene) return false; + this->paint = scene.release(); + if (!this->paint) return false; loader->close(); } } - if (!scene) return false; + if (!paint) return false; - if (flag & RenderUpdateFlag::Transform) { - if (!rTransform) return false; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } - } - - auto ret = true; - - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - ret = scene->IMPL->update(renderer, &outTransform, flag); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - ret = scene->IMPL->update(renderer, outTransform, flag); - } - - flag = RenderUpdateFlag::None; - - return ret; + return paint->IMPL->update(renderer, transform, flag); } bool render(RenderMethod &renderer) { - if (!scene) return false; - return scene->IMPL->render(renderer); + if (!paint) return false; + return paint->IMPL->render(renderer); } - bool size(float* w, float* h) { - if (loader) { - if (w) *w = loader->vw; - if (h) *h = loader->vh; - return true; - } - - return false; + if (!loader) return false; + if (w) *w = loader->vw; + if (h) *h = loader->vh; + return true; } bool bounds(float* x, float* y, float* w, float* h) { - if (!scene) return false; - return scene->IMPL->bounds(x, y, w, h); + if (!paint) return false; + return paint->IMPL->bounds(x, y, w, h); } - bool scale(float factor) - { - if (rTransform) { - if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; - } else { - if (fabsf(factor) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->scale = factor; - flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool rotate(float degree) - { - if (rTransform) { - if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; - } else { - if (fabsf(degree) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->degree = degree; - flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool translate(float x, float y) - { - if (rTransform) { - if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; - } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->x = x; - rTransform->y = y; - flag |= RenderUpdateFlag::Transform; - - return true; - } - - - bool transform(const Matrix& m) - { - if (!rTransform) { - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->override(m); - flag |= RenderUpdateFlag::Transform; - - return true; - } - - Result load(const string& path) { if (loader) loader->close(); diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 84bdd7e0..c4cbb235 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -26,18 +26,11 @@ struct Scene::Impl { vector paints; - RenderTransform *rTransform = nullptr; - uint32_t flag = RenderUpdateFlag::None; - - ~Impl() - { - if (rTransform) delete(rTransform); - } bool dispose(RenderMethod& renderer) { for (auto paint : paints) { - paint->IMPL->method()->dispose(renderer); + paint->IMPL->dispose(renderer); delete(paint); } paints.clear(); @@ -45,43 +38,18 @@ struct Scene::Impl return true; } - bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) + bool update(RenderMethod &renderer, const RenderTransform* transform, RenderUpdateFlag flag) { for(auto paint: paints) { - if (!paint->IMPL->method()->update(renderer, transform, flag)) return false; + if (!paint->IMPL->update(renderer, transform, static_cast(flag))) return false; } return true; } - bool update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t pFlag) - { - if (flag & RenderUpdateFlag::Transform) { - if (!rTransform) return false; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } - } - - auto ret = true; - - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - ret = updateInternal(renderer, &outTransform, pFlag | flag); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - ret = updateInternal(renderer, outTransform, pFlag | flag); - } - - flag = RenderUpdateFlag::None; - - return ret; - } - bool render(RenderMethod &renderer) { for(auto paint: paints) { - if(!paint->IMPL->method()->render(renderer)) return false; + if(!paint->IMPL->render(renderer)) return false; } return true; } @@ -99,7 +67,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->IMPL->method()->bounds(&x2, &y2, &w2, &h2)) return false; + if (paint->IMPL->bounds(&x2, &y2, &w2, &h2)) return false; //Merge regions if (x2 < x) x = x2; @@ -115,65 +83,6 @@ struct Scene::Impl return true; } - - bool scale(float factor) - { - if (rTransform) { - if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; - } else { - if (fabsf(factor) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->scale = factor; - flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool rotate(float degree) - { - if (rTransform) { - if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; - } else { - if (fabsf(degree) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->degree = degree; - flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool translate(float x, float y) - { - if (rTransform) { - if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; - } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->x = x; - rTransform->y = y; - flag |= RenderUpdateFlag::Transform; - - return true; - } - - - bool transform(const Matrix& m) - { - if (!rTransform) { - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->override(m); - flag |= RenderUpdateFlag::Transform; - - return true; - } }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 2a7005eb..ab11db03 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -45,12 +45,10 @@ struct Shape::Impl ShapePath *path = nullptr; Fill *fill = nullptr; ShapeStroke *stroke = nullptr; - RenderTransform *rTransform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a - uint32_t flag = RenderUpdateFlag::None; void *edata = nullptr; //engine data Shape *shape = nullptr; - + uint32_t flag = RenderUpdateFlag::None; Impl(Shape* s) : path(new ShapePath), shape(s) { @@ -61,7 +59,6 @@ struct Shape::Impl if (path) delete(path); if (fill) delete(fill); if (stroke) delete(stroke); - if (rTransform) delete(rTransform); } bool dispose(RenderMethod& renderer) @@ -74,23 +71,9 @@ struct Shape::Impl return renderer.render(*shape, edata); } - bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag) + bool update(RenderMethod& renderer, const RenderTransform* transform, RenderUpdateFlag pFlag) { - if (flag & RenderUpdateFlag::Transform) { - if (!rTransform) return false; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } - } - - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - edata = renderer.prepare(*shape, edata, &outTransform, static_cast(pFlag | flag)); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - edata = renderer.prepare(*shape, edata, outTransform, static_cast(pFlag | flag)); - } + edata = renderer.prepare(*shape, edata, transform, static_cast(pFlag | flag)); flag = RenderUpdateFlag::None; @@ -104,66 +87,6 @@ struct Shape::Impl return path->bounds(x, y, w, h); } - bool scale(float factor) - { - if (rTransform) { - if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; - } else { - if (fabsf(factor) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->scale = factor; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool rotate(float degree) - { - if (rTransform) { - if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; - } else { - if (fabsf(degree) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->degree = degree; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool translate(float x, float y) - { - if (rTransform) { - if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; - } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->x = x; - rTransform->y = y; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - - bool transform(const Matrix& m) - { - if (!rTransform) { - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->override(m); - flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool strokeWidth(float width) { //TODO: Size Exception? From f15aefa5dc1e48d97cea1316cb38dd3888a021de Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Jul 2020 20:40:12 +0900 Subject: [PATCH 193/244] test: updated svg sample also revise size() method of Picture for proper aligning. Change-Id: I58a0886968f6058e65a062477e2a873224d8ea8f --- inc/thorvg.h | 2 +- src/lib/tvgPicture.cpp | 4 +- src/lib/tvgPictureImpl.h | 4 +- test/svgs/batman1.svg | 3 + test/svgs/eee.svg | 4 + test/svgs/favorite_on.svg | 11 + test/svgs/google.svg | 4 + test/svgs/ibm.svg | 44 ++ test/svgs/scion.svg | 9 + test/svgs/tiger.svg | 829 ++++++++++++++++++++++++++++++++++++++ test/svgs/wikimedia.svg | 5 - test/svgs/yadis.svg | 16 + test/testSvg.cpp | 32 +- 13 files changed, 951 insertions(+), 16 deletions(-) create mode 100644 test/svgs/batman1.svg create mode 100644 test/svgs/eee.svg create mode 100644 test/svgs/favorite_on.svg create mode 100644 test/svgs/google.svg create mode 100644 test/svgs/ibm.svg create mode 100644 test/svgs/scion.svg create mode 100644 test/svgs/tiger.svg delete mode 100644 test/svgs/wikimedia.svg create mode 100644 test/svgs/yadis.svg diff --git a/inc/thorvg.h b/inc/thorvg.h index 622c302e..c738a0ee 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -282,7 +282,7 @@ public: ~Picture(); Result load(const std::string& path) noexcept; - Result size(float* w, float* h) const noexcept; + Result viewbox(float* x, float* y, float* w, float* h) const noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index 6d6ae473..03701636 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -48,9 +48,9 @@ Result Picture::load(const std::string& path) noexcept } -Result Picture::size(float* w, float* h) const noexcept +Result Picture::viewbox(float* x, float* y, float* w, float* h) const noexcept { - if (IMPL->size(w, h)) return Result::Success; + if (IMPL->viewbox(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 098176d2..ed1c678d 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -60,9 +60,11 @@ struct Picture::Impl return paint->IMPL->render(renderer); } - bool size(float* w, float* h) + bool viewbox(float* x, float* y, float* w, float* h) { if (!loader) return false; + if (x) *x = loader->vx; + if (y) *y = loader->vy; if (w) *w = loader->vw; if (h) *h = loader->vh; return true; diff --git a/test/svgs/batman1.svg b/test/svgs/batman1.svg new file mode 100644 index 00000000..7a9d2291 --- /dev/null +++ b/test/svgs/batman1.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/svgs/eee.svg b/test/svgs/eee.svg new file mode 100644 index 00000000..c23875ee --- /dev/null +++ b/test/svgs/eee.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/svgs/favorite_on.svg b/test/svgs/favorite_on.svg new file mode 100644 index 00000000..c34b3209 --- /dev/null +++ b/test/svgs/favorite_on.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/svgs/google.svg b/test/svgs/google.svg new file mode 100644 index 00000000..3e51a42e --- /dev/null +++ b/test/svgs/google.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/svgs/ibm.svg b/test/svgs/ibm.svg new file mode 100644 index 00000000..c87ad116 --- /dev/null +++ b/test/svgs/ibm.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/svgs/scion.svg b/test/svgs/scion.svg new file mode 100644 index 00000000..24fa109f --- /dev/null +++ b/test/svgs/scion.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/svgs/tiger.svg b/test/svgs/tiger.svg new file mode 100644 index 00000000..a59da8d3 --- /dev/null +++ b/test/svgs/tiger.svg @@ -0,0 +1,829 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/svgs/wikimedia.svg b/test/svgs/wikimedia.svg deleted file mode 100644 index ad2c2115..00000000 --- a/test/svgs/wikimedia.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/test/svgs/yadis.svg b/test/svgs/yadis.svg new file mode 100644 index 00000000..7bcbad8b --- /dev/null +++ b/test/svgs/yadis.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 5f053701..e16f19b1 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -4,11 +4,10 @@ /* Drawing Commands */ /************************************************************************/ -#define NUM_PER_LINE 3 +#define NUM_PER_LINE 4 +#define SIZE 200 -int x = 30; -int y = 30; -int count = 0; +static int count = 0; void svgDirCallback(const char* name, const char* path, void* data) { @@ -21,12 +20,31 @@ void svgDirCallback(const char* name, const char* path, void* data) if (picture->load(buf) != tvg::Result::Success) return; - picture->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); + float x, y, w, h; + picture->viewbox(&x, &y, &w, &h); + + float rate = (SIZE/(w > h ? w : h)); + picture->scale(rate); + + x *= rate; + y *= rate; + w *= rate; + h *= rate; + + //Center Align ? + if (w > h) { + y -= (SIZE - h) * 0.5f; + } else { + x -= (SIZE - w) * 0.5f; + } + + picture->translate((count % NUM_PER_LINE) * SIZE - x, SIZE * (count / NUM_PER_LINE) - y); + canvas->push(move(picture)); - count++; - cout << "SVG: " << buf << endl; + + count++; } void tvgDrawCmds(tvg::Canvas* canvas) From 7b9c7de1e5eca8e9fe300e17407ada28dc117802 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Fri, 31 Jul 2020 11:34:49 +0200 Subject: [PATCH 194/244] capi: Added C wrappers for gradient func Change-Id: If41dab9b06f6cec2831ea1361f30b50a193e99c4 --- inc/thorvg_capi.h | 20 ++++++++++++++ src/bindings/capi/tvgCapi.cpp | 51 +++++++++++++++++++++++++++++++++++ test/testCapi.c | 31 ++++++++++++++++++--- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 9fa4d590..037730fa 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -35,6 +35,7 @@ extern "C" { typedef struct _Tvg_Canvas Tvg_Canvas; typedef struct _Tvg_Paint Tvg_Paint; +typedef struct _Tvg_Gradient Tvg_Gradient; #define TVG_ENGINE_SW (1 << 1) #define TVG_ENGINE_GL (1 << 2) @@ -93,6 +94,11 @@ typedef struct float e31, e32, e33; } Tvg_Matrix; +typedef struct +{ + float offset; + uint8_t r, g, b, a; +} Tvg_Color_Stop; /************************************************************************/ /* Engine API */ @@ -144,6 +150,20 @@ TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y); TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m); +TVG_EXPORT Tvg_Result tvg_shape_linear_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad); +TVG_EXPORT Tvg_Result tvg_shape_radial_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad); + + +/************************************************************************/ +/* Gradient API */ +/************************************************************************/ +TVG_EXPORT Tvg_Gradient* tvg_linear_gradient_new(); +TVG_EXPORT Tvg_Gradient* tvg_radial_gradient_new(); +TVG_EXPORT Tvg_Result tvg_gradient_del(Tvg_Gradient* grad); +TVG_EXPORT Tvg_Result tvg_linear_gradient_set(Tvg_Gradient* grad, float x1, float y1, float x2, float y2); +TVG_EXPORT Tvg_Result tvg_radial_gradient_set(Tvg_Gradient* grad, float cx, float cy, float radius); +TVG_EXPORT Tvg_Result tvg_gradient_color_stops(Tvg_Gradient* grad, const Tvg_Color_Stop* color_stop, uint32_t cnt); + #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 9ceb1135..5df6b5af 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -35,6 +35,11 @@ struct _Tvg_Paint //Dummy for Direct Casting }; +struct _Tvg_Gradient +{ + //Dummy for Direct Casting +}; + /************************************************************************/ /* Engine API */ @@ -246,6 +251,52 @@ TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m) return (Tvg_Result) reinterpret_cast(paint)->transform(*(reinterpret_cast(m))); } +TVG_EXPORT Tvg_Result tvg_shape_linear_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad) +{ + return (Tvg_Result) reinterpret_cast(paint)->fill(unique_ptr((LinearGradient*)(grad))); +} + +TVG_EXPORT Tvg_Result tvg_shape_radial_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad) +{ + return (Tvg_Result) reinterpret_cast(paint)->fill(unique_ptr((RadialGradient*)(grad))); +} + + +/************************************************************************/ +/* Gradient API */ +/************************************************************************/ +TVG_EXPORT Tvg_Gradient* tvg_linear_gradient_new() +{ + return (Tvg_Gradient*)LinearGradient::gen().release(); +} + +TVG_EXPORT Tvg_Gradient* tvg_radial_gradient_new() +{ + return (Tvg_Gradient*)RadialGradient::gen().release(); + +} + +TVG_EXPORT Tvg_Result tvg_gradient_del(Tvg_Gradient* grad) +{ + delete(grad); + return TVG_RESULT_SUCCESS; +} + +TVG_EXPORT Tvg_Result tvg_linear_gradient_set(Tvg_Gradient* grad, float x1, float y1, float x2, float y2) +{ + return (Tvg_Result) reinterpret_cast(grad)->linear(x1, y1, x2, y2); +} + +TVG_EXPORT Tvg_Result tvg_radial_gradient_set(Tvg_Gradient* grad, float cx, float cy, float radius) +{ + return (Tvg_Result) reinterpret_cast(grad)->radial(cx, cy, radius); +} + +TVG_EXPORT Tvg_Result tvg_gradient_color_stops(Tvg_Gradient* grad, const Tvg_Color_Stop* color_stop, uint32_t cnt) +{ + return (Tvg_Result) reinterpret_cast(grad)->colorStops(reinterpret_cast(color_stop), cnt); +} + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/test/testCapi.c b/test/testCapi.c index 6a46e97e..3a307ab5 100644 --- a/test/testCapi.c +++ b/test/testCapi.c @@ -20,11 +20,36 @@ void testCapi() Tvg_Paint* shape = tvg_shape_new(); tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0); + tvg_shape_append_circle(shape, 200, 200, 100, 100); tvg_shape_append_rect(shape, 100, 100, 300, 300, 100, 100); - tvg_shape_append_circle(shape, 400, 400, 100, 100); - tvg_shape_append_circle(shape, 400, 500, 170, 100); - tvg_shape_fill_color(shape, 255, 255, 0, 255); + Tvg_Gradient* grad = tvg_linear_gradient_new(); + tvg_linear_gradient_set(grad, 0, 0, 300, 300); + Tvg_Color_Stop color_stops[4] = + { + {.offset=0.0, .r=0, .g=0, .b=0, .a=255}, + {.offset=0.25, .r=255, .g=0, .b=0, .a=255}, + {.offset=0.5, .r=0, .g=255, .b=0, .a=255}, + {.offset=1.0, .r=0, .g=0, .b=255, .a=255} + }; + + Tvg_Paint *shape1 = tvg_shape_new(); + tvg_shape_append_rect(shape1, 500, 500, 100, 100, 30, 30); + Tvg_Gradient* grad1 = tvg_radial_gradient_new(); + tvg_radial_gradient_set(grad1, 550, 550, 50); + Tvg_Color_Stop color_stops1[3] = + { + {.offset=0.0, .r=0, .g=0, .b=0, .a=255}, + {.offset=0.6, .r=255, .g=0, .b=0, .a=255}, + {.offset=1.0, .r=0, .g=255, .b=255, .a=255} + }; + + tvg_gradient_color_stops(grad, color_stops, 4); + tvg_gradient_color_stops(grad1, color_stops1, 3); + tvg_shape_linear_gradient_set(shape, grad); + tvg_shape_radial_gradient_set(shape1, grad1); + tvg_canvas_push(canvas, shape); + tvg_canvas_push(canvas, shape1); tvg_canvas_draw(canvas); tvg_canvas_sync(canvas); From 180aab13fba7b83282f6cb9dfebe2440735f1e5a Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 16 Jul 2020 13:15:58 +0900 Subject: [PATCH 195/244] spec: Add spec for rpm packaging Change-Id: I33a7d7e03549860c122eb56534f492a48784533e --- packaging/thorvg.manifest | 5 +++ packaging/thorvg.spec | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 packaging/thorvg.manifest create mode 100644 packaging/thorvg.spec diff --git a/packaging/thorvg.manifest b/packaging/thorvg.manifest new file mode 100644 index 00000000..017d22d3 --- /dev/null +++ b/packaging/thorvg.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec new file mode 100644 index 00000000..e4b37362 --- /dev/null +++ b/packaging/thorvg.spec @@ -0,0 +1,64 @@ +Name: thorvg +Summary: Thor Vector Graphics Library +Version: 0.0.1 +Release: 1 +Group: Graphics System/Rendering Engine +License: Apache-2.0 +URL: https://github.com/samsung/thorvg +Source0: %{name}-%{version}.tar.gz + +BuildRequires: pkgconfig +BuildRequires: pkgconfig(glesv2) + +BuildRequires: meson +BuildRequires: ninja +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description +Thor Vector Graphics Library + + +%package devel +Summary: Thor Vector Graphics Library (devel) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + + +%description devel +Thor Vector Graphics Library (devel) + + +%prep +%setup -q + + +%build + +export DESTDIR=%{buildroot} + +meson setup \ + --prefix /usr \ + --libdir %{_libdir} \ + builddir 2>&1 +ninja \ + -C builddir \ + -j %(echo "`/usr/bin/getconf _NPROCESSORS_ONLN`") + +%install + +export DESTDIR=%{buildroot} + +ninja -C builddir install + +%files +%defattr(-,root,root,-) +%{_libdir}/libthorvg.so.* +%manifest packaging/thorvg.manifest + +%files devel +%defattr(-,root,root,-) +%{_includedir}/*.h +%{_libdir}/libthorvg.so + +%{_libdir}/pkgconfig/thorvg.pc From 214072babeac7ea2fe514739852c1e052716c619 Mon Sep 17 00:00:00 2001 From: Michal Szczecinski Date: Fri, 31 Jul 2020 11:07:53 +0200 Subject: [PATCH 196/244] common shape: added arc implementation Change-Id: Ib483e24d8e358b2860ca8d46e8b88d58d12bdb62 --- .gitignore | 1 + inc/thorvg.h | 1 + inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 6 +- src/lib/tvgShape.cpp | 72 +++++++++++++++++ test/makefile | 1 + test/testArc.cpp | 142 ++++++++++++++++++++++++++++++++++ 7 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 test/testArc.cpp diff --git a/.gitignore b/.gitignore index b796b5e9..7f4d09bf 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ testGradientTransform testSvg testAsync testCapi +testArc diff --git a/inc/thorvg.h b/inc/thorvg.h index c738a0ee..50b03fd0 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -237,6 +237,7 @@ public: //Shape Result appendRect(float x, float y, float w, float h, float rx, float ry) noexcept; Result appendCircle(float cx, float cy, float rx, float ry) noexcept; + Result appendArc(float x, float y, float w, float h, float startAngle, float sweep) noexcept; Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept; //Stroke diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 9fa4d590..695b9948 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -133,6 +133,7 @@ TVG_EXPORT Tvg_Result tvg_shape_cubic_to(Tvg_Paint* paint, float cx1, float cy1, TVG_EXPORT Tvg_Result tvg_shape_close(Tvg_Paint* paint); TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, float w, float h, float rx, float ry); TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry); +TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep); TVG_EXPORT Tvg_Result tvg_shape_append_path(Tvg_Paint* paint, const Tvg_Path_Command* cmds, uint32_t cmdCnt, const Tvg_Point* pts, uint32_t ptsCnt); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_width(Tvg_Paint* paint, float width); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 9ceb1135..8ddbc073 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -178,6 +178,10 @@ TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, return (Tvg_Result) reinterpret_cast(paint)->appendRect(x, y, w, h, rx, ry); } +TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep) +{ + return (Tvg_Result) reinterpret_cast(paint)->appendArc(x, y, w ,h, startAngle, sweep); +} TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry) { @@ -248,4 +252,4 @@ TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m) #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 59718d8e..57c097a0 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -17,6 +17,8 @@ #ifndef _TVG_SHAPE_CPP_ #define _TVG_SHAPE_CPP_ +#include + #include "tvgShapeImpl.h" /************************************************************************/ @@ -148,6 +150,76 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept return Result::Success; } +Result Shape::appendArc(float x, float y, float w, float h, float startAngle, float sweep) noexcept +{ + const float M_PI_HALF = M_PI / 2.0; + const float radius = w / 2; + + Point center = {x + radius, y + radius}; + + auto impl = pImpl.get(); + + startAngle = (startAngle * M_PI) / 180; + sweep = sweep * M_PI / 180; + + auto nCurves = ceil(sweep / M_PI_HALF); + auto fract = fmod(sweep, M_PI_HALF); + fract = (fract < std::numeric_limits::epsilon()) ? M_PI_HALF : fract; + + for (int i = 0; i < nCurves; ++i) { + //bezier parameters + Point start = {0, 0}; + Point end = {0, 0}; + Point bControl1 = {0, 0}; + Point bControl2 = {0, 0}; + + //variables needed to calculate bezier control points + auto ax = 0.0f, ay = 0.0f, bx = 0.0f, by = 0.0f, q1 = 0.0f, q2 = 0.0f, k2 = 0.0f; + auto endAngle = startAngle + ((i != nCurves - 1) ? M_PI_HALF : fract); + + //get bezier start and end point + start.x = radius * cos(startAngle); + start.y = radius * sin(startAngle); + end.x = radius * cos(endAngle); + end.y = radius * sin(endAngle); + + //get bezier control points using article: + //(http://itc.ktu.lt/index.php/ITC/article/view/11812/6479) + ax = start.x; + ay = start.y; + bx = end.x; + by = end.y; + + q1 = ax * ax + ay * ay; + q2 = ax * bx + ay * by + q1; + + k2 = static_cast (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx)); + + bControl1.x = ax - k2 * ay; + bControl1.y = ay + k2 * ax; + bControl2.x = bx + k2 * by; + bControl2.y = by - k2 * bx; + + //move points to proper arc center + start.x += center.x; + start.y += center.y; + end.x += center.x; + end.y += center.y; + bControl1.x += center.x; + bControl1.y += center.y; + bControl2.x += center.x; + bControl2.y += center.y; + + impl->path->moveTo(start.x, start.y); + impl->path->cubicTo(bControl1.x, bControl1.y, bControl2.x, bControl2.y, end.x, end.y); + + startAngle = endAngle; + } + + IMPL->flag |= RenderUpdateFlag::Path; + return Result::Success; +} + Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) noexcept { diff --git a/test/makefile b/test/makefile index e1a8afb0..29e6e779 100644 --- a/test/makefile +++ b/test/makefile @@ -18,4 +18,5 @@ all: 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 testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testArc testArc.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg` diff --git a/test/testArc.cpp b/test/testArc.cpp new file mode 100644 index 00000000..3878aff8 --- /dev/null +++ b/test/testArc.cpp @@ -0,0 +1,142 @@ +#include "testCommon.h" + +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ + +void tvgDrawCmds(tvg::Canvas* canvas) +{ + if (!canvas) return; + + //draw reference rectangles + auto shape2 = tvg::Shape::gen(); + shape2->appendRect(0, 0, 200, 200, 0, 0); + shape2->stroke(255, 0, 0, 255); + shape2->stroke(2); + + auto shape3 = tvg::Shape::gen(); + shape3->moveTo(0, 100); + shape3->lineTo(200, 100); + shape3->stroke(255, 0, 0, 255); + shape3->stroke(2); + + auto shape4 = tvg::Shape::gen(); + shape4->moveTo(100, 0); + shape4->lineTo(100, 200); + shape4->stroke(255, 0, 0, 255); + shape4->stroke(2); + + //test arc + auto shape1 = tvg::Shape::gen(); + shape1->appendArc(0, 0, 200, 200, 10, 270); + shape1->stroke(255, 255, 255, 255); + shape1->stroke(3); + + //Appends Paths + if (canvas->push(move(shape2)) != tvg::Result::Success) return; + if (canvas->push(move(shape3)) != tvg::Result::Success) return; + if (canvas->push(move(shape4)) != tvg::Result::Success) return; + if (canvas->push(move(shape1)) != tvg::Result::Success) return; +} + +/************************************************************************/ +/* 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) +{ + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } +} + + +/************************************************************************/ +/* GL Engine Test Code */ +/************************************************************************/ + +static unique_ptr glCanvas; + +void initGLview(Evas_Object *obj) +{ + static constexpr auto BPP = 4; + + //Create a Canvas + glCanvas = tvg::GlCanvas::gen(); + glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + tvgDrawCmds(glCanvas.get()); +} + +void drawGLview(Evas_Object *obj) +{ + auto gl = elm_glview_gl_api_get(obj); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + +int main(int argc, char **argv) +{ + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } + + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); + + } else { + cout << "engine is not supported" << endl; + } + return 0; +} From e98988da029d56f72c8d4ec82be4545e0907ea6a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 3 Aug 2020 19:58:12 +0900 Subject: [PATCH 197/244] common shape: support pie filling from arc. last argument pie=true makes arc to pie shape. Change-Id: I6f22d00fed77bf728a4ff6e5f1ca42f476ac1664 --- inc/thorvg.h | 2 +- inc/thorvg_capi.h | 2 +- src/bindings/capi/tvgCapi.cpp | 4 +- src/lib/tvgShape.cpp | 78 +++++++++++++++++------------------ test/testArc.cpp | 42 ++++++++----------- 5 files changed, 59 insertions(+), 69 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 50b03fd0..d22acbb2 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -237,7 +237,7 @@ public: //Shape Result appendRect(float x, float y, float w, float h, float rx, float ry) noexcept; Result appendCircle(float cx, float cy, float rx, float ry) noexcept; - Result appendArc(float x, float y, float w, float h, float startAngle, float sweep) noexcept; + Result appendArc(float cx, float cy, float radius, float startAngle, float sweep, bool pie) noexcept; Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept; //Stroke diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index b94c413f..5c0428ba 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -139,7 +139,7 @@ TVG_EXPORT Tvg_Result tvg_shape_cubic_to(Tvg_Paint* paint, float cx1, float cy1, TVG_EXPORT Tvg_Result tvg_shape_close(Tvg_Paint* paint); TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, float w, float h, float rx, float ry); TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry); -TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep); +TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float cx, float cy, float radius, float startAngle, float sweep, uint8_t pie); TVG_EXPORT Tvg_Result tvg_shape_append_path(Tvg_Paint* paint, const Tvg_Path_Command* cmds, uint32_t cmdCnt, const Tvg_Point* pts, uint32_t ptsCnt); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_width(Tvg_Paint* paint, float width); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 65eedd2a..9897584e 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -183,9 +183,9 @@ TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, return (Tvg_Result) reinterpret_cast(paint)->appendRect(x, y, w, h, rx, ry); } -TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep) +TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float cx, float cy, float radius, float startAngle, float sweep, uint8_t pie) { - return (Tvg_Result) reinterpret_cast(paint)->appendArc(x, y, w ,h, startAngle, sweep); + return (Tvg_Result) reinterpret_cast(paint)->appendArc(cx, cy, radius, startAngle, sweep, pie); } TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry) diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 57c097a0..94f445e2 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -150,73 +150,69 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept return Result::Success; } -Result Shape::appendArc(float x, float y, float w, float h, float startAngle, float sweep) noexcept +Result Shape::appendArc(float cx, float cy, float radius, float startAngle, float sweep, bool pie) noexcept { const float M_PI_HALF = M_PI / 2.0; - const float radius = w / 2; - - Point center = {x + radius, y + radius}; auto impl = pImpl.get(); + //just circle + if (sweep >= 360) return appendCircle(cx, cy, radius, radius); + startAngle = (startAngle * M_PI) / 180; sweep = sweep * M_PI / 180; - auto nCurves = ceil(sweep / M_PI_HALF); + auto nCurves = ceil(sweep / M_PI_HALF); auto fract = fmod(sweep, M_PI_HALF); fract = (fract < std::numeric_limits::epsilon()) ? M_PI_HALF : fract; + //Start from here + Point start = {radius * cos(startAngle), radius * sin(startAngle)}; + + if (pie) { + impl->path->moveTo(cx, cy); + impl->path->lineTo(start.x + cx, start.y + cy); + }else { + impl->path->moveTo(start.x + cx, start.y + cy); + } + for (int i = 0; i < nCurves; ++i) { - //bezier parameters - Point start = {0, 0}; - Point end = {0, 0}; - Point bControl1 = {0, 0}; - Point bControl2 = {0, 0}; + + auto endAngle = startAngle + ((i != nCurves - 1) ? M_PI_HALF : fract); + Point end = {radius * cos(endAngle), radius * sin(endAngle)}; //variables needed to calculate bezier control points - auto ax = 0.0f, ay = 0.0f, bx = 0.0f, by = 0.0f, q1 = 0.0f, q2 = 0.0f, k2 = 0.0f; - auto endAngle = startAngle + ((i != nCurves - 1) ? M_PI_HALF : fract); - - //get bezier start and end point - start.x = radius * cos(startAngle); - start.y = radius * sin(startAngle); - end.x = radius * cos(endAngle); - end.y = radius * sin(endAngle); //get bezier control points using article: //(http://itc.ktu.lt/index.php/ITC/article/view/11812/6479) - ax = start.x; - ay = start.y; - bx = end.x; - by = end.y; + auto ax = start.x; + auto ay = start.y; + auto bx = end.x; + auto by = end.y; + auto q1 = ax * ax + ay * ay; + auto q2 = ax * bx + ay * by + q1; + auto k2 = static_cast (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx)); - q1 = ax * ax + ay * ay; - q2 = ax * bx + ay * by + q1; + start = end; //Next start point is the current end point - k2 = static_cast (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx)); + end.x += cx; + end.y += cy; - bControl1.x = ax - k2 * ay; - bControl1.y = ay + k2 * ax; - bControl2.x = bx + k2 * by; - bControl2.y = by - k2 * bx; + Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy}; + Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy}; - //move points to proper arc center - start.x += center.x; - start.y += center.y; - end.x += center.x; - end.y += center.y; - bControl1.x += center.x; - bControl1.y += center.y; - bControl2.x += center.x; - bControl2.y += center.y; - - impl->path->moveTo(start.x, start.y); - impl->path->cubicTo(bControl1.x, bControl1.y, bControl2.x, bControl2.y, end.x, end.y); + impl->path->cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y); startAngle = endAngle; } + if (pie) { + impl->path->moveTo(cx, cy); + impl->path->close(); + } + IMPL->flag |= RenderUpdateFlag::Path; + return Result::Success; } diff --git a/test/testArc.cpp b/test/testArc.cpp index 3878aff8..c00f4643 100644 --- a/test/testArc.cpp +++ b/test/testArc.cpp @@ -8,35 +8,29 @@ void tvgDrawCmds(tvg::Canvas* canvas) { if (!canvas) return; - //draw reference rectangles - auto shape2 = tvg::Shape::gen(); - shape2->appendRect(0, 0, 200, 200, 0, 0); - shape2->stroke(255, 0, 0, 255); - shape2->stroke(2); + //Arc Line + auto shape1 = tvg::Shape::gen(); + shape1->appendArc(150, 150, 100, 10, 270, false); + shape1->stroke(255, 255, 255, 255); + shape1->stroke(2); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; + auto shape2 = tvg::Shape::gen(); + shape2->appendArc(500, 150, 125, 0, 300, true); + shape2->stroke(255, 255, 255, 255); + shape2->stroke(2); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; + + //Pie Fill auto shape3 = tvg::Shape::gen(); - shape3->moveTo(0, 100); - shape3->lineTo(200, 100); - shape3->stroke(255, 0, 0, 255); - shape3->stroke(2); + shape3->appendArc(150, 500, 100, 0, 75, true); + shape3->fill(255, 255, 255, 255); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; auto shape4 = tvg::Shape::gen(); - shape4->moveTo(100, 0); - shape4->lineTo(100, 200); - shape4->stroke(255, 0, 0, 255); - shape4->stroke(2); - - //test arc - auto shape1 = tvg::Shape::gen(); - shape1->appendArc(0, 0, 200, 200, 10, 270); - shape1->stroke(255, 255, 255, 255); - shape1->stroke(3); - - //Appends Paths - if (canvas->push(move(shape2)) != tvg::Result::Success) return; - if (canvas->push(move(shape3)) != tvg::Result::Success) return; + shape4->appendArc(500, 500, 150, 0, 215, true); + shape4->fill(255, 255, 255, 255); if (canvas->push(move(shape4)) != tvg::Result::Success) return; - if (canvas->push(move(shape1)) != tvg::Result::Success) return; } /************************************************************************/ From 7106272d97e1b3f653e54e3c9fc307020b860cb0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 3 Aug 2020 20:06:02 +0900 Subject: [PATCH 198/244] common: code refactoring. return as soon as possible. Change-Id: If48e13e8976bc1692dadd9054b484bf7cd811917 --- src/lib/tvgShape.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 94f445e2..53c76899 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -152,13 +152,13 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept Result Shape::appendArc(float cx, float cy, float radius, float startAngle, float sweep, bool pie) noexcept { - const float M_PI_HALF = M_PI / 2.0; - - auto impl = pImpl.get(); + const float M_PI_HALF = M_PI * 0.5f; //just circle if (sweep >= 360) return appendCircle(cx, cy, radius, radius); + auto impl = pImpl.get(); + startAngle = (startAngle * M_PI) / 180; sweep = sweep * M_PI / 180; From 05757ec07cf0b050ffbd4d528fdb76ccbf92995c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 4 Aug 2020 09:37:08 +0900 Subject: [PATCH 199/244] capi: revise some common paint interfaces and added picture stuff. Change-Id: I9850cbead5ce1ab172f284738fe8456cd19dc3f9 --- inc/thorvg_capi.h | 22 ++++++++--- src/bindings/capi/tvgCapi.cpp | 74 +++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 5c0428ba..ecd7ee6a 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -127,11 +127,20 @@ TVG_EXPORT Tvg_Result tvg_canvas_draw(Tvg_Canvas* canvas); TVG_EXPORT Tvg_Result tvg_canvas_sync(Tvg_Canvas* canvas); +/************************************************************************/ +/* Paint API */ +/************************************************************************/ +TVG_EXPORT Tvg_Result tvg_paint_del(Tvg_Paint* paint); +TVG_EXPORT Tvg_Result tvg_paint_scale(Tvg_Paint* paint, float factor); +TVG_EXPORT Tvg_Result tvg_paint_rotate(Tvg_Paint* paint, float degree); +TVG_EXPORT Tvg_Result tvg_paint_translate(Tvg_Paint* paint, float x, float y); +TVG_EXPORT Tvg_Result tvg_paint_transform(Tvg_Paint* paint, const Tvg_Matrix* m); + + /************************************************************************/ /* Shape API */ /************************************************************************/ TVG_EXPORT Tvg_Paint* tvg_shape_new(); -TVG_EXPORT Tvg_Result tvg_shape_del(Tvg_Paint* paint); TVG_EXPORT Tvg_Result tvg_shape_reset(Tvg_Paint* paint); TVG_EXPORT Tvg_Result tvg_shape_move_to(Tvg_Paint* paint, float x, float y); TVG_EXPORT Tvg_Result tvg_shape_line_to(Tvg_Paint* paint, float x, float y); @@ -147,10 +156,6 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* d TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap cap); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join); TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); -TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); -TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y); -TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m); TVG_EXPORT Tvg_Result tvg_shape_linear_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad); TVG_EXPORT Tvg_Result tvg_shape_radial_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad); @@ -166,6 +171,13 @@ TVG_EXPORT Tvg_Result tvg_radial_gradient_set(Tvg_Gradient* grad, float cx, floa TVG_EXPORT Tvg_Result tvg_gradient_color_stops(Tvg_Gradient* grad, const Tvg_Color_Stop* color_stop, uint32_t cnt); +/************************************************************************/ +/* Picture API */ +/************************************************************************/ +TVG_EXPORT Tvg_Paint* tvg_picture_new(); +TVG_EXPORT Tvg_Result tvg_picture_load(Tvg_Paint* paint, const char* path); +TVG_EXPORT Tvg_Result tvg_picture_get_viewbox(Tvg_Paint* paint, float* x, float* y, float* w, float* h); + #ifdef __cplusplus } #endif diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 9897584e..9f9646e3 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -131,6 +131,41 @@ TVG_EXPORT Tvg_Result tvg_canvas_sync(Tvg_Canvas* canvas) } +/************************************************************************/ +/* Paint API */ +/************************************************************************/ + +TVG_EXPORT Tvg_Result tvg_paint_del(Tvg_Paint* paint) +{ + delete(paint); + return TVG_RESULT_SUCCESS; +} + + +TVG_EXPORT Tvg_Result tvg_paint_scale(Tvg_Paint* paint, float factor) +{ + return (Tvg_Result) reinterpret_cast(paint)->scale(factor); +} + + +TVG_EXPORT Tvg_Result tvg_paint_rotate(Tvg_Paint* paint, float degree) +{ + return (Tvg_Result) reinterpret_cast(paint)->rotate(degree); +} + + +TVG_EXPORT Tvg_Result tvg_paint_translate(Tvg_Paint* paint, float x, float y) +{ + return (Tvg_Result) reinterpret_cast(paint)->translate(x, y); +} + + +TVG_EXPORT Tvg_Result tvg_paint_transform(Tvg_Paint* paint, const Tvg_Matrix* m) +{ + return (Tvg_Result) reinterpret_cast(paint)->transform(*(reinterpret_cast(m))); +} + + /************************************************************************/ /* Shape API */ /************************************************************************/ @@ -141,13 +176,6 @@ TVG_EXPORT Tvg_Paint* tvg_shape_new() } -TVG_EXPORT Tvg_Result tvg_shape_del(Tvg_Paint* paint) -{ - delete(paint); - return TVG_RESULT_SUCCESS; -} - - TVG_EXPORT Tvg_Result tvg_shape_reset(Tvg_Paint* paint) { return (Tvg_Result) reinterpret_cast(paint)->reset(); @@ -235,34 +263,38 @@ TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t return (Tvg_Result) reinterpret_cast(paint)->fill(r, g, b, a); } -TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor) + +TVG_EXPORT Tvg_Result tvg_shape_linear_gradient_set(Tvg_Paint* paint, Tvg_Gradient *gradient) { - return (Tvg_Result) reinterpret_cast(paint)->scale(factor); + return (Tvg_Result) reinterpret_cast(paint)->fill(unique_ptr((LinearGradient*)(gradient))); } -TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree) + +TVG_EXPORT Tvg_Result tvg_shape_radial_gradient_set(Tvg_Paint* paint, Tvg_Gradient *gradient) { - return (Tvg_Result) reinterpret_cast(paint)->rotate(degree); + return (Tvg_Result) reinterpret_cast(paint)->fill(unique_ptr((RadialGradient*)(gradient))); } -TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y) + +/************************************************************************/ +/* Picture API */ +/************************************************************************/ + +TVG_EXPORT Tvg_Paint* tvg_picture_new() { - return (Tvg_Result) reinterpret_cast(paint)->translate(x, y); + return (Tvg_Paint*) Picture::gen().release(); } -TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m) + +TVG_EXPORT Tvg_Result tvg_picture_load(Tvg_Paint* paint, const char* path) { - return (Tvg_Result) reinterpret_cast(paint)->transform(*(reinterpret_cast(m))); + return (Tvg_Result) reinterpret_cast(paint)->load(path); } -TVG_EXPORT Tvg_Result tvg_shape_linear_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad) -{ - return (Tvg_Result) reinterpret_cast(paint)->fill(unique_ptr((LinearGradient*)(grad))); -} -TVG_EXPORT Tvg_Result tvg_shape_radial_gradient_set(Tvg_Paint* paint, Tvg_Gradient *grad) +TVG_EXPORT Tvg_Result tvg_picture_get_viewbox(Tvg_Paint* paint, float* x, float* y, float* w, float* h) { - return (Tvg_Result) reinterpret_cast(paint)->fill(unique_ptr((RadialGradient*)(grad))); + return (Tvg_Result) reinterpret_cast(paint)->viewbox(x, y, w, h); } From cfbd419fbd717693be8c67eeaf7063b76f7cdf18 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 4 Aug 2020 09:57:37 +0900 Subject: [PATCH 200/244] test arc: revise sample code. Change-Id: I3629befdf5ce74ae7822929a059b4c95f2a9e88e --- test/testArc.cpp | 50 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/test/testArc.cpp b/test/testArc.cpp index c00f4643..b02196ef 100644 --- a/test/testArc.cpp +++ b/test/testArc.cpp @@ -10,27 +10,63 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Arc Line auto shape1 = tvg::Shape::gen(); - shape1->appendArc(150, 150, 100, 10, 270, false); + shape1->appendArc(150, 150, 80, 10, 180, false); shape1->stroke(255, 255, 255, 255); shape1->stroke(2); if (canvas->push(move(shape1)) != tvg::Result::Success) return; auto shape2 = tvg::Shape::gen(); - shape2->appendArc(500, 150, 125, 0, 300, true); + shape2->appendArc(400, 150, 80, 0, 300, false); shape2->stroke(255, 255, 255, 255); shape2->stroke(2); if (canvas->push(move(shape2)) != tvg::Result::Success) return; - //Pie Fill auto shape3 = tvg::Shape::gen(); - shape3->appendArc(150, 500, 100, 0, 75, true); - shape3->fill(255, 255, 255, 255); + shape3->appendArc(600, 150, 80, 300, 60, false); + shape3->stroke(255, 255, 255, 255); + shape3->stroke(2); if (canvas->push(move(shape3)) != tvg::Result::Success) return; + //Pie Line auto shape4 = tvg::Shape::gen(); - shape4->appendArc(500, 500, 150, 0, 215, true); - shape4->fill(255, 255, 255, 255); + shape4->appendArc(150, 400, 80, 10, 180, true); + shape4->stroke(255, 255, 255, 255); + shape4->stroke(2); if (canvas->push(move(shape4)) != tvg::Result::Success) return; + + auto shape5 = tvg::Shape::gen(); + shape5->appendArc(400, 400, 80, 0, 300, true); + shape5->stroke(255, 255, 255, 255); + shape5->stroke(2); + if (canvas->push(move(shape5)) != tvg::Result::Success) return; + + auto shape6 = tvg::Shape::gen(); + shape6->appendArc(600, 400, 80, 300, 60, true); + shape6->stroke(255, 255, 255, 255); + shape6->stroke(2); + if (canvas->push(move(shape6)) != tvg::Result::Success) return; + + //Pie Fill + auto shape7 = tvg::Shape::gen(); + shape7->appendArc(150, 650, 80, 10, 180, true); + shape7->fill(255, 255, 255, 255); + shape7->stroke(255, 0, 0, 255); + shape7->stroke(2); + if (canvas->push(move(shape7)) != tvg::Result::Success) return; + + auto shape8 = tvg::Shape::gen(); + shape8->appendArc(400, 650, 80, 0, 300, true); + shape8->fill(255, 255, 255, 255); + shape8->stroke(255, 0, 0, 255); + shape8->stroke(2); + if (canvas->push(move(shape8)) != tvg::Result::Success) return; + + auto shape9 = tvg::Shape::gen(); + shape9->appendArc(600, 650, 80, 300, 60, true); + shape9->fill(255, 255, 255, 255); + shape9->stroke(255, 0, 0, 255); + shape9->stroke(2); + if (canvas->push(move(shape9)) != tvg::Result::Success) return; } /************************************************************************/ From 9979e2cbf7cc8811c167ae6e0fd85e2a31e8c7f6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 5 Aug 2020 20:08:27 +0900 Subject: [PATCH 201/244] updated README prepare for github system. Change-Id: I0ee45e3ccb56f25f0252aad91a48151d62f9ed02 --- README | 7 ------- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index 31d0cbd9..00000000 --- a/README +++ /dev/null @@ -1,7 +0,0 @@ -Thor Vector Graphics 0.1.0 - -****************************************************************************** - - FOR ANY ISSUES PLEASE EMAIL: - -****************************************************************************** diff --git a/README.md b/README.md new file mode 100644 index 00000000..aac7ad0a --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# ThorVG + +ThorVG is a platform independent standalone C++ library for drawing vector-based shapes and SVG. + +# +## Contents +- [Building ThorVG](#building-thorvg) + - [Meson Build](#meson-build) +- [Quick Start](#quick-start) +- [Issues or Feature Requests?](#issues-or-feature-requests) +# +## Building ThorVG +thorvg supports [meson](https://mesonbuild.com/) build system. +# +### Meson Build +install [meson](http://mesonbuild.com/Getting-meson.html) and [ninja](https://ninja-build.org/) if not already installed. + +Run meson to configure ThorVG. +``` +meson build +``` +Run ninja to build & install ThorVG. +``` +ninja -C build install +``` +[Back to contents](#contents) +# +## Quick Start +ThorVG renders vector shapes on a given canvas buffer. + +You can initialize ThorVG engine first: +```cpp +tvg::Initializer::init(tvg::CanvasEngine::Sw); +``` +You can prepare a empty canvas for drawing on it. +```cpp +static uint32_t buffer[WIDTH * HEIGHT]; //canvas target buffer + +auto canvas = tvg::SwCanvas::gen(); //generate a canvas +canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //stride, w, h +``` + +Next you can draw shapes onto the canvas. +```cpp +auto shape = tvg::Shape::gen(); //generate a shape +shape->appendRect(0, 0, 200, 200, 0, 0); //x, y, w, h, rx, ry +shape->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH +shape->fill(255, 255, 0, 255); //r, g, b, a + +canvas->push(move(shape)); //push shape drawing command +``` +Begin rendering & finish it at a particular time. +```cpp +canvas->draw(); +canvas->sync(); +``` +Lastly, you can acquire the rendered image in buffer memory. + +[Back to contents](#contents) +# +## Issues or Feature Requests? +For immidiate assistant or support please reach us in [Gitter](https://gitter.im/thorvg-dev/community#) From 9f6b5eb59edb623e9909e8994255b86509ec61fc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 13:53:00 +0900 Subject: [PATCH 202/244] common: changed premultiplied color policy. Some user have no idea of premultiplied alpha concept, We suggest more user-friendly interfaces so that they don't confuse it. Now, this pre-multipying is acommplished by backend engines. Change-Id: Ifd84d56361cb56a8b98240bbd16690accf370bad --- src/lib/sw_engine/tvgSwCommon.h | 9 ++++++++- src/lib/sw_engine/tvgSwFill.cpp | 13 +++++++++++-- src/lib/sw_engine/tvgSwRaster.cpp | 8 ++++++++ test/testBlending.cpp | 6 +++--- test/testSceneTransform.cpp | 4 ++-- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 469ce0f1..b653a93c 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -244,6 +244,12 @@ static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t } +static inline uint8_t COLOR_ALPHA_MULTIPLY(uint32_t c, uint32_t a) +{ + return (c * a) >> 8; +} + + int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -290,7 +296,8 @@ bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterClear(Surface& surface); -inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) + +static inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { #ifdef THORVG_AVX_VECTOR_SUPPORT int32_t align = (8 - (offset % 8)) % 8; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 266acaa8..80540ccd 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -46,7 +46,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) if (pColors->a < 255) fill->translucent = true; - auto rgba = COLOR_ARGB_JOIN(pColors->r, pColors->g, pColors->b, pColors->a); + auto r = COLOR_ALPHA_MULTIPLY(pColors->r, pColors->a); + auto g = COLOR_ALPHA_MULTIPLY(pColors->g, pColors->a); + auto b = COLOR_ALPHA_MULTIPLY(pColors->b, pColors->a); + + auto rgba = COLOR_ARGB_JOIN(r, g, b, pColors->a); auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); auto pos = 1.5f * inc; uint32_t i = 0; @@ -65,7 +69,12 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) assert(curr && next); auto delta = 1.0f / (next->offset - curr->offset); if (next->a < 255) fill->translucent = true; - auto rgba2 = COLOR_ARGB_JOIN(next->r, next->g, next->b, next->a); + + auto r = COLOR_ALPHA_MULTIPLY(next->r, next->a); + auto g = COLOR_ALPHA_MULTIPLY(next->g, next->a); + auto b = COLOR_ALPHA_MULTIPLY(next->b, next->a); + + auto rgba2 = COLOR_ARGB_JOIN(r, g, b, next->a); while (pos < next->offset && i < GRADIENT_STOP_SIZE) { auto t = (pos - curr->offset) * delta; diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 5819bb86..ce2dc15d 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -285,6 +285,10 @@ bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id) bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + r = COLOR_ALPHA_MULTIPLY(r, a); + g = COLOR_ALPHA_MULTIPLY(g, a); + b = COLOR_ALPHA_MULTIPLY(b, a); + //Fast Track if (shape.rect) { auto region = _clipRegion(surface, shape.bbox); @@ -300,6 +304,10 @@ bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + r = COLOR_ALPHA_MULTIPLY(r, a); + g = COLOR_ALPHA_MULTIPLY(g, a); + b = COLOR_ALPHA_MULTIPLY(b, a); + if (a == 255) return _rasterSolidRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); return _rasterTranslucentRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); } diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 5477b3b6..59a4fad7 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -19,13 +19,13 @@ void tvgDrawCmds(tvg::Canvas* canvas) //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 + shape2->fill(255, 255, 0, 170); //r, g, b, a 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 + shape3->fill(255, 255, 255, 100); //r, g, b, a if (canvas->push(move(shape3)) != tvg::Result::Success) return; //Prepare Star @@ -41,7 +41,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape4->lineTo(26, 361); shape4->lineTo(146, 343); shape4->close(); - shape4->fill(200, 0, 200, 200); + shape4->fill(255, 0, 200, 200); if (canvas->push(move(shape4)) != tvg::Result::Success) return; //Prepare Opaque Ellipse diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 0d0be8e7..49558fb7 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -58,7 +58,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape4->lineTo(-173, 12.5); shape4->lineTo(-53, -5.5); shape4->close(); - shape4->fill(0, 0, 127, 127); + shape4->fill(0, 0, 255, 127); shape4->stroke(3); //width shape4->stroke(0, 0, 255, 255); //r, g, b, a scene2->push(move(shape4)); @@ -78,7 +78,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); shape5->close(); - shape5->fill(127, 0, 0, 127); + shape5->fill(255, 0, 0, 127); scene2->push(move(shape5)); scene2->translate(500, 350); From 28ae7a44114084fd1cd5df42edad6c1af7c9f7b3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 14:19:50 +0900 Subject: [PATCH 203/244] svg_loader: code refactoring remove macro code that does not helpful. This just decrease readibility and increase LOC. Change-Id: I9f1b11318447b45a9f96e7b00c18141fd9e71f9a --- src/loaders/svg_loader/tvgSvgLoader.cpp | 59 +++++++------------------ 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 9d58792b..36eac07f 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -1004,12 +1004,6 @@ static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const ch } -#define CIRCLE_DEF(Name, Field, Type) \ - { \ -#Name, Type, sizeof(#Name), offsetof(SvgCircleNode, Field) \ - } - - static constexpr struct { const char* tag; @@ -1017,9 +1011,9 @@ static constexpr struct int sz; size_t offset; } circleTags[] = { - CIRCLE_DEF(cx, cx, SvgParserLengthType::Horizontal), - CIRCLE_DEF(cy, cy, SvgParserLengthType::Vertical), - CIRCLE_DEF(r, r, SvgParserLengthType::Other) + {"cx", SvgParserLengthType::Horizontal, sizeof("cx"), offsetof(SvgCircleNode, cx)}, + {"cy", SvgParserLengthType::Vertical, sizeof("cy"), offsetof(SvgCircleNode, cy)}, + {"r", SvgParserLengthType::Other, sizeof("r"), offsetof(SvgCircleNode, r)} }; @@ -1063,12 +1057,6 @@ static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const } -#define ELLIPSE_DEF(Name, Field, Type) \ - { \ -#Name, Type, sizeof(#Name), offsetof(SvgEllipseNode, Field) \ - } - - static constexpr struct { const char* tag; @@ -1076,10 +1064,10 @@ static constexpr struct 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) + {"cx", SvgParserLengthType::Horizontal, sizeof("cx"), offsetof(SvgEllipseNode, cx)}, + {"cy", SvgParserLengthType::Vertical, sizeof("cy"), offsetof(SvgEllipseNode, cy)}, + {"rx", SvgParserLengthType::Horizontal, sizeof("rx"), offsetof(SvgEllipseNode, rx)}, + {"ry", SvgParserLengthType::Vertical, sizeof("ry"), offsetof(SvgEllipseNode, ry)} }; @@ -1202,13 +1190,6 @@ static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, cons return loader->svgParse->node; } - -#define RECT_DEF(Name, Field, Type) \ - { \ -#Name, Type, sizeof(#Name), offsetof(SvgRectNode, Field) \ - } - - static constexpr struct { const char* tag; @@ -1216,12 +1197,12 @@ static constexpr struct int sz; size_t offset; } rectTags[] = { - RECT_DEF(x, x, SvgParserLengthType::Horizontal), - RECT_DEF(y, y, 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) + {"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgRectNode, x)}, + {"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgRectNode, y)}, + {"width", SvgParserLengthType::Horizontal, sizeof("width"), offsetof(SvgRectNode, w)}, + {"height", SvgParserLengthType::Vertical, sizeof("height"), offsetof(SvgRectNode, h)}, + {"rx", SvgParserLengthType::Horizontal, sizeof("rx"), offsetof(SvgRectNode, rx)}, + {"ry", SvgParserLengthType::Vertical, sizeof("ry"), offsetof(SvgRectNode, ry)} }; @@ -1271,12 +1252,6 @@ static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const ch } -#define LINE_DEF(Name, Field, Type) \ - { \ -#Name, Type, sizeof(#Name), offsetof(SvgLineNode, Field) \ - } - - static constexpr struct { const char* tag; @@ -1284,10 +1259,10 @@ static constexpr struct 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) + {"x1", SvgParserLengthType::Horizontal, sizeof("x1"), offsetof(SvgLineNode, x1)}, + {"y1", SvgParserLengthType::Vertical, sizeof("y1"), offsetof(SvgLineNode, y1)}, + {"x2", SvgParserLengthType::Horizontal, sizeof("x2"), offsetof(SvgLineNode, x2)}, + {"y2", SvgParserLengthType::Vertical, sizeof("y2"), offsetof(SvgLineNode, y2)} }; From 4f0561697a16f3f0f893bcc8035a5fe257a7febd Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Thu, 6 Aug 2020 14:31:08 +0900 Subject: [PATCH 204/244] svg_loader: fix build error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is solving following build error. error: ‘offsetof’ was not declared in this scope Depending on build environment, this error could happen. Change-Id: I3512bb205f79a4d893cf33266db0a9109c0df886 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 36eac07f..8851f02a 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -17,6 +17,7 @@ #ifndef _TVG_SVG_LOADER_CPP_ #define _TVG_SVG_LOADER_CPP_ +#include #include "tvgSvgLoader.h" #include From 892f729265ca4125700299da7d432d1f42891635 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 14:35:56 +0900 Subject: [PATCH 205/244] svg_loader: code refactoring. ++neat Change-Id: I3b5552a2bbf09571ba01f0e31569b553913f400d --- src/loaders/svg_loader/tvgSvgLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 8851f02a..c8fd79d6 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -18,8 +18,8 @@ #define _TVG_SVG_LOADER_CPP_ #include -#include "tvgSvgLoader.h" #include +#include "tvgSvgLoader.h" /************************************************************************/ From ad48f7d8ba8576970a8736f7e1ce8807fd4d6b6a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 16:24:24 +0900 Subject: [PATCH 206/244] common: fix compile warnings. --Werror=unused-parameter Change-Id: I180464d770b1aa04afd39c30a3223a7cd48c78a4 --- src/lib/tvgCommon.h | 2 ++ src/lib/tvgRender.h | 6 +++--- src/meson.build | 1 - 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index dddac620..87c75813 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -35,6 +35,8 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#define TVG_UNUSED __attribute__ ((__unused__)) + #include "tvgBezier.h" #include "tvgLoader.h" #include "tvgLoaderMgr.h" diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 6a0897e8..63f920ef 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -51,10 +51,10 @@ class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { return nullptr; } - virtual bool dispose(const Shape& shape, void *data) { return false; } + virtual void* prepare(TVG_UNUSED const Shape& shape, TVG_UNUSED void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED RenderUpdateFlag flags) { return nullptr; } + virtual bool dispose(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return false; } virtual bool preRender() { return false; } - virtual bool render(const Shape& shape, void *data) { return false; } + virtual bool render(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return false; } virtual bool postRender() { return false; } virtual bool clear() { return false; } virtual bool flush() { return false; } diff --git a/src/meson.build b/src/meson.build index ced59a59..40d85cea 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,7 +12,6 @@ endif subdir('lib') subdir('loaders') subdir('bindings') -subdir('examples') thread_dep = meson.get_compiler('cpp').find_library('pthread') thorvg_lib_dep = [common_dep, loader_dep, binding_dep, thread_dep] From 7214559ad9ec43027b15ea717ded343daa3c22d1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 16:38:12 +0900 Subject: [PATCH 207/244] common: fix compile warnings. --Werror=unused-parameter Change-Id: If4c04e3e20b67be62b50c3b1e2e909dbd848eccc --- src/lib/gl_engine/tvgGlGeometry.cpp | 4 +- src/lib/gl_engine/tvgGlRenderer.cpp | 6 +-- src/lib/sw_engine/tvgSwRenderer.cpp | 4 +- src/lib/sw_engine/tvgSwShape.cpp | 2 +- src/loaders/svg_loader/tvgSimpleXmlParser.cpp | 2 +- src/loaders/svg_loader/tvgSimpleXmlParser.h | 2 +- src/loaders/svg_loader/tvgSvgLoader.cpp | 40 +++++++++---------- src/loaders/svg_loader/tvgSvgPath.cpp | 4 +- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp index eba6fbff..5728b566 100644 --- a/src/lib/gl_engine/tvgGlGeometry.cpp +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -63,7 +63,7 @@ bool GlGeometry::decomposeOutline(const Shape &shape) return true; } -bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpdateFlag flag) +bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape &shape, float strokeWd, RenderUpdateFlag flag) { for (auto& shapeGeometry : mPrimitives) { @@ -128,7 +128,7 @@ bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpda return true; } -bool GlGeometry::tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag) +bool GlGeometry::tesselate(TVG_UNUSED const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag) { for (auto& shapeGeometry : mPrimitives) { diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index d9acf619..c47f2e07 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -41,7 +41,7 @@ bool GlRenderer::clear() } -bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +bool GlRenderer::target(TVG_UNUSED uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { assert(w > 0 && h > 0); @@ -109,7 +109,7 @@ bool GlRenderer::render(const Shape& shape, void *data) } -bool GlRenderer::dispose(const Shape& shape, void *data) +bool GlRenderer::dispose(TVG_UNUSED const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; @@ -119,7 +119,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index aac6d8ef..9f618de1 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -129,7 +129,7 @@ bool SwRenderer::flush() } -bool SwRenderer::render(const Shape& sdata, void *data) +bool SwRenderer::render(TVG_UNUSED const Shape& sdata, TVG_UNUSED void *data) { //Do Nothing @@ -137,7 +137,7 @@ bool SwRenderer::render(const Shape& sdata, void *data) } -bool SwRenderer::dispose(const Shape& sdata, void *data) +bool SwRenderer::dispose(TVG_UNUSED const Shape& sdata, void *data) { auto task = static_cast(data); if (!task) return true; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 2165f424..e558436e 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -470,7 +470,7 @@ bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const } -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias) +bool shapeGenRle(SwShape& shape, TVG_UNUSED const Shape* sdata, const SwSize& clip, bool antiAlias) { //FIXME: Should we draw it? //Case: Stroke Line diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.cpp b/src/loaders/svg_loader/tvgSimpleXmlParser.cpp index 40814535..c55042f8 100644 --- a/src/loaders/svg_loader/tvgSimpleXmlParser.cpp +++ b/src/loaders/svg_loader/tvgSimpleXmlParser.cpp @@ -141,7 +141,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb do { \ size_t _sz = end - start; \ bool _ret; \ - _ret = func((void*)data, type, start, start - buf, _sz); \ + _ret = func((void*)data, type, start, _sz); \ if (!_ret) \ return false; \ } while (0) diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.h b/src/loaders/svg_loader/tvgSimpleXmlParser.h index 4e3b3a73..ee241cea 100644 --- a/src/loaders/svg_loader/tvgSimpleXmlParser.h +++ b/src/loaders/svg_loader/tvgSimpleXmlParser.h @@ -20,7 +20,7 @@ enum class SimpleXMLType DoctypeChild //!< \style; _toColor(value, &style->r, &style->g, &style->b, nullptr); } -static void _handleFillAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +static void _handleFillAttr(TVG_UNUSED 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); + _handlePaintAttr(&style->fill.paint, value); } -static void _handleStrokeAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +static void _handleStrokeAttr(TVG_UNUSED 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); + _handlePaintAttr(&style->stroke.paint, value); } -static void _handleStrokeOpacityAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +static void _handleStrokeOpacityAttr(TVG_UNUSED 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); @@ -780,47 +780,47 @@ static void _handleStrokeWidthAttr(SvgLoaderData* loader, SvgNode* node, const c } -static void _handleStrokeLineCapAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +static void _handleStrokeLineCapAttr(TVG_UNUSED 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) +static void _handleStrokeLineJoinAttr(TVG_UNUSED 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) +static void _handleFillRuleAttr(TVG_UNUSED 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) +static void _handleOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { node->style->opacity = _toOpacity(value); } -static void _handleFillOpacityAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +static void _handleFillOpacityAttr(TVG_UNUSED 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) +static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { node->transform = _parseTransformationMatrix(value); } -static void _handleDisplayAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { //TODO : The display attribute can have various values as well as "none". // The default is "inline" which means visible and "none" means invisible. @@ -946,7 +946,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) } -static SvgNode* _createDefsNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength) { SvgNode* node = _createNode(nullptr, SvgNodeType::Defs); simpleXmlParseAttributes(buf, bufLength, nullptr, node); @@ -954,7 +954,7 @@ static SvgNode* _createDefsNode(SvgLoaderData* loader, SvgNode* parent, const ch } -static SvgNode* _createGNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) { loader->svgParse->node = _createNode(parent, SvgNodeType::G); @@ -1907,7 +1907,7 @@ static constexpr struct }; -static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content, unsigned int length) +static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content) { unsigned int i; @@ -1999,7 +1999,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } -static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int offset, unsigned int length) +static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length) { SvgLoaderData* loader = (SvgLoaderData*)data; @@ -2013,7 +2013,7 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content break; } case SimpleXMLType::Close: { - _svgLoaderParerXmlClose(loader, content, length); + _svgLoaderParerXmlClose(loader, content); break; } case SimpleXMLType::Data: @@ -2238,7 +2238,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch } -static bool _svgLoaderParserForValidCheck(void* data, SimpleXMLType type, const char* content, unsigned int offset, unsigned int length) +static bool _svgLoaderParserForValidCheck(void* data, SimpleXMLType type, const char* content, unsigned int length) { SvgLoaderData* loader = (SvgLoaderData*)data; bool res = true;; diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index bd430272..03cde1e7 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -36,7 +36,7 @@ static bool _parseLong(char** content, int* number) return true; } -void _pathAppendArcTo(vector* cmds, vector* pts, float* arr, Point* cur, Point* curCtl, float x, float y, float rx, float ry, float angle, bool largeArc, bool sweep) +void _pathAppendArcTo(vector* cmds, vector* pts, Point* cur, Point* curCtl, float x, float y, float rx, float ry, float angle, bool largeArc, bool sweep) { float cxp, cyp, cx, cy; float sx, sy; @@ -394,7 +394,7 @@ static void _processCommand(vector* cmds, vector* pts, char } case 'a': case 'A': { - _pathAppendArcTo(cmds, pts, arr, cur, curCtl, arr[5], arr[6], arr[0], arr[1], arr[2], arr[3], arr[4]); + _pathAppendArcTo(cmds, pts, cur, curCtl, arr[5], arr[6], arr[0], arr[1], arr[2], arr[3], arr[4]); *cur = {arr[5] ,arr[6]}; break; } From ccde125cf50e46fc1904b8eead6fcdc9131d1b3e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 16:50:59 +0900 Subject: [PATCH 208/244] svg_loader: fix compile warnings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --warning: extra â^`^x;â^`^y [-Wpedantic] Change-Id: Ib40079628cac3fff6d991fd05d7d8073dd350361 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index f7401df3..9d345598 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -182,7 +182,7 @@ static constexpr struct }; -_PARSE_TAG(StrokeCap, lineCap, LineCap, lineCapTags, StrokeCap::Butt); +_PARSE_TAG(StrokeCap, lineCap, LineCap, lineCapTags, StrokeCap::Butt) /* parse the line join used during stroking a path. @@ -201,7 +201,7 @@ static constexpr struct }; -_PARSE_TAG(StrokeJoin, lineJoin, LineJoin, lineJoinTags, StrokeJoin::Miter); +_PARSE_TAG(StrokeJoin, lineJoin, LineJoin, lineJoinTags, StrokeJoin::Miter) /* parse the fill rule used during filling a path. @@ -218,7 +218,7 @@ static constexpr struct }; -_PARSE_TAG(SvgFillRule, fillRule, FillRule, fillRuleTags, SvgFillRule::Winding); +_PARSE_TAG(SvgFillRule, fillRule, FillRule, fillRuleTags, SvgFillRule::Winding) static string* _idFromUrl(const char* url) @@ -1536,8 +1536,8 @@ static constexpr struct return nullptr; \ } -FIND_FACTORY(Group, groupTags); -FIND_FACTORY(Graphics, graphicsTags); +FIND_FACTORY(Group, groupTags) +FIND_FACTORY(Graphics, graphicsTags) FillSpread _parseSpreadValue(const char* value) From d92fc13d8bd4885c51b08bf2ce7db0a2544b596a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 16:57:38 +0900 Subject: [PATCH 209/244] gl_engine: fix compile warnings this statement may fall through [-Werror=implicit-fallthrough=] Change-Id: I3cfc9b51697e229a524f6f75e10b83715b06ce13 --- src/lib/gl_engine/tvgGlGeometry.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp index 5728b566..2202c3fc 100644 --- a/src/lib/gl_engine/tvgGlGeometry.cpp +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -40,6 +40,7 @@ bool GlGeometry::decomposeOutline(const Shape &shape) case PathCommand::MoveTo: mPrimitives.push_back(GlPrimitive()); curPrimitive = &mPrimitives.back(); + __attribute__ ((fallthrough)); case PathCommand::LineTo: { if (curPrimitive) From 2555e82f0d75ecfaf10ad001811ea04cc2d3e080 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 17:06:36 +0900 Subject: [PATCH 210/244] fix compile warnings comparison of unsigned expression < 0 is always false [-Werror=type-limits] Change-Id: I8cee625056bcde1f2a3cb2b9ce704b33be5bd725 --- src/lib/sw_engine/tvgSwRle.cpp | 2 -- src/lib/tvgShape.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index d88a8372..049c1ca1 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -572,8 +572,6 @@ static bool _decomposeOutline(RleWorker& rw) for (uint32_t n = 0; n < outline->cntrsCnt; ++n) { auto last = outline->cntrs[n]; - if (last < 0) goto invalid_outline; - auto limit = outline->pts + last; assert(limit); diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 53c76899..053c348d 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -79,7 +79,7 @@ uint32_t Shape::pathCoords(const Point** pts) const noexcept Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept { - if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments; + if (cmdCnt == 0 || ptsCnt == 0 || !pts || !ptsCnt) return Result::InvalidArguments; IMPL->path->grow(cmdCnt, ptsCnt); IMPL->path->append(cmds, cmdCnt, pts, ptsCnt); From 083fa57c3e02c6623e9072403cd31bbc8190c833 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Tue, 4 Aug 2020 12:11:24 +0200 Subject: [PATCH 211/244] capi: Added C wrapper for setting spread type and test Change-Id: I3b4cd3740a82446fea60ed050814b03f32632f6d --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 6 ++++ test/testCapi.c | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index ecd7ee6a..17d663ef 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -169,6 +169,7 @@ TVG_EXPORT Tvg_Result tvg_gradient_del(Tvg_Gradient* grad); TVG_EXPORT Tvg_Result tvg_linear_gradient_set(Tvg_Gradient* grad, float x1, float y1, float x2, float y2); TVG_EXPORT Tvg_Result tvg_radial_gradient_set(Tvg_Gradient* grad, float cx, float cy, float radius); TVG_EXPORT Tvg_Result tvg_gradient_color_stops(Tvg_Gradient* grad, const Tvg_Color_Stop* color_stop, uint32_t cnt); +TVG_EXPORT Tvg_Result tvg_gradient_spread(Tvg_Gradient* grad, const Tvg_Stroke_Fill); /************************************************************************/ diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 9f9646e3..6e61d8f7 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -333,6 +333,12 @@ TVG_EXPORT Tvg_Result tvg_gradient_color_stops(Tvg_Gradient* grad, const Tvg_Col return (Tvg_Result) reinterpret_cast(grad)->colorStops(reinterpret_cast(color_stop), cnt); } +TVG_EXPORT Tvg_Result tvg_gradient_spread(Tvg_Gradient* grad, const Tvg_Stroke_Fill spread) +{ + return (Tvg_Result) reinterpret_cast(grad)->spread((FillSpread)spread); +} + + #ifdef __cplusplus } #endif diff --git a/test/testCapi.c b/test/testCapi.c index 3a307ab5..90c4e1d7 100644 --- a/test/testCapi.c +++ b/test/testCapi.c @@ -32,6 +32,7 @@ void testCapi() {.offset=1.0, .r=0, .g=0, .b=255, .a=255} }; + Tvg_Paint *shape1 = tvg_shape_new(); tvg_shape_append_rect(shape1, 500, 500, 100, 100, 30, 30); Tvg_Gradient* grad1 = tvg_radial_gradient_new(); @@ -43,13 +44,67 @@ void testCapi() {.offset=1.0, .r=0, .g=255, .b=255, .a=255} }; + Tvg_Paint *shape2 = tvg_shape_new(); + tvg_shape_append_rect(shape2, 400, 0, 800, 400, 20, 20); + Tvg_Gradient* grad2 = tvg_linear_gradient_new(); + tvg_linear_gradient_set(grad2, 400, 0, 450, 50); + Tvg_Color_Stop color_stops2[2] = + { + {.offset=0.0, .r=0, .g=0, .b=0, .a=255}, + {.offset=1, .r=255, .g=0, .b=0, .a=255}, + }; + + tvg_gradient_spread(grad2, TVG_STROKE_FILL_REPEAT); + + Tvg_Paint* shape3 = tvg_shape_new(); + tvg_shape_append_rect(shape3, 0, 400, 400, 800, 20, 20); + Tvg_Gradient* grad3 = tvg_linear_gradient_new(); + tvg_linear_gradient_set(grad3, 0, 400, 50, 450); + Tvg_Color_Stop color_stops3[2] = + { + {.offset=0.0, .r=0, .g=0, .b=0, .a=255}, + {.offset=1, .r=0, .g=255, .b=0, .a=255}, + }; + + tvg_gradient_spread(grad3, TVG_STROKE_FILL_REFLECT); + tvg_gradient_color_stops(grad, color_stops, 4); tvg_gradient_color_stops(grad1, color_stops1, 3); + tvg_gradient_color_stops(grad2, color_stops2, 2); + tvg_gradient_color_stops(grad3, color_stops3, 2); tvg_shape_linear_gradient_set(shape, grad); tvg_shape_radial_gradient_set(shape1, grad1); + tvg_shape_linear_gradient_set(shape2, grad2); + tvg_shape_linear_gradient_set(shape3, grad3); tvg_canvas_push(canvas, shape); tvg_canvas_push(canvas, shape1); + tvg_canvas_push(canvas, shape2); + tvg_canvas_push(canvas, shape3); + + Tvg_Paint* shape4 = tvg_shape_new(); + tvg_shape_append_rect(shape4, 700, 700, 100, 100, 20, 20); + Tvg_Gradient* grad4 = tvg_linear_gradient_new(); + tvg_linear_gradient_set(grad4, 700, 700, 800, 800); + Tvg_Color_Stop color_stops4[2] = + { + {.offset=0.0, .r=0, .g=0, .b=0, .a=255}, + {.offset=1, .r=0, .g=255, .b=0, .a=255}, + }; + tvg_gradient_color_stops(grad4, color_stops4, 2); + tvg_shape_linear_gradient_set(shape4, grad4); + + Tvg_Gradient* grad5 = tvg_linear_gradient_new(); + tvg_linear_gradient_set(grad5, 700, 700, 800, 800); + Tvg_Color_Stop color_stops5[2] = + { + {.offset=0.0, .r=0, .g=0, .b=255, .a=255}, + {.offset=1, .r=0, .g=255, .b=255, .a=255}, + }; + tvg_gradient_color_stops(grad5, color_stops5, 2); + tvg_shape_linear_gradient_set(shape4, grad5); + + tvg_canvas_push(canvas, shape4); tvg_canvas_draw(canvas); tvg_canvas_sync(canvas); From ef11d500ba0032f0d3b29e16a57ea12e87bede8c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 19:50:44 +0900 Subject: [PATCH 212/244] common: fix compiler warnings that loss data by mis-matched converision these conversions are intented, we explicity use casting so that compiler doesn't catch them anymore. Change-Id: I9d905c7562c43929b040d034e5ee0d14c6750a80 --- src/lib/sw_engine/tvgSwMath.cpp | 5 ++-- src/lib/sw_engine/tvgSwRaster.cpp | 4 ++-- src/lib/sw_engine/tvgSwStroke.cpp | 40 +++++++++++++++---------------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 540ddcfb..ad03e1a7 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -168,7 +168,7 @@ static void _rotate(SwPoint& pt, SwFixed theta) y = y - ((x + j) >> i); x = tmp; theta += *atan++; - }else { + } else { auto tmp = x - ((y + j) >> i); y = y + ((x + j) >> i); x = tmp; @@ -176,7 +176,8 @@ static void _rotate(SwPoint& pt, SwFixed theta) } } - pt = {x, y}; + pt.x = static_cast(x); + pt.y = static_cast(y); } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index ce2dc15d..6c9dba3e 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -29,8 +29,8 @@ static SwBBox _clipRegion(Surface& surface, SwBBox& in) if (bbox.min.x < 0) bbox.min.x = 0; if (bbox.min.y < 0) bbox.min.y = 0; - if (bbox.max.x > surface.w) bbox.max.x = surface.w; - if (bbox.max.y > surface.h) bbox.max.y = surface.h; + if (bbox.max.x > static_cast(surface.w)) bbox.max.x = surface.w; + if (bbox.max.y > static_cast(surface.h)) bbox.max.y = surface.h; return bbox; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 15cbf021..9a737a9f 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -142,7 +142,7 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff, SwStroke& stroke) { constexpr SwFixed ARC_CUBIC_ANGLE = SW_ANGLE_PI / 2; - SwPoint a = {radius, 0}; + SwPoint a = {static_cast(radius), 0}; mathRotate(a, angleStart); SCALE(stroke, a); a += center; @@ -163,7 +163,7 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius theta >>= 1; //compute end point - SwPoint b = {radius, 0}; + SwPoint b = {static_cast(radius), 0}; mathRotate(b, next); SCALE(stroke, b); b += center; @@ -171,12 +171,12 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius //compute first and second control points auto length = mathMulDiv(radius, mathSin(theta) * 4, (0x10000L + mathCos(theta)) * 3); - SwPoint a2 = {length, 0}; + SwPoint a2 = {static_cast(length), 0}; mathRotate(a2, angle + rotate); SCALE(stroke, a2); a2 += a; - SwPoint b2 = {length, 0}; + SwPoint b2 = {static_cast(length), 0}; mathRotate(b2, next - rotate); SCALE(stroke, b2); b2 += b; @@ -277,7 +277,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) //this is a bevel (broken angle) if (bevel) { - SwPoint delta = {stroke.width, 0}; + SwPoint delta = {static_cast(stroke.width), 0}; mathRotate(delta, stroke.angleOut + rotate); SCALE(stroke, delta); delta += stroke.center; @@ -286,7 +286,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) //this is a miter (intersection) } else { auto length = mathDivide(stroke.width, thcos); - SwPoint delta = {length, 0}; + SwPoint delta = {static_cast(length), 0}; mathRotate(delta, phi); SCALE(stroke, delta); delta += stroke.center; @@ -295,7 +295,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) /* Now add and end point Only needed if not lineto (lineLength is zero for curves) */ if (lineLength == 0) { - delta = {stroke.width, 0}; + delta = {static_cast(stroke.width), 0}; mathRotate(delta, stroke.angleOut + rotate); SCALE(stroke, delta); delta += stroke.center; @@ -324,7 +324,7 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) auto rotate = SIDE_TO_ROTATE(side); if (!intersect) { - delta = {stroke.width, 0}; + delta = {static_cast(stroke.width), 0}; mathRotate(delta, stroke.angleOut + rotate); SCALE(stroke, delta); delta += stroke.center; @@ -366,7 +366,7 @@ void _processCorner(SwStroke& stroke, SwFixed lineLength) void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { - SwPoint delta = {stroke.width, 0}; + SwPoint delta = {static_cast(stroke.width), 0}; mathRotate(delta, startAngle + SW_ANGLE_PI2); SCALE(stroke, delta); @@ -397,7 +397,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) auto lineLength = mathLength(delta); auto angle = mathAtan(delta); - delta = {stroke.width, 0}; + delta = {static_cast(stroke.width), 0}; mathRotate(delta, angle + SW_ANGLE_PI2); SCALE(stroke, delta); @@ -509,18 +509,18 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl auto rotate = SIDE_TO_ROTATE(side); //compute control points - SwPoint _ctrl1 = {length1, 0}; + SwPoint _ctrl1 = {static_cast(length1), 0}; mathRotate(_ctrl1, phi1 + rotate); SCALE(stroke, _ctrl1); _ctrl1 += arc[2]; - SwPoint _ctrl2 = {length2, 0}; + SwPoint _ctrl2 = {static_cast(length2), 0}; mathRotate(_ctrl2, phi2 + rotate); SCALE(stroke, _ctrl2); _ctrl2 += arc[1]; //compute end point - SwPoint _end = {stroke.width, 0}; + SwPoint _end = {static_cast(stroke.width), 0}; mathRotate(_end, angleOut + rotate); SCALE(stroke, _end); _end += arc[0]; @@ -544,7 +544,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl auto sinB = abs(mathSin(beta - gamma)); auto alen = mathMulDiv(blen, sinA, sinB); - SwPoint delta = {alen, 0}; + SwPoint delta = {static_cast(alen), 0}; mathRotate(delta, beta); delta += _start; @@ -581,22 +581,22 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) auto rotate = SIDE_TO_ROTATE(side); auto border = stroke.borders + side; - SwPoint delta = {stroke.width, 0}; + SwPoint delta = {static_cast(stroke.width), 0}; mathRotate(delta, angle); SCALE(stroke, delta); - SwPoint delta2 = {stroke.width, 0}; + SwPoint delta2 = {static_cast(stroke.width), 0}; mathRotate(delta2, angle + rotate); SCALE(stroke, delta2); delta += stroke.center + delta2; _borderLineTo(border, delta, false); - delta = {stroke.width, 0}; + delta = {static_cast(stroke.width), 0}; mathRotate(delta, angle); SCALE(stroke, delta); - delta2 = {stroke.width, 0}; + delta2 = {static_cast(stroke.width), 0}; mathRotate(delta2, angle - rotate); SCALE(stroke, delta2); delta += delta2 + stroke.center; @@ -614,14 +614,14 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) auto rotate = SIDE_TO_ROTATE(side); auto border = stroke.borders + side; - SwPoint delta = {stroke.width, 0}; + SwPoint delta = {static_cast(stroke.width), 0}; mathRotate(delta, angle + rotate); SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); - delta = {stroke.width, 0}; + delta = {static_cast(stroke.width), 0}; mathRotate(delta, angle - rotate); SCALE(stroke, delta); delta += stroke.center; From 4959db9c048f297d41ccd56c689621585d032fa4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 20:09:15 +0900 Subject: [PATCH 213/244] svg_loader: fix compile warnings. -- warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move] Change-Id: I7dec55fe117d27217b7a29d5983b23cedadacb71 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 4d7a27a7..603409eb 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -111,7 +111,7 @@ unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Sha fillGrad->colorStops(stops, stopCount); free(stops); } - return move(fillGrad); + return fillGrad; } @@ -197,7 +197,7 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Sha fillGrad->colorStops(stops, stopCount); free(stops); } - return move(fillGrad); + return fillGrad; } @@ -342,7 +342,7 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, } } } - return move(scene); + return scene; } return nullptr; } From 7839c662d706907fdfa136370465b2152c9864b0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 20:17:34 +0900 Subject: [PATCH 214/244] sw_engine: fix one last compile warning. casting to loss data in converting data type. Change-Id: I4c9b45b1c015579807a2d44e0ff2734bd2f655f3 --- src/lib/sw_engine/tvgSwStroke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 9a737a9f..08390faf 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -333,7 +333,7 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) //compute median angle auto phi = stroke.angleIn + theta; auto thcos = mathCos(theta); - delta = {mathDivide(stroke.width, thcos), 0}; + delta = {static_cast(mathDivide(stroke.width, thcos)), 0}; mathRotate(delta, phi + rotate); SCALE(stroke, delta); delta += stroke.center; From 9893af979f26e3ea09eff03e9d5c514cb4d19ec2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 16:50:32 +0900 Subject: [PATCH 215/244] replace license from Apache 2.0 to MIT Change-Id: I61f7cb2b0e407bc035f3b2ec7da9b7f230057e24 --- LICENSE | 203 +----------------- inc/thorvg.h | 16 -- inc/thorvg_capi.h | 17 -- meson.build | 2 +- packaging/thorvg.spec | 2 +- src/bindings/capi/tvgCapi.cpp | 33 +-- src/examples/main.cpp | 16 -- src/lib/gl_engine/tvgGlCommon.h | 22 ++ src/lib/gl_engine/tvgGlGeometry.cpp | 22 ++ src/lib/gl_engine/tvgGlGeometry.h | 22 ++ src/lib/gl_engine/tvgGlGpuBuffer.cpp | 22 ++ src/lib/gl_engine/tvgGlGpuBuffer.h | 22 ++ src/lib/gl_engine/tvgGlProgram.cpp | 22 ++ src/lib/gl_engine/tvgGlProgram.h | 22 ++ src/lib/gl_engine/tvgGlRenderer.cpp | 34 +-- src/lib/gl_engine/tvgGlRenderer.h | 34 +-- src/lib/gl_engine/tvgGlShader.cpp | 22 ++ src/lib/gl_engine/tvgGlShader.h | 22 ++ src/lib/gl_engine/tvgGlShaderSrc.cpp | 22 ++ src/lib/gl_engine/tvgGlShaderSrc.h | 22 ++ src/lib/sw_engine/tvgSwCommon.h | 35 +-- src/lib/sw_engine/tvgSwFill.cpp | 35 +-- src/lib/sw_engine/tvgSwMath.cpp | 35 +-- src/lib/sw_engine/tvgSwRaster.cpp | 35 +-- src/lib/sw_engine/tvgSwRenderer.cpp | 33 +-- src/lib/sw_engine/tvgSwRenderer.h | 33 +-- src/lib/sw_engine/tvgSwRle.cpp | 33 +-- src/lib/sw_engine/tvgSwShape.cpp | 33 +-- src/lib/sw_engine/tvgSwStroke.cpp | 35 +-- src/lib/tvgBezier.cpp | 33 +-- src/lib/tvgBezier.h | 33 +-- src/lib/tvgCanvas.cpp | 33 +-- src/lib/tvgCanvasImpl.h | 33 +-- src/lib/tvgCommon.h | 33 +-- src/lib/tvgFill.cpp | 33 +-- src/lib/tvgGlCanvas.cpp | 33 +-- src/lib/tvgInitializer.cpp | 33 +-- src/lib/tvgLinearGradient.cpp | 33 +-- src/lib/tvgLoader.h | 33 +-- src/lib/tvgLoaderMgr.cpp | 33 +-- src/lib/tvgLoaderMgr.h | 33 +-- src/lib/tvgPaint.cpp | 33 +-- src/lib/tvgPaint.h | 33 +-- src/lib/tvgPicture.cpp | 33 +-- src/lib/tvgPictureImpl.h | 33 +-- src/lib/tvgRadialGradient.cpp | 33 +-- src/lib/tvgRender.cpp | 33 +-- src/lib/tvgRender.h | 33 +-- src/lib/tvgScene.cpp | 33 +-- src/lib/tvgSceneImpl.h | 33 +-- src/lib/tvgShape.cpp | 33 +-- src/lib/tvgShapeImpl.h | 33 +-- src/lib/tvgShapePath.h | 33 +-- src/lib/tvgSwCanvas.cpp | 33 +-- src/loaders/svg_loader/tvgSimpleXmlParser.cpp | 22 ++ src/loaders/svg_loader/tvgSimpleXmlParser.h | 22 ++ src/loaders/svg_loader/tvgSvgLoader.cpp | 33 +-- src/loaders/svg_loader/tvgSvgLoader.h | 33 +-- src/loaders/svg_loader/tvgSvgLoaderCommon.h | 34 +-- src/loaders/svg_loader/tvgSvgPath.cpp | 22 ++ src/loaders/svg_loader/tvgSvgPath.h | 22 ++ src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 34 +-- src/loaders/svg_loader/tvgSvgSceneBuilder.h | 34 +-- 63 files changed, 1143 insertions(+), 844 deletions(-) diff --git a/LICENSE b/LICENSE index 8a7fbe45..8becbac1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,202 +1,7 @@ +Copyright 2020 (see AUTHORS) - Apache License - Version 2.0, January 2016 - http://www.apache.org/licenses/ +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/inc/thorvg.h b/inc/thorvg.h index d22acbb2..97592459 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -1,19 +1,3 @@ -/* - * 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 _THORVG_H_ #define _THORVG_H_ diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 17d663ef..763d71b2 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -1,20 +1,3 @@ -/* - * 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 __THORVG_CAPI_H__ #define __THORVG_CAPI_H__ diff --git a/meson.build b/meson.build index 6da6d269..981e7535 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project('thorvg', 'cpp', default_options : ['buildtype=debugoptimized', 'werror=false', 'optimization=s'], version : '0.1.0', - license : 'Apache-2.0') + license : 'MIT') config_h = configuration_data() diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index e4b37362..8b7f6f54 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -3,7 +3,7 @@ Summary: Thor Vector Graphics Library Version: 0.0.1 Release: 1 Group: Graphics System/Rendering Engine -License: Apache-2.0 +License: MIT URL: https://github.com/samsung/thorvg Source0: %{name}-%{version}.tar.gz diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 6e61d8f7..e05435a5 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/src/examples/main.cpp b/src/examples/main.cpp index fee1aa8d..8bd265a2 100644 --- a/src/examples/main.cpp +++ b/src/examples/main.cpp @@ -1,19 +1,3 @@ -/* - * 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. - * - */ #include using namespace std; diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h index c5969545..db137f22 100644 --- a/src/lib/gl_engine/tvgGlCommon.h +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_GL_COMMON_H_ #define _TVG_GL_COMMON_H_ diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp index 2202c3fc..e89077d7 100644 --- a/src/lib/gl_engine/tvgGlGeometry.cpp +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "tvgGlGpuBuffer.h" #include "tvgGlGeometry.h" #include "tvgGlCommon.h" diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h index 9f87efa9..e5f1b033 100644 --- a/src/lib/gl_engine/tvgGlGeometry.h +++ b/src/lib/gl_engine/tvgGlGeometry.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_GL_GEOMETRY_H_ #define _TVG_GL_GEOMETRY_H_ diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp index 2aaba198..f4024252 100644 --- a/src/lib/gl_engine/tvgGlGpuBuffer.cpp +++ b/src/lib/gl_engine/tvgGlGpuBuffer.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "tvgGlCommon.h" #include "tvgGlGpuBuffer.h" diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h index 3116001c..e3ed97cf 100644 --- a/src/lib/gl_engine/tvgGlGpuBuffer.h +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_GL_GPU_BUFFER_H_ #define _TVG_GL_GPU_BUFFER_H_ diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp index dbf87622..9d03849b 100644 --- a/src/lib/gl_engine/tvgGlProgram.cpp +++ b/src/lib/gl_engine/tvgGlProgram.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "tvgGlCommon.h" #include "tvgGlProgram.h" diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h index 5df0e4f1..ccdb258c 100644 --- a/src/lib/gl_engine/tvgGlProgram.h +++ b/src/lib/gl_engine/tvgGlProgram.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_GL_PROGRAM_H_ #define _TVG_GL_PROGRAM_H_ diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index c47f2e07..0276c8f1 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -1,19 +1,25 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + #ifndef _TVG_GL_RENDERER_CPP_ #define _TVG_GL_RENDERER_CPP_ diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 7d0972a7..9c893b3a 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -1,19 +1,25 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + #ifndef _TVG_GL_RENDERER_H_ #define _TVG_GL_RENDERER_H_ diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp index a655159c..62c69ed7 100644 --- a/src/lib/gl_engine/tvgGlShader.cpp +++ b/src/lib/gl_engine/tvgGlShader.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "tvgGlCommon.h" #include "tvgGlShader.h" diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h index 85bf1160..75c8f377 100644 --- a/src/lib/gl_engine/tvgGlShader.h +++ b/src/lib/gl_engine/tvgGlShader.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_GL_SHADER_H_ #define _TVG_GL_SHADER_H_ diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp index cdd25f0f..135ef435 100644 --- a/src/lib/gl_engine/tvgGlShaderSrc.cpp +++ b/src/lib/gl_engine/tvgGlShaderSrc.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "tvgGlShaderSrc.h" const char* COLOR_VERT_SHADER = diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h index e6d3b911..22993547 100644 --- a/src/lib/gl_engine/tvgGlShaderSrc.h +++ b/src/lib/gl_engine/tvgGlShaderSrc.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_GL_SHADERSRC_H_ #define _TVG_GL_SHADERSRC_H_ diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index b653a93c..e7566c18 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -1,18 +1,23 @@ -/* - * 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. - * +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 80540ccd..ae938fd3 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -1,18 +1,23 @@ -/* - * 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. - * +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_FILL_CPP_ #define _TVG_SW_FILL_CPP_ diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index ad03e1a7..36760481 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -1,18 +1,23 @@ -/* - * 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. - * +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_MATH_H_ #define _TVG_SW_MATH_H_ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 6c9dba3e..98579c52 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -1,18 +1,23 @@ -/* - * 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. - * +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_RASTER_CPP_ #define _TVG_SW_RASTER_CPP_ diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 9f618de1..92fddfb1 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_RENDERER_CPP_ #define _TVG_SW_RENDERER_CPP_ diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 3669d034..b6c7a196 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_RENDERER_H_ #define _TVG_SW_RENDERER_H_ diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 049c1ca1..191e59ec 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_RLE_H_ #define _TVG_SW_RLE_H_ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index e558436e..ed7c1e47 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_SHAPE_H_ #define _TVG_SW_SHAPE_H_ diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 08390faf..d8902da9 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -1,18 +1,23 @@ -/* - * 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. - * +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SW_STROKER_H_ #define _TVG_SW_STROKER_H_ diff --git a/src/lib/tvgBezier.cpp b/src/lib/tvgBezier.cpp index 1aa2dab5..0ed4ed21 100644 --- a/src/lib/tvgBezier.cpp +++ b/src/lib/tvgBezier.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_BEZIER_CPP_ #define _TVG_BEZIER_CPP_ diff --git a/src/lib/tvgBezier.h b/src/lib/tvgBezier.h index aa7d77f0..df21719d 100644 --- a/src/lib/tvgBezier.h +++ b/src/lib/tvgBezier.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_BEZIER_H_ #define _TVG_BEZIER_H_ diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index e9db4610..7e7250aa 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_CANVAS_CPP_ #define _TVG_CANVAS_CPP_ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index adcd472e..aeab1f54 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_CANVAS_IMPL_H_ #define _TVG_CANVAS_IMPL_H_ diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 87c75813..0c73b914 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_COMMON_H_ #define _TVG_COMMON_H_ diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp index fe3ef3f7..d1240f0d 100644 --- a/src/lib/tvgFill.cpp +++ b/src/lib/tvgFill.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_FILL_CPP_ #define _TVG_FILL_CPP_ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 4502498e..755d8eb7 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_GLCANVAS_CPP_ #define _TVG_GLCANVAS_CPP_ diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index 468178ec..20092997 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_INITIALIZER_CPP_ #define _TVG_INITIALIZER_CPP_ diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp index 88be20cb..68a0d8aa 100644 --- a/src/lib/tvgLinearGradient.cpp +++ b/src/lib/tvgLinearGradient.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_LINEAR_GRADIENT_CPP_ #define _TVG_LINEAR_GRADIENT_CPP_ diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h index 8f5bb49f..c714f92c 100644 --- a/src/lib/tvgLoader.h +++ b/src/lib/tvgLoader.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_LOADER_H_ #define _TVG_LOADER_H_ diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index ae657322..208ba794 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_LOADER_MGR_CPP_ #define _TVG_LOADER_MGR_CPP_ diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h index 0d37012f..7c9d52e1 100644 --- a/src/lib/tvgLoaderMgr.h +++ b/src/lib/tvgLoaderMgr.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_LOADER_MGR_H_ #define _TVG_LOADER_MGR_H_ diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index dacbffb7..7984ac0e 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_PAINT_CPP_ #define _TVG_PAINT_CPP_ diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 7d43df01..f331fefd 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_PAINT_H_ #define _TVG_PAINT_H_ diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index 03701636..7595afab 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_PICTURE_CPP_ #define _TVG_PICTURE_CPP_ diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index ed1c678d..45e2e9d8 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_PICTURE_IMPL_H_ #define _TVG_PICTURE_IMPL_H_ diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp index 154e1631..179c51e3 100644 --- a/src/lib/tvgRadialGradient.cpp +++ b/src/lib/tvgRadialGradient.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_RADIAL_GRADIENT_CPP_ #define _TVG_RADIAL_GRADIENT_CPP_ diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 89edcb1e..b1e8cf0e 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_RENDER_CPP_ #define _TVG_RENDER_CPP_ diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 63f920ef..85292d21 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_RENDER_H_ #define _TVG_RENDER_H_ diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index ff3aca81..9120e00b 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SCENE_CPP_ #define _TVG_SCENE_CPP_ diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index c4cbb235..68939c3b 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SCENE_IMPL_H_ #define _TVG_SCENE_IMPL_H_ diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 053c348d..8b171869 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SHAPE_CPP_ #define _TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index ab11db03..1b85c07b 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SHAPE_IMPL_H_ #define _TVG_SHAPE_IMPL_H_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 38ed3eb7..75c86ad6 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SHAPE_PATH_CPP_ #define _TVG_SHAPE_PATH_CPP_ diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 4c61eaa6..bb504705 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SWCANVAS_CPP_ #define _TVG_SWCANVAS_CPP_ diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.cpp b/src/loaders/svg_loader/tvgSimpleXmlParser.cpp index c55042f8..932d0717 100644 --- a/src/loaders/svg_loader/tvgSimpleXmlParser.cpp +++ b/src/loaders/svg_loader/tvgSimpleXmlParser.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "tvgSimpleXmlParser.h" static const char* _simpleXmlFindWhiteSpace(const char* itr, const char* itrEnd) diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.h b/src/loaders/svg_loader/tvgSimpleXmlParser.h index ee241cea..a9f999db 100644 --- a/src/loaders/svg_loader/tvgSimpleXmlParser.h +++ b/src/loaders/svg_loader/tvgSimpleXmlParser.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_SIMPLE_XML_PARSER_H_ #define _TVG_SIMPLE_XML_PARSER_H_ diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 9d345598..0529ec80 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SVG_LOADER_CPP_ #define _TVG_SVG_LOADER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h index 9a02a86d..7f0ce3cd 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.h +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -1,18 +1,23 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _TVG_SVG_LOADER_H_ #define _TVG_SVG_LOADER_H_ diff --git a/src/loaders/svg_loader/tvgSvgLoaderCommon.h b/src/loaders/svg_loader/tvgSvgLoaderCommon.h index 2f1af74f..5bf83334 100644 --- a/src/loaders/svg_loader/tvgSvgLoaderCommon.h +++ b/src/loaders/svg_loader/tvgSvgLoaderCommon.h @@ -1,20 +1,24 @@ /* - * 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. - * - */ + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #ifndef _TVG_SVG_LOADER_COMMON_H_ #define _TVG_SVG_LOADER_COMMON_H_ diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index 03cde1e7..2d3b86a9 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef __TVG_SVG_PATH_CPP_ #define __TVG_SVG_PATH_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgPath.h b/src/loaders/svg_loader/tvgSvgPath.h index 47a35d87..9d853d19 100644 --- a/src/loaders/svg_loader/tvgSvgPath.h +++ b/src/loaders/svg_loader/tvgSvgPath.h @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef _TVG_SVG_PATH_H_ #define _TVG_SVG_PATH_H_ diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 603409eb..091f78af 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -1,19 +1,25 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + #ifndef _TVG_SVG_SCENE_BUILDER_CPP_ #define _TVG_SVG_SCENE_BUILDER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.h b/src/loaders/svg_loader/tvgSvgSceneBuilder.h index 1bd779b1..66f50472 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.h +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.h @@ -1,19 +1,25 @@ /* - * 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. - * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + #ifndef _TVG_SVG_SCENE_BUILDER_H_ #define _TVG_SVG_SCENE_BUILDER_H_ From 2c9610bf6abac5c6332abe34cfc8e843ba60c884 Mon Sep 17 00:00:00 2001 From: Michal Szczecinski Date: Tue, 11 Aug 2020 12:11:06 +0200 Subject: [PATCH 216/244] common_shape: fixed arc api to draw rectangles lower than 0. Absolute value is used to calculate number of bezier curves used to approximate arc. Change-Id: Idedd7fd73590d569417fc646fc7febdaaab65857 --- src/lib/tvgShape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 8b171869..c688ffc7 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -167,7 +167,7 @@ Result Shape::appendArc(float cx, float cy, float radius, float startAngle, floa startAngle = (startAngle * M_PI) / 180; sweep = sweep * M_PI / 180; - auto nCurves = ceil(sweep / M_PI_HALF); + auto nCurves = ceil(abs(sweep / M_PI_HALF)); auto fract = fmod(sweep, M_PI_HALF); fract = (fract < std::numeric_limits::epsilon()) ? M_PI_HALF : fract; From a12f346425774932f4fc18a4ad9dc75288ba17d5 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:00:09 +0900 Subject: [PATCH 217/244] sw_engine: remove unnecessary assert() call Change-Id: I7c665bab4ef867f912ea738480e6d9b2b63e014e --- src/lib/sw_engine/tvgSwStroke.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index d8902da9..edba638d 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -880,7 +880,6 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) for (uint32_t i = 0; i < outline.cntrsCnt; ++i) { auto last = outline.cntrs[i]; //index of last point in contour auto limit = outline.pts + last; - assert(limit); //Skip empty points if (last <= first) { @@ -889,12 +888,8 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) } auto start = outline.pts[first]; - auto pt = outline.pts + first; - assert(pt); auto types = outline.types + first; - assert(types); - auto type = types[0]; //A contour cannot start with a cubic control point @@ -903,8 +898,8 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) _beginSubPath(stroke, start, outline.opened); while (pt < limit) { - assert(++pt); - assert(++types); + ++pt; + ++types; //emit a signel line_to if (types[0] == SW_CURVE_TYPE_POINT) { From 0b95e55e2ff01f0a41ac787c68dadc5889c42d28 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:02:31 +0900 Subject: [PATCH 218/244] gl_engine renderer: initialize member data in default. static analizyer bothers us due to this. we'd rather initialize members for free of them. Change-Id: Ifa6ebffdfdcb31d2dd3a1d6b911226928f654e3f --- src/lib/gl_engine/tvgGlRenderer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 9c893b3a..9a86bae1 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -30,7 +30,7 @@ class GlRenderer : public RenderMethod { public: - Surface surface; + Surface surface = {nullptr, 0, 0, 0}; void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; @@ -54,9 +54,9 @@ private: void initShaders(); void drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag); - unique_ptr mColorProgram; - int32_t mColorUniformLoc; - uint32_t mVertexAttrLoc; + unique_ptr mColorProgram = nullptr; + int32_t mColorUniformLoc = 0; + uint32_t mVertexAttrLoc = 0; }; #endif /* _TVG_GL_RENDERER_H_ */ From 9ce44de97010d3200e81c9e12da02b18028ea423 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:08:34 +0900 Subject: [PATCH 219/244] svg_loader: initialize member data in default. static analizyer bothers us due to this. we'd rather initialize members for free of them. Change-Id: I6dd76427b0fe2f9ff09034fe3ab11080a8d72a2e --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 1 - src/loaders/svg_loader/tvgSvgSceneBuilder.h | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 091f78af..faea2ec4 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -373,7 +373,6 @@ unique_ptr SvgSceneBuilder::build(SvgNode* node) viewBox.w = node->node.doc.vw; viewBox.h = node->node.doc.vh; preserveAspect = node->node.doc.preserveAspect; - staticViewBox = true; return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h, 255); } diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.h b/src/loaders/svg_loader/tvgSvgSceneBuilder.h index 66f50472..0f93d961 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.h +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.h @@ -32,12 +32,8 @@ 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; + } viewBox = {0, 0, 0, 0}; + bool preserveAspect = false; public: SvgSceneBuilder(); From 199b54c5caf8dd8ef25b065d310bd08ae7fb661b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:13:17 +0900 Subject: [PATCH 220/244] common: code refactoring. we can return nullptr directly here. Change-Id: I35e04dc9850b3b3b75e1e02b4c81a61b79f2c43f --- src/lib/tvgGlCanvas.cpp | 2 +- src/lib/tvgSwCanvas.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 755d8eb7..7f2c04b7 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -86,7 +86,7 @@ unique_ptr GlCanvas::gen() noexcept return canvas; #endif - return unique_ptr(nullptr); + return nullptr; } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index bb504705..e958ea26 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -85,7 +85,7 @@ unique_ptr SwCanvas::gen() noexcept return canvas; #endif - return unique_ptr(nullptr); + return nullptr; } #endif /* _TVG_SWCANVAS_CPP_ */ From 7b004363f9826faba339fee469e777423fa9c079 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:15:33 +0900 Subject: [PATCH 221/244] sw_engine renderer: initialize member data in default. static analizyer bothers us due to this. we'd rather initialize members for free of them. Change-Id: I23b769b94be7514a8bf6e6d683ddb90b3cd613c4 --- src/lib/sw_engine/tvgSwRenderer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index b6c7a196..d34c83ce 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -52,7 +52,7 @@ public: void doRender(); //Internally used for threading private: - Surface surface; + Surface surface = {nullptr, 0, 0, 0}; future progress; queue prepareTasks; queue renderTasks; From 3dc3cfd8c0726ad2571a101747df724638cc8f14 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:27:02 +0900 Subject: [PATCH 222/244] sw_engine: fix data overflow case. Change-Id: I01f90a8a6b3bca38142c8c16d1990b5b1a09d081 --- src/lib/sw_engine/tvgSwStroke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index edba638d..70eb1ca7 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -35,7 +35,7 @@ static constexpr auto SW_STROKE_TAG_END = 8; static inline SwFixed SIDE_TO_ROTATE(const int32_t s) { - return (SW_ANGLE_PI2 - (s) * SW_ANGLE_PI); + return (SW_ANGLE_PI2 - static_cast(s) * SW_ANGLE_PI); } From 8abef404cf026d7740c835c393ca516d7d17d849 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:29:23 +0900 Subject: [PATCH 223/244] sw_engine: remove unnecessary assert() call Change-Id: I8cb249b6b7f32992f7ce9c86e408546c14856330 --- src/lib/sw_engine/tvgSwRle.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 191e59ec..6f1f2f2d 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -571,21 +571,14 @@ static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, static bool _decomposeOutline(RleWorker& rw) { auto outline = rw.outline; - assert(outline); - auto first = 0; //index of first point in contour for (uint32_t n = 0; n < outline->cntrsCnt; ++n) { auto last = outline->cntrs[n]; auto limit = outline->pts + last; - assert(limit); - auto start = UPSCALE(outline->pts[first]); - auto pt = outline->pts + first; - assert(pt); auto types = outline->types + first; - assert(types); /* A contour cannot start with a cubic control point! */ if (types[0] == SW_CURVE_TYPE_CUBIC) goto invalid_outline; @@ -593,8 +586,8 @@ static bool _decomposeOutline(RleWorker& rw) _moveTo(rw, UPSCALE(outline->pts[first])); while (pt < limit) { - assert(++pt); - assert(++types); + ++pt; + ++types; //emit a single line_to if (types[0] == SW_CURVE_TYPE_POINT) { From 3b9bb51321bb9b6aa5aba78ac984915a8eb9d854 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:41:34 +0900 Subject: [PATCH 224/244] svg_loader: free allocated data properly. also renamed internal function for consistency. createNode() cloneNode() freeSVGNode() ? Change-Id: Ie9b22e92d5e918e947f8476ad0d4682fc7a3be65 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 0529ec80..205e8cb5 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -33,7 +33,7 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); - +static void _freeNode(SvgNode* node); static char* _skipSpace(const char* str, const char* end) { @@ -1459,6 +1459,8 @@ static void _cloneNode(SvgNode* from, SvgNode* parent) for (vector::iterator itrChild = from->child.begin(); itrChild != from->child.end(); itrChild++) { _cloneNode(*itrChild, newNode); } + + _freeNode(newNode); } @@ -2161,12 +2163,12 @@ static void _freeNodeStyle(SvgStyleProperty* style) free(style); } -static void _freeSvgNode(SvgNode* node) +static void _freeNode(SvgNode* node) { if (!node) return; for(vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { - _freeSvgNode(*itrChild); + _freeNode(*itrChild); } node->child.clear(); @@ -2187,7 +2189,7 @@ static void _freeSvgNode(SvgNode* node) break; } case SvgNodeType::Doc: { - _freeSvgNode(node->node.doc.defs); + _freeNode(node->node.doc.defs); break; } case SvgNodeType::Defs: { @@ -2360,7 +2362,7 @@ bool SvgLoader::close() free(loaderData.svgParse); loaderData.svgParse = nullptr; } - _freeSvgNode(loaderData.doc); + _freeNode(loaderData.doc); loaderData.doc = nullptr; return true; From ac4405a4ec29ce5c7a324117c9b45c1f7d62fa09 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:50:46 +0900 Subject: [PATCH 225/244] sw_engine: fix potential data overflow. Change-Id: Ie800fda74d44ad3741f7a92f12681f7f753ee50c --- src/lib/sw_engine/tvgSwMath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 36760481..5ac3912a 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -377,7 +377,7 @@ SwFixed mathLength(SwPoint& pt) _polarize(v); v.x = _downscale(v.x); - if (shift > 0) return (v.x + (1 << (shift -1))) >> shift; + if (shift > 0) return (v.x + (static_cast(1) << (shift -1))) >> shift; return static_cast((uint32_t)v.x << -shift); } From 3b22a25798167299c99119970676aa411186b7b4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 19:59:01 +0900 Subject: [PATCH 226/244] gl_engine: engine should return shape data for resuing it. Change-Id: I45f7ecbdb707b0751894e01d273b149402e089af --- src/lib/gl_engine/tvgGlRenderer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 0276c8f1..a295ed65 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -129,16 +129,16 @@ void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const Rende { //prepare shape data GlShape* sdata = static_cast(data); - if (!sdata) - { + if (!sdata) { sdata = new GlShape; - assert(sdata); + if (!sdata) return nullptr; } + sdata->viewWd = static_cast(surface.w); sdata->viewHt = static_cast(surface.h); sdata->updateFlag = flags; - if (sdata->updateFlag == RenderUpdateFlag::None) return nullptr; + if (sdata->updateFlag == RenderUpdateFlag::None) return sdata; initShaders(); From 9dd3cc5edc8f43473cfa163b46e83a02a54eed00 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 20:05:37 +0900 Subject: [PATCH 227/244] common: code refactoring. we can return nullptr directly here. Change-Id: Ic1d987f2701d20ff1b69af2854f9cfee7e2fe065 --- src/lib/tvgLoaderMgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index 208ba794..a35dcd5d 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -56,7 +56,7 @@ unique_ptr LoaderMgr::loader(const char* path) return unique_ptr(new SvgLoader); #endif cout << "Non supported format: " << path << endl; - return unique_ptr(nullptr); + return nullptr; } #endif //_TVG_LOADER_MGR_CPP_ \ No newline at end of file From 275c2f9d7901bbf5d44e1fa2cf3a4fce32f2fc8f Mon Sep 17 00:00:00 2001 From: Subhransu Mohanty Date: Thu, 13 Aug 2020 13:01:53 +0900 Subject: [PATCH 228/244] tvg: added task support that runs on a threadpool. this patch adds an async() function that takes a shared_task and runs asyncronously in a threadpool. Change-Id: I02a47df6938656828f924fbf5e2bc075073b329b --- src/lib/meson.build | 1 + src/lib/tvgTask.cpp | 156 ++++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgTask.h | 72 ++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 src/lib/tvgTask.cpp create mode 100644 src/lib/tvgTask.h diff --git a/src/lib/meson.build b/src/lib/meson.build index 631016dd..503c35e9 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -35,6 +35,7 @@ source_file = [ 'tvgScene.cpp', 'tvgShape.cpp', 'tvgSwCanvas.cpp', + 'tvgTask.cpp', ] common_dep = declare_dependency( diff --git a/src/lib/tvgTask.cpp b/src/lib/tvgTask.cpp new file mode 100644 index 00000000..81ce22e3 --- /dev/null +++ b/src/lib/tvgTask.cpp @@ -0,0 +1,156 @@ +/* + * 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. + * + */ + +#include + +#include + +template +class TaskQueue { + using lock_t = std::unique_lock; + std::deque _q; + bool _done{false}; + std::mutex _mutex; + std::condition_variable _ready; + +public: + bool try_pop(Task &task) + { + lock_t lock{_mutex, std::try_to_lock}; + if (!lock || _q.empty()) return false; + task = std::move(_q.front()); + _q.pop_front(); + return true; + } + + bool try_push(Task &&task) + { + { + lock_t lock{_mutex, std::try_to_lock}; + if (!lock) return false; + _q.push_back(std::move(task)); + } + _ready.notify_one(); + return true; + } + + void done() + { + { + lock_t lock{_mutex}; + _done = true; + } + _ready.notify_all(); + } + + bool pop(Task &task) + { + lock_t lock{_mutex}; + while (_q.empty() && !_done) _ready.wait(lock); + if (_q.empty()) return false; + task = std::move(_q.front()); + _q.pop_front(); + return true; + } + + void push(Task &&task) + { + { + lock_t lock{_mutex}; + _q.push_back(std::move(task)); + } + _ready.notify_one(); + } + +}; + +#include +#include + +namespace tvg +{ + +class Executor +{ + const unsigned _count{std::thread::hardware_concurrency()}; + std::vector _threads; + std::vector> _q{_count}; + std::atomic _index{0}; + void run(unsigned i) + { + // Task Loop + shared_task task; + while (true) { + bool success = false; + + for (unsigned n = 0; n != _count * 2; ++n) { + if (_q[(i + n) % _count].try_pop(task)) { + success = true; + break; + } + } + + if (!success && !_q[i].pop(task)) break; + + (*task)(); + } + } + + Executor() + { + for (unsigned n = 0; n != _count; ++n) { + _threads.emplace_back([&, n] { run(n); }); + } + } + ~Executor() + { + for (auto &e : _q) e.done(); + + for (auto &e : _threads) e.join(); + } + +public: + + static Executor& instance() { + static Executor singleton; + return singleton; + } + + void post(shared_task task) + { + task->prepare(); + + auto i = _index++; + + for (unsigned n = 0; n != _count; ++n) { + if (_q[(i + n) % _count].try_push(std::move(task))) return; + } + + if (_count > 0) { + _q[i % _count].push(std::move(task)); + } + } +}; + +void async(shared_task task) +{ + Executor::instance().post(std::move(task)); +} + +} + + diff --git a/src/lib/tvgTask.h b/src/lib/tvgTask.h new file mode 100644 index 00000000..9fb250ed --- /dev/null +++ b/src/lib/tvgTask.h @@ -0,0 +1,72 @@ +/* + * 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_TASK_H_ +#define _TVG_TASK_H_ + +#include +#include + +namespace tvg +{ + +/* + Task Interface. + Able to run a task in the thread pool. derive from the + task interface and implement run method. + + To get the result call task->get() which will return immidiately if the + task is already finishd otherwise will wait till task completion. + */ + +class Task +{ +public: + virtual ~Task() = default; + void get() { if (_receiver.valid()) _receiver.get(); } + +protected: + virtual void run() = 0; +private: + void operator()() + { + run(); + _sender.set_value(); + } + void prepare() + { + _sender = std::promise(); + _receiver = _sender.get_future(); + } + friend class Executor; + + std::promise _sender; + std::future _receiver; +}; + + +using shared_task = std::shared_ptr; + +/* + async() function takes a shared task and runs it in + a thread pool asyncronously. call get() on the shared_task + to get the ressult out of the shared_task. + */ +void async(shared_task task); + +} + +#endif //_TVG_TASK_H_ \ No newline at end of file From 72891162274dba579be585034140663193fab897 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 13 Aug 2020 20:39:34 +0900 Subject: [PATCH 229/244] remove std async usage. we can't control any threads count that could drop the performance. remove async() and will come back with fine-tuned threading-pool. Change-Id: I17c39792234acfce6db334abc0ce12da23978a9a --- src/lib/sw_engine/tvgSwCommon.h | 36 ++--- src/lib/sw_engine/tvgSwRaster.cpp | 30 ++-- src/lib/sw_engine/tvgSwRenderer.cpp | 198 +++++++----------------- src/lib/sw_engine/tvgSwRenderer.h | 12 -- src/lib/sw_engine/tvgSwShape.cpp | 105 ++++++------- src/lib/sw_engine/tvgSwStroke.cpp | 48 +++--- src/lib/tvgRender.h | 12 +- src/loaders/svg_loader/tvgSvgLoader.cpp | 50 +++--- src/loaders/svg_loader/tvgSvgLoader.h | 3 +- 9 files changed, 199 insertions(+), 295 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index e7566c18..295f11a5 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -269,22 +269,22 @@ SwFixed mathLength(SwPoint& pt); bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); -void shapeReset(SwShape& shape); -bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform); -bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias); -void shapeDelOutline(SwShape& shape); -void shapeResetStroke(SwShape& shape, const Shape* sdata, const Matrix* transform); -bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); -void shapeFree(SwShape& shape); -void shapeDelStroke(SwShape& shape); -bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable); -void shapeResetFill(SwShape& shape); -void shapeDelFill(SwShape& shape); +void shapeReset(SwShape* shape); +bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform); +bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); +bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias); +void shapeDelOutline(SwShape* shape); +void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform); +bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); +void shapeFree(SwShape* shape); +void shapeDelStroke(SwShape* shape); +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable); +void shapeResetFill(SwShape* shape); +void shapeDelFill(SwShape* shape); -void strokeReset(SwStroke& stroke, const Shape* shape, const Matrix* transform); -bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); -SwOutline* strokeExportOutline(SwStroke& stroke); +void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform); +bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); +SwOutline* strokeExportOutline(SwStroke* stroke); void strokeFree(SwStroke* stroke); bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); @@ -296,9 +296,9 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias); void rleFree(SwRleData* rle); -bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); -bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id); +bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterClear(Surface& surface); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 98579c52..46ef4ac0 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -273,48 +273,48 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF /* External Class Implementation */ /************************************************************************/ -bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id) +bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id) { //Fast Track - if (shape.rect) { - auto region = _clipRegion(surface, shape.bbox); - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, region, shape.fill); - return _rasterRadialGradientRect(surface, region, shape.fill); + if (shape->rect) { + auto region = _clipRegion(surface, shape->bbox); + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, region, shape->fill); + return _rasterRadialGradientRect(surface, region, shape->fill); } else { - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill); - return _rasterRadialGradientRle(surface, shape.rle, shape.fill); + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill); + return _rasterRadialGradientRle(surface, shape->rle, shape->fill); } return false; } -bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { r = COLOR_ALPHA_MULTIPLY(r, a); g = COLOR_ALPHA_MULTIPLY(g, a); b = COLOR_ALPHA_MULTIPLY(b, a); //Fast Track - if (shape.rect) { - auto region = _clipRegion(surface, shape.bbox); + if (shape->rect) { + auto region = _clipRegion(surface, shape->bbox); if (a == 255) return _rasterSolidRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); return _rasterTranslucentRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); } else{ - if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); + if (a == 255) return _rasterSolidRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); } return false; } -bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { r = COLOR_ALPHA_MULTIPLY(r, a); g = COLOR_ALPHA_MULTIPLY(g, a); b = COLOR_ALPHA_MULTIPLY(b, a); - if (a == 255) return _rasterSolidRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); + if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 92fddfb1..eb2f199e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -22,27 +22,12 @@ #ifndef _TVG_SW_RENDERER_CPP_ #define _TVG_SW_RENDERER_CPP_ -using namespace std; - #include "tvgSwCommon.h" #include "tvgSwRenderer.h" - /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -namespace tvg { - struct SwTask - { - SwShape shape; - const Shape* sdata; - SwSize clip; - Matrix* transform; - RenderUpdateFlag flags; - future progress; - }; -} - static RenderInitializer renderInit; @@ -52,13 +37,6 @@ static RenderInitializer renderInit; SwRenderer::~SwRenderer() { - flush(); -} - - -bool SwRenderer::clear() -{ - return flush(); } @@ -77,66 +55,25 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t bool SwRenderer::preRender() { - //before we start rendering, we should finish all preparing tasks - while (prepareTasks.size() > 0) { - auto task = prepareTasks.front(); - if (task->progress.valid()) task->progress.get(); - prepareTasks.pop(); - renderTasks.push(task); + return rasterClear(surface); +} + + +bool SwRenderer::render(const Shape& sdata, TVG_UNUSED void *data) +{ + auto shape = static_cast(data); + if (!shape) return false; + + uint8_t r, g, b, a; + + if (auto fill = sdata.fill()) { + rasterGradientShape(surface, shape, fill->id()); + } else{ + sdata.fill(&r, &g, &b, &a); + if (a > 0) rasterSolidShape(surface, shape, r, g, b, a); } - return true; -} - - -bool SwRenderer::postRender() -{ - auto asyncTask = [](SwRenderer* renderer) { - renderer->doRender(); - }; - - progress = async(launch::async, asyncTask, this); - - return true; -} - - -void SwRenderer::doRender() -{ - rasterClear(surface); - - while (renderTasks.size() > 0) { - auto task = renderTasks.front(); - uint8_t r, g, b, a; - if (auto fill = task->sdata->fill()) { - rasterGradientShape(surface, task->shape, fill->id()); - } else{ - task->sdata->fill(&r, &g, &b, &a); - if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); - } - task->sdata->strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); - renderTasks.pop(); - } -} - - -bool SwRenderer::flush() -{ - while (prepareTasks.size() > 0) { - auto task = prepareTasks.front(); - if (task->progress.valid()) task->progress.get(); - prepareTasks.pop(); - } - - if (progress.valid()) progress.get(); - - return true; -} - - -bool SwRenderer::render(TVG_UNUSED const Shape& sdata, TVG_UNUSED void *data) -{ - //Do Nothing + sdata.strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, shape, r, g, b, a); return true; } @@ -144,91 +81,72 @@ bool SwRenderer::render(TVG_UNUSED const Shape& sdata, TVG_UNUSED void *data) bool SwRenderer::dispose(TVG_UNUSED const Shape& sdata, void *data) { - auto task = static_cast(data); - if (!task) return true; - if (task->progress.valid()) task->progress.get(); - shapeFree(task->shape); - if (task->transform) free(task->transform); - free(task); + auto shape = static_cast(data); + if (!shape) return false; + shapeFree(shape); return true; } void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { - //prepare task - auto task = static_cast(data); - if (!task) { - task = static_cast(calloc(1, sizeof(SwTask))); - if (!task) return nullptr; + //prepare shape data + auto shape = static_cast(data); + if (!shape) { + shape = static_cast(calloc(1, sizeof(SwShape))); + assert(shape); } - if (flags == RenderUpdateFlag::None || task->progress.valid()) return task; + if (flags == RenderUpdateFlag::None) return shape; - task->sdata = &sdata; - task->clip = {static_cast(surface.w), static_cast(surface.h)}; + SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; - 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; + //Valid Stroking? + uint8_t strokeAlpha = 0; + auto strokeWidth = sdata.strokeWidth(); + if (strokeWidth > FLT_EPSILON) { + sdata.strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); } - task->flags = flags; + const Matrix* matrix = (transform ? &transform->m : nullptr); - auto asyncTask = [](SwTask* task) { - - //Valid Stroking? - uint8_t strokeAlpha = 0; - auto strokeWidth = task->sdata->strokeWidth(); - if (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); - bool renderShape = (alpha > 0 || task->sdata->fill()); - if (renderShape || strokeAlpha) { - if (!shapePrepare(task->shape, task->sdata, task->clip, task->transform)) return; - if (renderShape) { - auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true; - if (!shapeGenRle(task->shape, task->sdata, task->clip, antiAlias)) return; - } + //Shape + if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { + shapeReset(shape); + uint8_t alpha = 0; + sdata.fill(nullptr, nullptr, nullptr, &alpha); + bool renderShape = (alpha > 0 || sdata.fill()); + if (renderShape || strokeAlpha) { + if (!shapePrepare(shape, &sdata, clip, matrix)) return shape; + if (renderShape) { + auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true; + if (!shapeGenRle(shape, &sdata, clip, antiAlias)) return shape; } } //Fill - if (task->flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { - auto fill = task->sdata->fill(); + if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { + auto fill = sdata.fill(); if (fill) { - auto ctable = (task->flags & RenderUpdateFlag::Gradient) ? true : false; - if (ctable) shapeResetFill(task->shape); - if (!shapeGenFillColors(task->shape, fill, task->transform, ctable)) return; + auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; + if (ctable) shapeResetFill(shape); + if (!shapeGenFillColors(shape, fill, matrix, ctable)) return shape; } else { - shapeDelFill(task->shape); + shapeDelFill(shape); } } //Stroke - if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (strokeAlpha > 0) { - shapeResetStroke(task->shape, task->sdata, task->transform); - if (!shapeGenStrokeRle(task->shape, task->sdata, task->transform, task->clip)) return; + shapeResetStroke(shape, &sdata, matrix); + if (!shapeGenStrokeRle(shape, &sdata, matrix, clip)) return shape; } else { - shapeDelStroke(task->shape); + shapeDelStroke(shape); } } - shapeDelOutline(task->shape); - }; + shapeDelOutline(shape); + } - prepareTasks.push(task); - task->progress = async((launch::async | launch::deferred), asyncTask, task); - - return task; + return shape; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index d34c83ce..9a419028 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,10 +22,6 @@ #ifndef _TVG_SW_RENDERER_H_ #define _TVG_SW_RENDERER_H_ -#include -#include -#include - namespace tvg { @@ -38,10 +34,7 @@ public: bool dispose(const Shape& shape, void *data) override; bool preRender() override; bool render(const Shape& shape, void *data) override; - bool postRender() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); - bool clear() override; - bool flush() override; uint32_t ref() override; uint32_t unref() override; @@ -49,13 +42,8 @@ public: static int init(); static int term(); - void doRender(); //Internally used for threading - private: Surface surface = {nullptr, 0, 0, 0}; - future progress; - queue prepareTasks; - queue renderTasks; SwRenderer(){}; ~SwRenderer(); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index ed7c1e47..f9537d1b 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -463,52 +463,52 @@ bool _fastTrack(const SwOutline* outline) /* External Class Implementation */ /************************************************************************/ -bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) +bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) { if (!shapeGenOutline(shape, sdata, transform)) return false; - if (!_updateBBox(shape.outline, shape.bbox)) return false; + if (!_updateBBox(shape->outline, shape->bbox)) return false; - if (!_checkValid(shape.outline, shape.bbox, clip)) return false; + if (!_checkValid(shape->outline, shape->bbox, clip)) return false; return true; } -bool shapeGenRle(SwShape& shape, TVG_UNUSED const Shape* sdata, const SwSize& clip, bool antiAlias) +bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, const SwSize& clip, bool antiAlias) { //FIXME: Should we draw it? //Case: Stroke Line //if (shape.outline->opened) return true; //Case A: Fast Track Rectangle Drawing - if ((shape.rect = _fastTrack(shape.outline))) return true; + if ((shape->rect = _fastTrack(shape->outline))) return true; //Case B: Normale Shape RLE Drawing - if ((shape.rle = rleRender(shape.outline, shape.bbox, clip, antiAlias))) return true; + if ((shape->rle = rleRender(shape->outline, shape->bbox, clip, antiAlias))) return true; return false; } -void shapeDelOutline(SwShape& shape) +void shapeDelOutline(SwShape* shape) { - auto outline = shape.outline; + auto outline = shape->outline; _delOutline(outline); - shape.outline = nullptr; + shape->outline = nullptr; } -void shapeReset(SwShape& shape) +void shapeReset(SwShape* shape) { shapeDelOutline(shape); - rleFree(shape.rle); - shape.rle = nullptr; - shape.rect = false; - _initBBox(shape.bbox); + rleFree(shape->rle); + shape->rle = nullptr; + shape->rect = false; + _initBBox(shape->bbox); } -bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform) +bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform) { assert(sdata); @@ -550,7 +550,7 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform ++outlinePtsCnt; //for close ++outlineCntrsCnt; //for end - auto outline = shape.outline; + auto outline = shape->outline; if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); assert(outline); outline->opened = true; @@ -594,49 +594,49 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform //FIXME: //outline->flags = SwOutline::FillRule::Winding; - shape.outline = outline; + shape->outline = outline; return true; } -void shapeFree(SwShape& shape) +void shapeFree(SwShape* shape) { shapeDelOutline(shape); - rleFree(shape.rle); + rleFree(shape->rle); shapeDelFill(shape); - if (shape.stroke) { - rleFree(shape.strokeRle); - strokeFree(shape.stroke); + if (shape->stroke) { + rleFree(shape->strokeRle); + strokeFree(shape->stroke); } } -void shapeDelStroke(SwShape& shape) +void shapeDelStroke(SwShape* shape) { - if (!shape.stroke) return; - rleFree(shape.strokeRle); - shape.strokeRle = nullptr; - strokeFree(shape.stroke); - shape.stroke = nullptr; + if (!shape->stroke) return; + rleFree(shape->strokeRle); + shape->strokeRle = nullptr; + strokeFree(shape->stroke); + shape->stroke = nullptr; } -void shapeResetStroke(SwShape& shape, const Shape* sdata, const Matrix* transform) +void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform) { - if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); - auto stroke = shape.stroke; - assert(stroke); + if (!shape->stroke) shape->stroke = static_cast(calloc(1, sizeof(SwStroke))); + auto stroke = shape->stroke; + if (!stroke) return; - strokeReset(*stroke, sdata, transform); + strokeReset(stroke, sdata, transform); - rleFree(shape.strokeRle); - shape.strokeRle = nullptr; + rleFree(shape->strokeRle); + shape->strokeRle = nullptr; } -bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip) +bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip) { assert(sdata); @@ -648,15 +648,15 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transfo if (!shapeOutline) return false; //Normal Style stroke } else { - if (!shape.outline) { + if (!shape->outline) { if (!shapeGenOutline(shape, sdata, transform)) return false; } - shapeOutline = shape.outline; + shapeOutline = shape->outline; } - if (!strokeParseOutline(*shape.stroke, *shapeOutline)) return false; + if (!strokeParseOutline(shape->stroke, *shapeOutline)) return false; - auto strokeOutline = strokeExportOutline(*shape.stroke); + auto strokeOutline = strokeExportOutline(shape->stroke); if (!strokeOutline) return false; SwBBox bbox; @@ -664,7 +664,7 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transfo if (!_checkValid(strokeOutline, bbox, clip)) return false; - shape.strokeRle = rleRender(strokeOutline, bbox, clip, true); + shape->strokeRle = rleRender(strokeOutline, bbox, clip, true); _delOutline(strokeOutline); @@ -672,26 +672,27 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transfo } -bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable) +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable) { - return fillGenColorTable(shape.fill, fill, transform, ctable); + return fillGenColorTable(shape->fill, fill, transform, ctable); } -void shapeResetFill(SwShape& shape) +void shapeResetFill(SwShape* shape) { - if (!shape.fill) shape.fill = static_cast(calloc(1, sizeof(SwFill))); - assert(shape.fill); - - fillReset(shape.fill); + if (!shape->fill) { + shape->fill = static_cast(calloc(1, sizeof(SwFill))); + if (!shape->fill) return; + } + fillReset(shape->fill); } -void shapeDelFill(SwShape& shape) +void shapeDelFill(SwShape* shape) { - if (!shape.fill) return; - fillFree(shape.fill); - shape.fill = nullptr; + if (!shape->fill) return; + fillFree(shape->fill); + shape->fill = nullptr; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 70eb1ca7..fbe28c1e 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -846,34 +846,34 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) +void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); if (transform) { - stroke.sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); - stroke.sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); + stroke->sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + stroke->sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); } else { - stroke.sx = stroke.sy = 1.0f; + stroke->sx = stroke->sy = 1.0f; } - stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); - stroke.cap = sdata->strokeCap(); + stroke->width = TO_SWCOORD(sdata->strokeWidth() * 0.5); + stroke->cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... - stroke.joinSaved = stroke.join = sdata->strokeJoin(); + stroke->joinSaved = stroke->join = sdata->strokeJoin(); - stroke.borders[0].ptsCnt = 0; - stroke.borders[0].start = -1; - stroke.borders[0].valid = false; + stroke->borders[0].ptsCnt = 0; + stroke->borders[0].start = -1; + stroke->borders[0].valid = false; - stroke.borders[1].ptsCnt = 0; - stroke.borders[1].start = -1; - stroke.borders[1].valid = false; + stroke->borders[1].ptsCnt = 0; + stroke->borders[1].start = -1; + stroke->borders[1].valid = false; } -bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) +bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline) { uint32_t first = 0; @@ -895,7 +895,7 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) //A contour cannot start with a cubic control point if (type == SW_CURVE_TYPE_CUBIC) return false; - _beginSubPath(stroke, start, outline.opened); + _beginSubPath(*stroke, start, outline.opened); while (pt < limit) { ++pt; @@ -903,7 +903,7 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) //emit a signel line_to if (types[0] == SW_CURVE_TYPE_POINT) { - _lineTo(stroke, *pt); + _lineTo(*stroke, *pt); //types cubic } else { if (pt + 1 > limit || types[1] != SW_CURVE_TYPE_CUBIC) return false; @@ -912,28 +912,28 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) types += 2; if (pt <= limit) { - _cubicTo(stroke, pt[-2], pt[-1], pt[0]); + _cubicTo(*stroke, pt[-2], pt[-1], pt[0]); continue; } - _cubicTo(stroke, pt[-2], pt[-1], start); + _cubicTo(*stroke, pt[-2], pt[-1], start); goto close; } } close: - if (!stroke.firstPt) _endSubPath(stroke); + if (!stroke->firstPt) _endSubPath(*stroke); first = last + 1; } return true; } -SwOutline* strokeExportOutline(SwStroke& stroke) +SwOutline* strokeExportOutline(SwStroke* stroke) { uint32_t count1, count2, count3, count4; - _getCounts(stroke.borders + 0, count1, count2); - _getCounts(stroke.borders + 1, count3, count4); + _getCounts(stroke->borders + 0, count1, count2); + _getCounts(stroke->borders + 1, count3, count4); auto ptsCnt = count1 + count3; auto cntrsCnt = count2 + count4; @@ -950,8 +950,8 @@ SwOutline* strokeExportOutline(SwStroke& stroke) outline->cntrs = static_cast(malloc(sizeof(uint32_t) * cntrsCnt)); assert(outline->cntrs); - _exportBorderOutline(stroke, outline, 0); //left - _exportBorderOutline(stroke, outline, 1); //right + _exportBorderOutline(*stroke, outline, 0); //left + _exportBorderOutline(*stroke, outline, 1); //right return outline; } diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 85292d21..60c76d50 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -57,12 +57,12 @@ class RenderMethod public: virtual ~RenderMethod() {} virtual void* prepare(TVG_UNUSED const Shape& shape, TVG_UNUSED void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED RenderUpdateFlag flags) { return nullptr; } - virtual bool dispose(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return false; } - virtual bool preRender() { return false; } - virtual bool render(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return false; } - virtual bool postRender() { return false; } - virtual bool clear() { return false; } - virtual bool flush() { return false; } + virtual bool dispose(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return true; } + virtual bool preRender() { return true; } + virtual bool render(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return true; } + virtual bool postRender() { return true; } + virtual bool clear() { return true; } + virtual bool flush() { return true; } virtual uint32_t ref() { return 0; } virtual uint32_t unref() { return 0; } }; diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 205e8cb5..442d3b78 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2324,31 +2324,34 @@ bool SvgLoader::read() { if (content.empty()) return false; - auto asyncTask = [](SvgLoader *loader) { - bool res = simpleXmlParse(loader->content.c_str(), loader->content.size(), true, _svgLoaderParser, &(loader->loaderData)); + loaderData = {vector(), + nullptr, + nullptr, + vector(), + nullptr, + nullptr, + 0, + false}; - if (!res) return unique_ptr(nullptr); + loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); - if (loader->loaderData.doc) { - SvgNode *defs; - _updateStyle(loader->loaderData.doc, nullptr); - defs = loader->loaderData.doc->node.doc.defs; - if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients); - else { - if (!loader->loaderData.gradients.empty()) { - vector gradientList; - for (auto gradient : loader->loaderData.gradients) { - gradientList.push_back(gradient); - } - _updateGradient(loader->loaderData.doc, gradientList); - gradientList.clear(); - } + if (!simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParser, &loaderData)) return false; + + if (loaderData.doc) { + _updateStyle(loaderData.doc, nullptr); + auto 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(); } } - return loader->builder.build(loader->loaderData.doc); - }; + } - rootProgress = async((launch::async | launch::deferred), asyncTask, this); + root = builder.build(loaderData.doc); return true; } @@ -2356,8 +2359,6 @@ bool SvgLoader::read() bool SvgLoader::close() { - if (rootProgress.valid()) root = rootProgress.get(); - if (loaderData.svgParse) { free(loaderData.svgParse); loaderData.svgParse = nullptr; @@ -2371,10 +2372,7 @@ bool SvgLoader::close() unique_ptr SvgLoader::data() { - if (rootProgress.valid()) root = rootProgress.get(); - - if (root) return move(root); - else return unique_ptr(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 7f0ce3cd..3ef981df 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.h +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -24,7 +24,7 @@ #include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" -#include + class SvgLoader : public Loader { @@ -32,7 +32,6 @@ private: string content; SvgLoaderData loaderData; SvgSceneBuilder builder; - future> rootProgress; unique_ptr root; public: From 93b517df062a42c511d93770558ade9293996362 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 14 Aug 2020 17:44:17 +0900 Subject: [PATCH 230/244] disable gl_engine in default. We don't include gl compile before it works properly. For development & test please turn it on in meson_option.txt locally. Change-Id: I2ff8b06f8e1b496922f70ec580662e8886a9b93d --- meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index 59d0130d..3990b177 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option('engines', type: 'array', choices: ['sw', 'gl'], - value: ['sw', 'gl'], + value: ['sw'], description: 'Enable Rasterizer Engine in thorvg') option('loaders', From 709548701a7dc1c2ae61e6a473ccc0a072482b23 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 14 Aug 2020 18:47:03 +0900 Subject: [PATCH 231/244] loader svg: code refactoring. renamed svg loader path. Change-Id: I0219721540ea981d15d17b9571c1ee9b37651fb8 --- src/loaders/meson.build | 2 +- src/loaders/{svg_loader => svg}/meson.build | 0 src/loaders/{svg_loader => svg}/tvgSimpleXmlParser.cpp | 0 src/loaders/{svg_loader => svg}/tvgSimpleXmlParser.h | 0 src/loaders/{svg_loader => svg}/tvgSvgLoader.cpp | 0 src/loaders/{svg_loader => svg}/tvgSvgLoader.h | 0 src/loaders/{svg_loader => svg}/tvgSvgLoaderCommon.h | 0 src/loaders/{svg_loader => svg}/tvgSvgPath.cpp | 0 src/loaders/{svg_loader => svg}/tvgSvgPath.h | 0 src/loaders/{svg_loader => svg}/tvgSvgSceneBuilder.cpp | 0 src/loaders/{svg_loader => svg}/tvgSvgSceneBuilder.h | 0 11 files changed, 1 insertion(+), 1 deletion(-) rename src/loaders/{svg_loader => svg}/meson.build (100%) rename src/loaders/{svg_loader => svg}/tvgSimpleXmlParser.cpp (100%) rename src/loaders/{svg_loader => svg}/tvgSimpleXmlParser.h (100%) rename src/loaders/{svg_loader => svg}/tvgSvgLoader.cpp (100%) rename src/loaders/{svg_loader => svg}/tvgSvgLoader.h (100%) rename src/loaders/{svg_loader => svg}/tvgSvgLoaderCommon.h (100%) rename src/loaders/{svg_loader => svg}/tvgSvgPath.cpp (100%) rename src/loaders/{svg_loader => svg}/tvgSvgPath.h (100%) rename src/loaders/{svg_loader => svg}/tvgSvgSceneBuilder.cpp (100%) rename src/loaders/{svg_loader => svg}/tvgSvgSceneBuilder.h (100%) diff --git a/src/loaders/meson.build b/src/loaders/meson.build index 873cfa7f..bc67b53e 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -1,7 +1,7 @@ subloader_dep = [] if get_option('loaders').contains('svg') == true - subdir('svg_loader') + subdir('svg') message('Enable SVG Loader') endif diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg/meson.build similarity index 100% rename from src/loaders/svg_loader/meson.build rename to src/loaders/svg/meson.build diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.cpp b/src/loaders/svg/tvgSimpleXmlParser.cpp similarity index 100% rename from src/loaders/svg_loader/tvgSimpleXmlParser.cpp rename to src/loaders/svg/tvgSimpleXmlParser.cpp diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.h b/src/loaders/svg/tvgSimpleXmlParser.h similarity index 100% rename from src/loaders/svg_loader/tvgSimpleXmlParser.h rename to src/loaders/svg/tvgSimpleXmlParser.h diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp similarity index 100% rename from src/loaders/svg_loader/tvgSvgLoader.cpp rename to src/loaders/svg/tvgSvgLoader.cpp diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h similarity index 100% rename from src/loaders/svg_loader/tvgSvgLoader.h rename to src/loaders/svg/tvgSvgLoader.h diff --git a/src/loaders/svg_loader/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h similarity index 100% rename from src/loaders/svg_loader/tvgSvgLoaderCommon.h rename to src/loaders/svg/tvgSvgLoaderCommon.h diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp similarity index 100% rename from src/loaders/svg_loader/tvgSvgPath.cpp rename to src/loaders/svg/tvgSvgPath.cpp diff --git a/src/loaders/svg_loader/tvgSvgPath.h b/src/loaders/svg/tvgSvgPath.h similarity index 100% rename from src/loaders/svg_loader/tvgSvgPath.h rename to src/loaders/svg/tvgSvgPath.h diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp similarity index 100% rename from src/loaders/svg_loader/tvgSvgSceneBuilder.cpp rename to src/loaders/svg/tvgSvgSceneBuilder.cpp diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.h b/src/loaders/svg/tvgSvgSceneBuilder.h similarity index 100% rename from src/loaders/svg_loader/tvgSvgSceneBuilder.h rename to src/loaders/svg/tvgSvgSceneBuilder.h From 1eb11f249ef62217e6f47fcc90b459764d0685b1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 14 Aug 2020 18:51:38 +0900 Subject: [PATCH 232/244] common initializer: introduce thread count api. this interface controls the number of threads working behind. default is 0 == only syncrhonous. Change-Id: I8404f33359e6213acc5e578061568fede50cd9a6 --- inc/thorvg.h | 2 ++ src/lib/tvgInitializer.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/inc/thorvg.h b/inc/thorvg.h index 97592459..452234d8 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -365,6 +365,8 @@ public: */ static Result init(CanvasEngine engine) noexcept; static Result term(CanvasEngine engine) noexcept; + static Result threads(uint32_t cnt) noexcept; + static uint32_t threads() noexcept; _TVG_DISABLE_CTOR(Initializer); }; diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index 20092997..3367603a 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -38,6 +38,8 @@ /* Internal Class Implementation */ /************************************************************************/ +static uint32_t threadCnt = 0; + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -93,4 +95,18 @@ Result Initializer::term(CanvasEngine engine) noexcept return Result::Success; } + +Result Initializer::threads(uint32_t cnt) noexcept +{ + threadCnt = cnt; + + return Result::Success; +} + + +uint32_t Initializer::threads() noexcept +{ + return threadCnt; +} + #endif /* _TVG_INITIALIZER_CPP_ */ From 7ab71c52d038a5940641c61871aca169ece36197 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 14 Aug 2020 19:35:39 +0900 Subject: [PATCH 233/244] picture svg: introduce load() with memory data input source. picture now affords the memory data as input source so that user can pass svg data memory directly. Change-Id: I246c09b682a2d60e53ad556ce0c90337142ee4f1 --- .gitignore | 1 + inc/thorvg.h | 1 + src/lib/tvgLoader.h | 1 + src/lib/tvgLoaderMgr.cpp | 3 +- src/lib/tvgLoaderMgr.h | 2 +- src/lib/tvgPicture.cpp | 8 ++ src/lib/tvgPictureImpl.h | 19 +++- src/loaders/svg/tvgSvgLoader.cpp | 68 ++++++++------ src/loaders/svg/tvgSvgLoader.h | 7 +- test/makefile | 1 + test/testSvg2.cpp | 148 +++++++++++++++++++++++++++++++ 11 files changed, 228 insertions(+), 31 deletions(-) create mode 100644 test/testSvg2.cpp diff --git a/.gitignore b/.gitignore index 7f4d09bf..53a53b5b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ testLinearGradient testRadialGradient testGradientTransform testSvg +testSvg2 testAsync testCapi testArc diff --git a/inc/thorvg.h b/inc/thorvg.h index 452234d8..3f43a2fc 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -267,6 +267,7 @@ public: ~Picture(); Result load(const std::string& path) noexcept; + Result load(const char* data, uint32_t size) noexcept; Result viewbox(float* x, float* y, float* w, float* h) const noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h index c714f92c..9c7279eb 100644 --- a/src/lib/tvgLoader.h +++ b/src/lib/tvgLoader.h @@ -37,6 +37,7 @@ public: virtual ~Loader() {} virtual bool open(const char* path) = 0; + virtual bool open(const char* data, uint32_t size) = 0; virtual bool read() = 0; virtual bool close() = 0; virtual unique_ptr data() = 0; diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index a35dcd5d..5e59a447 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -50,12 +50,11 @@ bool LoaderMgr::term() return true; } -unique_ptr LoaderMgr::loader(const char* path) +unique_ptr LoaderMgr::loader() { #ifdef THORVG_SVG_LOADER_SUPPORT return unique_ptr(new SvgLoader); #endif - cout << "Non supported format: " << path << endl; return nullptr; } diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h index 7c9d52e1..95a06767 100644 --- a/src/lib/tvgLoaderMgr.h +++ b/src/lib/tvgLoaderMgr.h @@ -26,7 +26,7 @@ struct LoaderMgr { static bool init(); static bool term(); - static unique_ptr loader(const char* path); + static unique_ptr loader(); }; #endif //_TVG_LOADER_MGR_H_ \ No newline at end of file diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index 7595afab..70836924 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -53,6 +53,14 @@ Result Picture::load(const std::string& path) noexcept } +Result Picture::load(const char* data, uint32_t size) noexcept +{ + if (!data || size <= 0) return Result::InvalidArguments; + + return IMPL->load(data, size); +} + + Result Picture::viewbox(float* x, float* y, float* w, float* h) const noexcept { if (IMPL->viewbox(x, y, w, h)) return Result::Success; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 45e2e9d8..5ab9618f 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -84,8 +84,23 @@ struct Picture::Impl Result load(const string& path) { if (loader) loader->close(); - loader = LoaderMgr::loader(path.c_str()); - if (!loader || !loader->open(path.c_str())) return Result::NonSupport; + loader = LoaderMgr::loader(); + if (!loader || !loader->open(path.c_str())) { + cout << "Non supported format: " << path.c_str() << endl; + return Result::NonSupport; + } + if (!loader->read()) return Result::Unknown; + return Result::Success; + } + + Result load(const char* data, uint32_t size) + { + if (loader) loader->close(); + loader = LoaderMgr::loader(); + if (!loader || !loader->open(data, size)) { + cout << "Non supported load data" << endl; + return Result::NonSupport; + } if (!loader->read()) return Result::Unknown; return Result::Success; } diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 442d3b78..1579390c 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -35,6 +35,7 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); static void _freeNode(SvgNode* node); + static char* _skipSpace(const char* str, const char* end) { while (((end != nullptr && str < end) || (end == nullptr && *str != '\0')) && isspace(*str)) @@ -2280,6 +2281,40 @@ SvgLoader::~SvgLoader() } +bool SvgLoader::header() +{ + //For valid check, only tag is parsed first. + //If the tag is found, the loaded file is valid and stores viewbox information. + //After that, the remaining content data is parsed in order with async. + loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); + if (!loaderData.svgParse) return false; + + simpleXmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData)); + + if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) { + //Return the brief resource info such as viewbox: + this->vx = loaderData.doc->node.doc.vx; + this->vy = loaderData.doc->node.doc.vy; + this->vw = loaderData.doc->node.doc.vw; + this->vh = loaderData.doc->node.doc.vh; + } else { + cout << "ERROR : No SVG File. There is no " <content = data; + this->size = size; + + return header(); +} + + bool SvgLoader::open(const char* path) { ifstream f; @@ -2290,39 +2325,22 @@ bool SvgLoader::open(const char* path) cout << "ERROR: Failed to open file = " << path; return false; } else { - getline(f, content, '\0'); + getline(f, filePath, '\0'); f.close(); - if (content.empty()) return false; + if (filePath.empty()) return false; + + this->content = filePath.c_str(); + this->size = filePath.size(); } - //For valid check, only tag is parsed first. - //If the tag is found, the loaded file is valid and stores viewbox information. - //After that, the remaining content data is parsed in order with async. - loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); - if (!loaderData.svgParse) return false; - - simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParserForValidCheck, &(loaderData)); - - if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) { - //Return the brief resource info such as viewbox: - this->vx = loaderData.doc->node.doc.vx; - this->vy = loaderData.doc->node.doc.vy; - this->vw = loaderData.doc->node.doc.vw; - this->vh = loaderData.doc->node.doc.vh; - - } else { - cout << "ERROR : No SVG File. There is no " <(), nullptr, @@ -2335,7 +2353,7 @@ bool SvgLoader::read() loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); - if (!simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParser, &loaderData)) return false; + if (!simpleXmlParse(content, size, true, _svgLoaderParser, &loaderData)) return false; if (loaderData.doc) { _updateStyle(loaderData.doc, nullptr); diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index 3ef981df..e85582bf 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -29,7 +29,10 @@ class SvgLoader : public Loader { private: - string content; + string filePath; + const char* content = nullptr; + uint32_t size = 0; + SvgLoaderData loaderData; SvgSceneBuilder builder; unique_ptr root; @@ -39,6 +42,8 @@ public: ~SvgLoader(); bool open(const char* path) override; + bool open(const char* data, uint32_t size) override; + bool header(); bool read() override; bool close() override; unique_ptr data() override; diff --git a/test/makefile b/test/makefile index 29e6e779..f48278d4 100644 --- a/test/makefile +++ b/test/makefile @@ -17,6 +17,7 @@ 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 testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testArc testArc.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg` diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp new file mode 100644 index 00000000..171db919 --- /dev/null +++ b/test/testSvg2.cpp @@ -0,0 +1,148 @@ +#include "testCommon.h" + +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ + +static const char* svg = ""; + + +void tvgDrawCmds(tvg::Canvas* canvas) +{ + if (!canvas) return; + + //Background + auto shape = tvg::Shape::gen(); + shape->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry + shape->fill(255, 255, 255, 255); //r, g, b, a + + if (canvas->push(move(shape)) != tvg::Result::Success) return; + + auto picture = tvg::Picture::gen(); + if (picture->load(svg, strlen(svg)) != tvg::Result::Success) return; + + float x, y, w, h; + picture->viewbox(&x, &y, &w, &h); + + float rate = (WIDTH/(w > h ? w : h)); + picture->scale(rate); + + x *= rate; + y *= rate; + w *= rate; + h *= rate; + + //Center Align ? + if (w > h) { + y -= (WIDTH - h) * 0.5f; + } else { + x -= (WIDTH - w) * 0.5f; + } + + picture->translate(-x, -y); + + canvas->push(move(picture)); +} + + +/************************************************************************/ +/* 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) +{ + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } +} + + +/************************************************************************/ +/* GL Engine Test Code */ +/************************************************************************/ + +static unique_ptr glCanvas; + +void initGLview(Evas_Object *obj) +{ + static constexpr auto BPP = 4; + + //Create a Canvas + glCanvas = tvg::GlCanvas::gen(); + glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + tvgDrawCmds(glCanvas.get()); +} + +void drawGLview(Evas_Object *obj) +{ + auto gl = elm_glview_gl_api_get(obj); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + +int main(int argc, char **argv) +{ + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } + + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); + + } else { + cout << "engine is not supported" << endl; + } + return 0; +} From f4d1065d5247abfd074aaff08a2db28343288357 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 15 Aug 2020 16:29:46 +0900 Subject: [PATCH 234/244] sw_engine: convert colorspace ARGB -> RGBA in default. We can use RGBA colorspace rather ARGB for pixel data. This would be better for many rendering system, since it's more widely preferred than ARGB including opengl. Change-Id: Ibbfe6a511d77bf0ef30ce261995467c11164d306 --- inc/thorvg.h | 4 +- inc/thorvg_capi.h | 4 +- src/bindings/capi/tvgCapi.cpp | 4 +- src/lib/sw_engine/tvgSwCommon.h | 30 +++++-- src/lib/sw_engine/tvgSwFill.cpp | 26 +++--- src/lib/sw_engine/tvgSwRaster.cpp | 124 +++++++++++++++++++--------- src/lib/sw_engine/tvgSwRenderer.cpp | 5 +- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 4 +- src/lib/tvgGlCanvas.cpp | 2 +- src/lib/tvgRender.h | 1 + src/lib/tvgSwCanvas.cpp | 4 +- test/testArc.cpp | 2 +- test/testAsync.cpp | 2 +- test/testBlending.cpp | 2 +- test/testBoundary.cpp | 2 +- test/testCapi.c | 2 +- test/testCustomTransform.cpp | 2 +- test/testDirectUpdate.cpp | 2 +- test/testGradientTransform.cpp | 2 +- test/testLinearGradient.cpp | 2 +- test/testMultiShapes.cpp | 2 +- test/testPath.cpp | 2 +- test/testPathCopy.cpp | 2 +- test/testRadialGradient.cpp | 2 +- test/testScene.cpp | 2 +- test/testSceneTransform.cpp | 2 +- test/testShape.cpp | 2 +- test/testStroke.cpp | 2 +- test/testStrokeLine.cpp | 2 +- test/testSvg.cpp | 2 +- test/testSvg2.cpp | 2 +- test/testTransform.cpp | 2 +- test/testUpdate.cpp | 2 +- 34 files changed, 157 insertions(+), 97 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 3f43a2fc..9ed54988 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -311,7 +311,9 @@ class TVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; + enum Colorspace { RGBA8888 = 0, ARGB8888 }; + + Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept; static std::unique_ptr gen() noexcept; diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 763d71b2..2f1bf967 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -23,6 +23,8 @@ typedef struct _Tvg_Gradient Tvg_Gradient; #define TVG_ENGINE_SW (1 << 1) #define TVG_ENGINE_GL (1 << 2) +#define TVG_COLORSPACE_RGBA8888 0 +#define TVG_COLORSPACE_ARGB8888 1 typedef enum { TVG_RESULT_SUCCESS = 0, @@ -94,7 +96,7 @@ TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method); /* SwCanvas API */ /************************************************************************/ TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create(); -TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); +TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); /************************************************************************/ diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index e05435a5..ac8cdcb1 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -88,9 +88,9 @@ TVG_EXPORT Tvg_Result tvg_canvas_destroy(Tvg_Canvas* canvas) } -TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs) { - return (Tvg_Result) reinterpret_cast(canvas)->target(buffer, stride, w, h); + return (Tvg_Result) reinterpret_cast(canvas)->target(buffer, stride, w, h, static_cast(cs)); } diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 295f11a5..e5d4719f 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -222,20 +222,26 @@ static inline SwCoord TO_SWCOORD(float val) } -static inline uint32_t COLOR_ALPHA(uint32_t rgba) +static inline uint32_t RGBA_ALPHA(uint32_t rgba) { - return (rgba >> 24) & 0xff; + return rgba & 0x000000ff; } -static inline uint32_t COLOR_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) +static inline uint32_t ARGB_ALPHA(uint32_t argb) +{ + return (argb >> 24) & 0xff; +} + + +static inline uint32_t RGBA_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) { return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); } -static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) +static inline uint32_t RGBA_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) { auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; @@ -243,13 +249,19 @@ static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rg } -static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static inline uint32_t RGBA_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (r << 24 | g << 16 | b << 8 | a); +} + + +static inline uint32_t ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (a << 24 | r << 16 | g << 8 | b); } -static inline uint8_t COLOR_ALPHA_MULTIPLY(uint32_t c, uint32_t a) +static inline uint8_t ALPHA_MULTIPLY(uint32_t c, uint32_t a) { return (c * a) >> 8; } @@ -278,7 +290,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape* shape); -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable); +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable); void shapeResetFill(SwShape* shape); void shapeDelFill(SwShape* shape); @@ -287,7 +299,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke* stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable); void fillReset(SwFill* fill); void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len); @@ -302,7 +314,7 @@ bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_ bool rasterClear(Surface& surface); -static inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { #ifdef THORVG_AVX_VECTOR_SUPPORT int32_t align = (8 - (offset % 8)) % 8; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index ae938fd3..cd68d0f1 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -34,7 +34,7 @@ #define FIXPT_SIZE (1<a < 255) fill->translucent = true; - auto r = COLOR_ALPHA_MULTIPLY(pColors->r, pColors->a); - auto g = COLOR_ALPHA_MULTIPLY(pColors->g, pColors->a); - auto b = COLOR_ALPHA_MULTIPLY(pColors->b, pColors->a); + auto r = ALPHA_MULTIPLY(pColors->r, pColors->a); + auto g = ALPHA_MULTIPLY(pColors->g, pColors->a); + auto b = ALPHA_MULTIPLY(pColors->b, pColors->a); - auto rgba = COLOR_ARGB_JOIN(r, g, b, pColors->a); + auto rgba = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, pColors->a) : ARGB_JOIN(r, g, b, pColors->a); auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); auto pos = 1.5f * inc; uint32_t i = 0; @@ -75,17 +75,17 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) auto delta = 1.0f / (next->offset - curr->offset); if (next->a < 255) fill->translucent = true; - auto r = COLOR_ALPHA_MULTIPLY(next->r, next->a); - auto g = COLOR_ALPHA_MULTIPLY(next->g, next->a); - auto b = COLOR_ALPHA_MULTIPLY(next->b, next->a); + auto r = ALPHA_MULTIPLY(next->r, next->a); + auto g = ALPHA_MULTIPLY(next->g, next->a); + auto b = ALPHA_MULTIPLY(next->b, next->a); - auto rgba2 = COLOR_ARGB_JOIN(r, g, b, next->a); + auto rgba2 = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, next->a) : ARGB_JOIN(r, g, b, next->a); while (pos < next->offset && i < GRADIENT_STOP_SIZE) { auto t = (pos - curr->offset) * delta; auto dist = static_cast(256 * t); auto dist2 = 256 - dist; - fill->ctable[i] = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); + fill->ctable[i] = RGBA_INTERPOLATE(rgba, dist2, rgba2, dist); ++i; pos += inc; } @@ -252,7 +252,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); - rasterARGB32(dst, color, offset, len); + rasterRGBA32(dst, color, offset, len); return; } @@ -282,7 +282,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable) { if (!fill) return false; @@ -291,7 +291,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, fill->spread = fdata->spread(); if (ctable) { - if (!_updateColorTable(fill, fdata)) return false; + if (!_updateColorTable(fill, fdata, cs)) return false; } if (fdata->id() == FILL_ID_LINEAR) { diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 46ef4ac0..d07d7eb1 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -45,12 +45,12 @@ static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint3 auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); - auto ialpha = 255 - COLOR_ALPHA(color); + auto ialpha = 255 - (surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(color) : ARGB_ALPHA(color); for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface.stride]; for (uint32_t x = 0; x < w; ++x) { - dst[x] = color + COLOR_ALPHA_BLEND(dst[x], ialpha); + dst[x] = color + RGBA_ALPHA_BLEND(dst[x], ialpha); } } return true; @@ -64,7 +64,7 @@ static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t co auto h = static_cast(region.max.y - region.min.y); for (uint32_t y = 0; y < h; ++y) { - rasterARGB32(buffer + y * surface.stride, color, region.min.x, w); + rasterRGBA32(buffer + y * surface.stride, color, region.min.x, w); } return true; } @@ -79,11 +79,11 @@ static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t col for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * surface.stride + span->x]; - if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage); + if (span->coverage < 255) src = RGBA_ALPHA_BLEND(color, span->coverage); else src = color; - auto ialpha = 255 - COLOR_ALPHA(src); + auto ialpha = 255 - ((surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(src) : ARGB_ALPHA(src)); for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); } ++span; } @@ -99,13 +99,13 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) for (uint32_t i = 0; i < rle->size; ++i) { if (span->coverage == 255) { - rasterARGB32(surface.buffer + span->y * surface.stride, color, span->x, span->len); + rasterRGBA32(surface.buffer + span->y * surface.stride, color, span->x, span->len); } else { auto dst = &surface.buffer[span->y * surface.stride + span->x]; - auto src = COLOR_ALPHA_BLEND(color, span->coverage); + auto src = RGBA_ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -131,8 +131,14 @@ static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, co for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface.stride]; fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); + if (surface.cs == SwCanvas::RGBA8888) { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x])); + } + } else { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x])); + } } } //Opaque Gradient @@ -162,8 +168,14 @@ static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, co for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface.stride]; fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); + if (surface.cs == SwCanvas::RGBA8888) { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x])); + } + } else { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x])); + } } } //Opaque Gradient @@ -191,14 +203,27 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * surface.stride + span->x]; fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + if (surface.cs == SwCanvas::RGBA8888) { + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp)); + } } } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp)); + } } } ++span; @@ -213,7 +238,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -237,14 +262,27 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * surface.stride + span->x]; fillFetchRadial(fill, buf, span->y, span->x, span->len); - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + if (surface.cs == SwCanvas::RGBA8888) { + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp)); + } } } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp)); + } } } ++span; @@ -259,7 +297,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF fillFetchRadial(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -290,18 +328,20 @@ bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id) bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - r = COLOR_ALPHA_MULTIPLY(r, a); - g = COLOR_ALPHA_MULTIPLY(g, a); - b = COLOR_ALPHA_MULTIPLY(b, a); + r = ALPHA_MULTIPLY(r, a); + g = ALPHA_MULTIPLY(g, a); + b = ALPHA_MULTIPLY(b, a); + + auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a); //Fast Track if (shape->rect) { auto region = _clipRegion(surface, shape->bbox); - if (a == 255) return _rasterSolidRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); + if (a == 255) return _rasterSolidRect(surface, region, color); + return _rasterTranslucentRect(surface, region, color); } else{ - if (a == 255) return _rasterSolidRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); + if (a == 255) return _rasterSolidRle(surface, shape->rle, color); + return _rasterTranslucentRle(surface, shape->rle, color); } return false; } @@ -309,12 +349,14 @@ bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - r = COLOR_ALPHA_MULTIPLY(r, a); - g = COLOR_ALPHA_MULTIPLY(g, a); - b = COLOR_ALPHA_MULTIPLY(b, a); + r = ALPHA_MULTIPLY(r, a); + g = ALPHA_MULTIPLY(g, a); + b = ALPHA_MULTIPLY(b, a); - if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); + auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a); + + if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color); + return _rasterTranslucentRle(surface, shape->strokeRle, color); } @@ -323,10 +365,10 @@ bool rasterClear(Surface& surface) if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; if (surface.w == surface.stride) { - rasterARGB32(surface.buffer, 0x00000000, 0, surface.w * surface.h); + rasterRGBA32(surface.buffer, 0x00000000, 0, surface.w * surface.h); } else { for (uint32_t i = 0; i < surface.h; i++) { - rasterARGB32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); + rasterRGBA32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); } } return true; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index eb2f199e..66608f54 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -40,7 +40,7 @@ SwRenderer::~SwRenderer() } -bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -48,6 +48,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t surface.stride = stride; surface.w = w; surface.h = h; + surface.cs = cs; return true; } @@ -129,7 +130,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (fill) { auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; if (ctable) shapeResetFill(shape); - if (!shapeGenFillColors(shape, fill, matrix, ctable)) return shape; + if (!shapeGenFillColors(shape, fill, matrix, surface.cs, ctable)) return shape; } else { shapeDelFill(shape); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 9a419028..5657602b 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -34,7 +34,7 @@ public: bool dispose(const Shape& shape, void *data) override; bool preRender() override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); uint32_t ref() override; uint32_t unref() override; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index f9537d1b..3704a2cb 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -672,9 +672,9 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo } -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable) +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable) { - return fillGenColorTable(shape->fill, fill, transform, ctable); + return fillGenColorTable(shape->fill, fill, transform, cs, ctable); } diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 7f2c04b7..1ac57329 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -70,7 +70,7 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; + if (!renderer->target(buffer, stride, w, h, 0)) return Result::Unknown; return Result::Success; #endif diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 60c76d50..3535bf43 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -31,6 +31,7 @@ struct Surface uint32_t* buffer; uint32_t stride; uint32_t w, h; + uint32_t cs; }; enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32}; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index e958ea26..755d422d 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -62,14 +62,14 @@ SwCanvas::~SwCanvas() } -Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept +Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept { #ifdef THORVG_SW_RASTER_SUPPORT //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; + if (!renderer->target(buffer, stride, w, h, cs)) return Result::InvalidArguments; return Result::Success; #endif diff --git a/test/testArc.cpp b/test/testArc.cpp index b02196ef..1f158122 100644 --- a/test/testArc.cpp +++ b/test/testArc.cpp @@ -79,7 +79,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testAsync.cpp b/test/testAsync.cpp index edc6dde7..608cefb2 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -68,7 +68,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); } Eina_Bool animSwCb(void* data) diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 59a4fad7..743b1e09 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -62,7 +62,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 57a3d6c6..38306877 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -51,7 +51,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testCapi.c b/test/testCapi.c index 90c4e1d7..c6df3968 100644 --- a/test/testCapi.c +++ b/test/testCapi.c @@ -16,7 +16,7 @@ void testCapi() tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL); Tvg_Canvas* canvas = tvg_swcanvas_create(); - tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT); + tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT, TVG_COLORSPACE_ARGB8888); Tvg_Paint* shape = tvg_shape_new(); tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0); diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 4803ef16..9daa6fc1 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -92,7 +92,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 3c275b62..8dcc474a 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -55,7 +55,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 4fa426be..77d5f6af 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -120,7 +120,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index f98fc970..db11682a 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -80,7 +80,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 5a6d34f9..12009bc2 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -40,7 +40,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testPath.cpp b/test/testPath.cpp index 52c56efb..de6ef60e 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -57,7 +57,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 0ae364b7..fb1080b3 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -94,7 +94,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index a6c10ba1..6e772915 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -80,7 +80,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testScene.cpp b/test/testScene.cpp index 5b12020e..daa5d868 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -87,7 +87,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 49558fb7..e64fa9aa 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -116,7 +116,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testShape.cpp b/test/testShape.cpp index 88519d05..af4d0c47 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -30,7 +30,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 91748727..778d7c7b 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -77,7 +77,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 445f8406..1205bb14 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -114,7 +114,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testSvg.cpp b/test/testSvg.cpp index e16f19b1..06fe3501 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -72,7 +72,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp index 171db919..2300f217 100644 --- a/test/testSvg2.cpp +++ b/test/testSvg2.cpp @@ -55,7 +55,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 7529d140..5ef33f44 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -83,7 +83,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 9c213436..3ff6c246 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -44,7 +44,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare From a5beca736913ecb5be833fd6d36d883f92cfd329 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 18 Aug 2020 20:19:31 +0900 Subject: [PATCH 235/244] sw_engine: code refactoring introduce compositor table for runtime colorspace switching. Change-Id: If179d1e1625f995e114d66cf1bf13742c54ed4f7 --- src/lib/sw_engine/tvgSwCommon.h | 63 +++------ src/lib/sw_engine/tvgSwFill.cpp | 10 +- src/lib/sw_engine/tvgSwRaster.cpp | 203 ++++++++++++++-------------- src/lib/sw_engine/tvgSwRenderer.cpp | 22 +-- src/lib/sw_engine/tvgSwRenderer.h | 6 +- src/lib/sw_engine/tvgSwShape.cpp | 4 +- 6 files changed, 149 insertions(+), 159 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index e5d4719f..ee705998 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -38,8 +38,6 @@ static double timeStamp() } #endif -using namespace tvg; - #define SW_CURVE_TYPE_POINT 0 #define SW_CURVE_TYPE_CUBIC 1 #define SW_OUTLINE_FILL_WINDING 0 @@ -215,58 +213,40 @@ struct SwShape bool rect; //Fast Track: Othogonal rectangle? }; +struct SwCompositor +{ + uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + uint32_t (*alpha)(uint32_t rgba); +}; + +struct SwSurface : Surface +{ + SwCompositor comp; +}; static inline SwCoord TO_SWCOORD(float val) { return SwCoord(val * 64); } - -static inline uint32_t RGBA_ALPHA(uint32_t rgba) -{ - return rgba & 0x000000ff; -} - - -static inline uint32_t ARGB_ALPHA(uint32_t argb) -{ - return (argb >> 24) & 0xff; -} - - static inline uint32_t RGBA_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) { - return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + - ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); + return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + + ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); } - static inline uint32_t RGBA_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) { - auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; - rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; - return (rgba1 |= t); + auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; + rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; + return (rgba1 |= t); } - -static inline uint32_t RGBA_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (r << 24 | g << 16 | b << 8 | a); -} - - -static inline uint32_t ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (a << 24 | r << 16 | g << 8 | b); -} - - static inline uint8_t ALPHA_MULTIPLY(uint32_t c, uint32_t a) { return (c * a) >> 8; } - int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -290,7 +270,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape* shape); -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable); +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable); void shapeResetFill(SwShape* shape); void shapeDelFill(SwShape* shape); @@ -299,7 +279,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke* stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, bool ctable); void fillReset(SwFill* fill); void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len); @@ -308,10 +288,11 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias); void rleFree(SwRleData* rle); -bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id); -bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterClear(Surface& surface); +bool rasterCompositor(SwSurface* surface); +bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id); +bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterClear(SwSurface* surface); static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index cd68d0f1..e748651d 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -34,7 +34,7 @@ #define FIXPT_SIZE (1<g, pColors->a); auto b = ALPHA_MULTIPLY(pColors->b, pColors->a); - auto rgba = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, pColors->a) : ARGB_JOIN(r, g, b, pColors->a); + auto rgba = surface->comp.join(r, g, b, pColors->a); auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); auto pos = 1.5f * inc; uint32_t i = 0; @@ -79,7 +79,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, uint32_t cs) auto g = ALPHA_MULTIPLY(next->g, next->a); auto b = ALPHA_MULTIPLY(next->b, next->a); - auto rgba2 = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, next->a) : ARGB_JOIN(r, g, b, next->a); + auto rgba2 = surface->comp.join(r, g, b, next->a); while (pos < next->offset && i < GRADIENT_STOP_SIZE) { auto t = (pos - curr->offset) * delta; @@ -282,7 +282,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, bool ctable) { if (!fill) return false; @@ -291,7 +291,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, fill->spread = fdata->spread(); if (ctable) { - if (!_updateColorTable(fill, fdata, cs)) return false; + if (!_updateColorTable(fill, fdata, surface)) return false; } if (fdata->id() == FILL_ID_LINEAR) { diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index d07d7eb1..072c74ce 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -28,27 +28,51 @@ /* Internal Class Implementation */ /************************************************************************/ -static SwBBox _clipRegion(Surface& surface, SwBBox& in) +static uint32_t _rgbaAlpha(uint32_t rgba) +{ + return rgba & 0x000000ff; +} + + +static uint32_t _argbAlpha(uint32_t argb) +{ + return (argb >> 24) & 0xff; +} + + +static uint32_t _rgbaJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (r << 24 | g << 16 | b << 8 | a); +} + + +static uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (a << 24 | r << 16 | g << 8 | b); +} + + +static SwBBox _clipRegion(Surface* surface, SwBBox& in) { auto bbox = in; if (bbox.min.x < 0) bbox.min.x = 0; if (bbox.min.y < 0) bbox.min.y = 0; - if (bbox.max.x > static_cast(surface.w)) bbox.max.x = surface.w; - if (bbox.max.y > static_cast(surface.h)) bbox.max.y = surface.h; + if (bbox.max.x > static_cast(surface->w)) bbox.max.x = surface->w; + if (bbox.max.y > static_cast(surface->h)) bbox.max.y = surface->h; return bbox; } -static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint32_t color) +static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { - auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); - auto ialpha = 255 - (surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(color) : ARGB_ALPHA(color); + auto ialpha = 255 - surface->comp.alpha(color); for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface.stride]; + auto dst = &buffer[y * surface->stride]; for (uint32_t x = 0; x < w; ++x) { dst[x] = color + RGBA_ALPHA_BLEND(dst[x], ialpha); } @@ -57,20 +81,20 @@ static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint3 } -static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t color) +static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color) { - auto buffer = surface.buffer + (region.min.y * surface.stride); + auto buffer = surface->buffer + (region.min.y * surface->stride); auto w = static_cast(region.max.x - region.min.x); auto h = static_cast(region.max.y - region.min.y); for (uint32_t y = 0; y < h; ++y) { - rasterRGBA32(buffer + y * surface.stride, color, region.min.x, w); + rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w); } return true; } -static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color) +static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color) { if (!rle) return false; @@ -78,10 +102,10 @@ static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t col uint32_t src; for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; if (span->coverage < 255) src = RGBA_ALPHA_BLEND(color, span->coverage); else src = color; - auto ialpha = 255 - ((surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(src) : ARGB_ALPHA(src)); + auto ialpha = 255 - surface->comp.alpha(src); for (uint32_t i = 0; i < span->len; ++i) { dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); } @@ -91,7 +115,7 @@ static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t col } -static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) +static bool _rasterSolidRle(SwSurface* surface, SwRleData* rle, uint32_t color) { if (!rle) return false; @@ -99,9 +123,9 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) for (uint32_t i = 0; i < rle->size; ++i) { if (span->coverage == 255) { - rasterRGBA32(surface.buffer + span->y * surface.stride, color, span->x, span->len); + rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len); } else { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto src = RGBA_ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { @@ -114,74 +138,62 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) } -static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, const SwFill* fill) +static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (!fill) return false; - auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); //Translucent Gradient if (fill->translucent) { - auto tmpBuf = static_cast(alloca(surface.w * sizeof(uint32_t))); + auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!tmpBuf) return false; for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface.stride]; + auto dst = &buffer[y * surface->stride]; fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w); - if (surface.cs == SwCanvas::RGBA8888) { - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x])); - } - } else { - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x])); - } + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x])); } } //Opaque Gradient } else { for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, buffer + y * surface.stride, region.min.y + y, region.min.x, 0, w); + fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, 0, w); } } return true; } -static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, const SwFill* fill) +static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (!fill) return false; - auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); //Translucent Gradient if (fill->translucent) { - auto tmpBuf = static_cast(alloca(surface.w * sizeof(uint32_t))); + auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!tmpBuf) return false; for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface.stride]; + auto dst = &buffer[y * surface->stride]; fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); - if (surface.cs == SwCanvas::RGBA8888) { - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x])); - } - } else { - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x])); - } + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x])); } } //Opaque Gradient } else { for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface.stride]; + auto dst = &buffer[y * surface->stride]; fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w); } } @@ -189,11 +201,11 @@ static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, co } -static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +static bool _rasterLinearGradientRle(SwSurface* surface, SwRleData* rle, const SwFill* fill) { if (!rle || !fill) return false; - auto buf = static_cast(alloca(surface.w * sizeof(uint32_t))); + auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!buf) return false; auto span = rle->spans; @@ -201,29 +213,16 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF //Translucent Gradient if (fill->translucent) { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); - if (surface.cs == SwCanvas::RGBA8888) { - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i])); - } - } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp)); - } + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i])); } } else { - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i])); - } - } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp)); - } + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp)); } } ++span; @@ -232,9 +231,9 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF } else { for (uint32_t i = 0; i < rle->size; ++i) { if (span->coverage == 255) { - fillFetchLinear(fill, surface.buffer + span->y * surface.stride, span->y, span->x, span->x, span->len); + fillFetchLinear(fill, surface->buffer + span->y * surface->stride, span->y, span->x, span->x, span->len); } else { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { @@ -248,11 +247,11 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF } -static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +static bool _rasterRadialGradientRle(SwSurface* surface, SwRleData* rle, const SwFill* fill) { if (!rle || !fill) return false; - auto buf = static_cast(alloca(surface.w * sizeof(uint32_t))); + auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!buf) return false; auto span = rle->spans; @@ -260,29 +259,16 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF //Translucent Gradient if (fill->translucent) { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchRadial(fill, buf, span->y, span->x, span->len); - if (surface.cs == SwCanvas::RGBA8888) { - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i])); - } - } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp)); - } + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i])); } } else { - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i])); - } - } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp)); - } + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp)); } } ++span; @@ -290,7 +276,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF //Opaque Gradient } else { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface.buffer[span->y * surface.stride + span->x]; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; if (span->coverage == 255) { fillFetchRadial(fill, dst, span->y, span->x, span->len); } else { @@ -311,7 +297,24 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF /* External Class Implementation */ /************************************************************************/ -bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id) +bool rasterCompositor(SwSurface* surface) +{ + if (surface->cs == SwCanvas::RGBA8888) { + surface->comp.alpha = _rgbaAlpha; + surface->comp.join = _rgbaJoin; + } else if (surface->cs == SwCanvas::ARGB8888) { + surface->comp.alpha = _argbAlpha; + surface->comp.join = _argbJoin; + } else { + //What Color Space ??? + return false; + } + + return true; +} + + +bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) { //Fast Track if (shape->rect) { @@ -326,13 +329,13 @@ bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id) } -bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { r = ALPHA_MULTIPLY(r, a); g = ALPHA_MULTIPLY(g, a); b = ALPHA_MULTIPLY(b, a); - auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a); + auto color = surface->comp.join(r, g, b, a); //Fast Track if (shape->rect) { @@ -347,28 +350,28 @@ bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, ui } -bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { r = ALPHA_MULTIPLY(r, a); g = ALPHA_MULTIPLY(g, a); b = ALPHA_MULTIPLY(b, a); - auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a); + auto color = surface->comp.join(r, g, b, a); if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color); return _rasterTranslucentRle(surface, shape->strokeRle, color); } -bool rasterClear(Surface& surface) +bool rasterClear(SwSurface* surface) { - if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; + if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false; - if (surface.w == surface.stride) { - rasterRGBA32(surface.buffer, 0x00000000, 0, surface.w * surface.h); + if (surface->w == surface->stride) { + rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h); } else { - for (uint32_t i = 0; i < surface.h; i++) { - rasterRGBA32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); + for (uint32_t i = 0; i < surface->h; i++) { + rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w); } } return true; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 66608f54..8d02b404 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -37,6 +37,7 @@ static RenderInitializer renderInit; SwRenderer::~SwRenderer() { + if (surface) delete(surface); } @@ -44,13 +45,18 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t { if (!buffer || stride == 0 || w == 0 || h == 0) return false; - surface.buffer = buffer; - surface.stride = stride; - surface.w = w; - surface.h = h; - surface.cs = cs; + if (!surface) { + surface = new SwSurface; + if (!surface) return false; + } - return true; + surface->buffer = buffer; + surface->stride = stride; + surface->w = w; + surface->h = h; + surface->cs = cs; + + return rasterCompositor(surface); } @@ -100,7 +106,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (flags == RenderUpdateFlag::None) return shape; - SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; + SwSize clip = {static_cast(surface->w), static_cast(surface->h)}; //Valid Stroking? uint8_t strokeAlpha = 0; @@ -130,7 +136,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (fill) { auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; if (ctable) shapeResetFill(shape); - if (!shapeGenFillColors(shape, fill, matrix, surface.cs, ctable)) return shape; + if (!shapeGenFillColors(shape, fill, matrix, surface, ctable)) return shape; } else { shapeDelFill(shape); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 5657602b..2185f344 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,11 +22,11 @@ #ifndef _TVG_SW_RENDERER_H_ #define _TVG_SW_RENDERER_H_ +struct SwSurface; + namespace tvg { -struct SwTask; - class SwRenderer : public RenderMethod { public: @@ -43,7 +43,7 @@ public: static int term(); private: - Surface surface = {nullptr, 0, 0, 0}; + SwSurface* surface = nullptr; SwRenderer(){}; ~SwRenderer(); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 3704a2cb..c94ef260 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -672,9 +672,9 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo } -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable) +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable) { - return fillGenColorTable(shape->fill, fill, transform, cs, ctable); + return fillGenColorTable(shape->fill, fill, transform, surface, ctable); } From 70b4703707a1bd5ebc4ffa372a4fe2dce86ce83f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 18 Aug 2020 20:35:13 +0900 Subject: [PATCH 236/244] remove print/cout logs. we need a comprehensive logging interface for this. right now, leave as "LOG:" to replace later. Change-Id: I25321223cd48ec13a1de5e4140cfea75a2f42866 --- src/lib/sw_engine/tvgSwFill.cpp | 2 +- src/lib/sw_engine/tvgSwRle.cpp | 6 +++--- src/lib/sw_engine/tvgSwStroke.cpp | 4 +++- src/lib/tvgPictureImpl.h | 4 ++-- src/loaders/svg/tvgSvgLoader.cpp | 14 +++++++------- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index e748651d..1539c172 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -300,7 +300,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, return _prepareRadial(fill, static_cast(fdata), transform); } - cout << "What type of gradient?!" << endl; + //LOG: What type of gradient?! return false; } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 6f1f2f2d..fb4b87bd 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -193,11 +193,11 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor //span has ushort coordinates. check limit overflow if (x >= SHRT_MAX) { - cout << "x(" << x << ") coordinate overflow!" << endl; + //LOG: x coordinate overflow! x = SHRT_MAX; } if (y >= SHRT_MAX) { - cout << "y(" << y << ") coordinate overflow!" << endl; + //LOG: y coordinate overflow! y = SHRT_MAX; } @@ -616,7 +616,7 @@ static bool _decomposeOutline(RleWorker& rw) return true; invalid_outline: - cout << "Invalid Outline!" << endl; + //LOG: Invalid Outline! return false; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index fbe28c1e..94c738c9 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -812,7 +812,9 @@ static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t if (*src & SW_STROKE_TAG_POINT) *tags = SW_CURVE_TYPE_POINT; else if (*src & SW_STROKE_TAG_CUBIC) *tags = SW_CURVE_TYPE_CUBIC; - else cout << "what type of stroke outline??" << endl; + else { + //LOG: What type of stroke outline?? + } if (*src & SW_STROKE_TAG_END) { *cntrs = idx; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 5ab9618f..d430de49 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -86,7 +86,7 @@ struct Picture::Impl if (loader) loader->close(); loader = LoaderMgr::loader(); if (!loader || !loader->open(path.c_str())) { - cout << "Non supported format: " << path.c_str() << endl; + //LOG: Non supported format return Result::NonSupport; } if (!loader->read()) return Result::Unknown; @@ -98,7 +98,7 @@ struct Picture::Impl if (loader) loader->close(); loader = LoaderMgr::loader(); if (!loader || !loader->open(data, size)) { - cout << "Non supported load data" << endl; + //LOG: Non supported load data return Result::NonSupport; } if (!loader->read()) return Result::Unknown; diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 1579390c..f1d94325 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1118,7 +1118,7 @@ static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const } -static void _attrParsePolygonPoints(const char* str, float** points, int* ptCount) +static bool _attrParsePolygonPoints(const char* str, float** points, int* ptCount) { float tmp[50]; int tmpCount = 0; @@ -1147,11 +1147,11 @@ static void _attrParsePolygonPoints(const char* str, float** points, int* ptCoun } *ptCount = count; *points = pointArray; - return; + return true; error_alloc: - printf("ERR : allocation for point array failed. out of memory"); - abort(); + //LOG: allocation for point array failed. out of memory + return false; } @@ -1168,7 +1168,7 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value else polygon = &(node->node.polyline); if (!strcmp(key, "points")) { - _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount); + return _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount); } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } else if (!strcmp(key, "id")) { @@ -2298,7 +2298,7 @@ bool SvgLoader::header() this->vw = loaderData.doc->node.doc.vw; this->vh = loaderData.doc->node.doc.vh; } else { - cout << "ERROR : No SVG File. There is no " < return false; } @@ -2322,7 +2322,7 @@ bool SvgLoader::open(const char* path) if (!f.is_open()) { - cout << "ERROR: Failed to open file = " << path; + //LOG: Failed to open file return false; } else { getline(f, filePath, '\0'); From ffa4a7248baf1ce68763f8243a7f25be9feba5f3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 19 Aug 2020 14:50:49 +0900 Subject: [PATCH 237/244] code refactoring Now, stabilizing is pretty enough. Remove assert code so that we never abort process in any cases. This also reduce the binary size. Change-Id: Ia7d2d5c5a0757b12481eaebad7a86aade6a89c1e --- src/lib/sw_engine/tvgSwFill.cpp | 11 +-------- src/lib/sw_engine/tvgSwMath.cpp | 2 -- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- src/lib/sw_engine/tvgSwRle.cpp | 13 ----------- src/lib/sw_engine/tvgSwShape.cpp | 21 ----------------- src/lib/sw_engine/tvgSwStroke.cpp | 36 ++--------------------------- src/lib/tvgCommon.h | 1 - src/lib/tvgGlCanvas.cpp | 5 +--- src/lib/tvgLinearGradient.cpp | 5 +--- src/lib/tvgRadialGradient.cpp | 5 +--- src/lib/tvgRender.cpp | 2 -- src/lib/tvgRender.h | 3 --- src/lib/tvgShapeImpl.h | 3 --- src/lib/tvgShapePath.h | 2 -- src/lib/tvgSwCanvas.cpp | 5 +--- 15 files changed, 8 insertions(+), 108 deletions(-) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 1539c172..ccc05745 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -36,11 +36,9 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, SwSurface* surface) { - assert(fill && fdata); - if (!fill->ctable) { fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); - assert(fill->ctable); + if (!fill->ctable) return false; } const Fill::ColorStop* colors; @@ -71,7 +69,6 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, SwSurface* surfac for (uint32_t j = 0; j < cnt - 1; ++j) { auto curr = colors + j; auto next = curr + 1; - assert(curr && next); auto delta = 1.0f / (next->offset - curr->offset); if (next->a < 255) fill->translucent = true; @@ -104,8 +101,6 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, SwSurface* surfac bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* transform) { - assert(fill && linear); - float x1, x2, y1, y2; if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; @@ -140,8 +135,6 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform) { - assert(fill && radial); - float radius; if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; if (radius < FLT_EPSILON) return true; @@ -286,8 +279,6 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, { if (!fill) return false; - assert(fdata); - fill->spread = fdata->spread(); if (ctable) { diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 5ac3912a..5227d794 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -384,8 +384,6 @@ SwFixed mathLength(SwPoint& pt) void mathSplitCubic(SwPoint* base) { - assert(base); - SwCoord a, b, c, d; base[6].x = base[3].x; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 8d02b404..b173ce47 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -101,7 +101,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* auto shape = static_cast(data); if (!shape) { shape = static_cast(calloc(1, sizeof(SwShape))); - assert(shape); + if (!shape) return nullptr; } if (flags == RenderUpdateFlag::None) return shape; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index fb4b87bd..c9aa6aec 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -145,8 +145,6 @@ static inline SwCoord HYPOT(SwPoint pt) static void _genSpan(SwRleData* rle, SwSpan* spans, uint32_t count) { - assert(rle && spans); - auto newSize = rle->size + count; /* allocate enough memory for new spans */ @@ -155,12 +153,10 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, uint32_t count) if (rle->alloc < newSize) { rle->alloc = (newSize * 2); rle->spans = static_cast(realloc(rle->spans, rle->alloc * sizeof(SwSpan))); - assert(rle->spans); } //copy the new spans to the allocated memory SwSpan* lastSpan = rle->spans + rle->size; - assert(lastSpan); memcpy(lastSpan, spans, count * sizeof(SwSpan)); rle->size = newSize; @@ -205,7 +201,6 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor if (!rw.antiAlias) coverage = 255; auto count = rw.spansCnt; auto span = rw.spans + count - 1; - assert(span); //see whether we can add this span to the current list if ((count > 0) && (rw.ySpan == y) && @@ -226,10 +221,8 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor rw.spansCnt = 0; rw.ySpan = 0; span = rw.spans; - assert(span); } else { ++span; - assert(span); } //Clip x range @@ -290,7 +283,6 @@ static Cell* _findCell(RleWorker& rw) if (x > rw.cellXCnt) x = rw.cellXCnt; auto pcell = &rw.yCells[rw.cellPos.y]; - assert(pcell); while(true) { Cell* cell = *pcell; @@ -302,7 +294,6 @@ static Cell* _findCell(RleWorker& rw) if (rw.cellsCnt >= rw.maxCells) longjmp(rw.jmpBuf, 1); auto cell = rw.cells + rw.cellsCnt++; - assert(cell); cell->x = x; cell->area = 0; cell->cover = 0; @@ -317,7 +308,6 @@ static void _recordCell(RleWorker& rw) { if (rw.area | rw.cover) { auto cell = _findCell(rw); - assert(cell); cell->area += rw.area; cell->cover += rw.cover; } @@ -498,8 +488,6 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) { auto arc = rw.bezStack; - assert(arc); - arc[0] = to; arc[1] = ctrl2; arc[2] = ctrl1; @@ -668,7 +656,6 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.clip = clip; rw.antiAlias = antiAlias; rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); - assert(rw.rle); //Generate RLE Band bands[BAND_SIZE]; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index c94ef260..f14d3b65 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -76,7 +76,6 @@ static void _growOutlineContour(SwOutline& outline, uint32_t n) if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; outline.reservedCntrsCnt = outline.cntrsCnt + n; outline.cntrs = static_cast(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t))); - assert(outline.cntrs); } @@ -85,9 +84,7 @@ static void _growOutlinePoint(SwOutline& outline, uint32_t n) if (outline.reservedPtsCnt >= outline.ptsCnt + n) return; outline.reservedPtsCnt = outline.ptsCnt + n; outline.pts = static_cast(realloc(outline.pts, outline.reservedPtsCnt * sizeof(SwPoint))); - assert(outline.pts); outline.types = static_cast(realloc(outline.types, outline.reservedPtsCnt * sizeof(uint8_t))); - assert(outline.types); } @@ -114,8 +111,6 @@ static void _outlineEnd(SwOutline& outline) static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform) { - assert(to); - _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = _transform(to, transform); @@ -134,8 +129,6 @@ static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* tr static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix* transform) { - assert(to); - _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = _transform(to, transform); @@ -146,8 +139,6 @@ static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix* tr static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) { - assert(ctrl1 && ctrl2 && to); - _growOutlinePoint(outline, 3); outline.pts[outline.ptsCnt] = _transform(ctrl1, transform); @@ -203,7 +194,6 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) if (!outline) return false; auto pt = outline->pts; - assert(pt); if (outline->ptsCnt <= 0) { _initBBox(bbox); @@ -236,8 +226,6 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) { - assert(outline); - if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; //Check boundary @@ -341,8 +329,6 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) { - assert(sdata); - const PathCommand* cmds = nullptr; auto cmdCnt = sdata->pathCommands(&cmds); @@ -361,12 +347,10 @@ SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) const float* pattern; dash.cnt = sdata->strokeDash(&pattern); - assert(dash.cnt > 0 && pattern); //Is it safe to mutual exclusive? dash.pattern = const_cast(pattern); dash.outline = static_cast(calloc(1, sizeof(SwOutline))); - assert(dash.outline); dash.outline->opened = true; //smart reservation @@ -510,8 +494,6 @@ void shapeReset(SwShape* shape) bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform) { - assert(sdata); - const PathCommand* cmds = nullptr; auto cmdCnt = sdata->pathCommands(&cmds); @@ -552,7 +534,6 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform auto outline = shape->outline; if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); - assert(outline); outline->opened = true; _growOutlinePoint(*outline, outlinePtsCnt); @@ -638,8 +619,6 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip) { - assert(sdata); - SwOutline* shapeOutline = nullptr; //Dash Style Stroke diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 94c738c9..8400237a 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -48,8 +48,6 @@ static inline void SCALE(SwStroke& stroke, SwPoint& pt) static void _growBorder(SwStrokeBorder* border, uint32_t newPts) { - assert(border); - auto maxOld = border->maxPts; auto maxNew = border->ptsCnt + newPts; @@ -61,21 +59,15 @@ static void _growBorder(SwStrokeBorder* border, uint32_t newPts) maxCur += (maxCur >> 1) + 16; border->pts = static_cast(realloc(border->pts, maxCur * sizeof(SwPoint))); - assert(border->pts); - border->tags = static_cast(realloc(border->tags, maxCur * sizeof(uint8_t))); - assert(border->tags); - border->maxPts = maxCur; } static void _borderClose(SwStrokeBorder* border, bool reverse) { - assert(border && border->start >= 0); - - uint32_t start = border->start; - uint32_t count = border->ptsCnt; + auto start = border->start; + auto count = border->ptsCnt; //Don't record empty paths! if (count <= start + 1U) { @@ -123,8 +115,6 @@ static void _borderClose(SwStrokeBorder* border, bool reverse) static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to) { - assert(border && border->start >= 0); - _growBorder(border, 3); auto pt = border->pts + border->ptsCnt; @@ -199,8 +189,6 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) { - assert(border && border->start >= 0); - if (border->movable) { //move last point border->pts[border->ptsCnt - 1] = to; @@ -221,8 +209,6 @@ static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable) static void _borderMoveTo(SwStrokeBorder* border, SwPoint& to) { - assert(border); - //close current open path if any? if (border->start >= 0) _borderClose(border, false); @@ -249,10 +235,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) { constexpr SwFixed MITER_LIMIT = 4 * (1 << 16); - assert(MITER_LIMIT >= 0x10000); - auto border = stroke.borders + side; - assert(border); if (stroke.join == StrokeJoin::Round) { _arcTo(stroke, side); @@ -640,8 +623,6 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) { auto right = stroke.borders + 0; auto left = stroke.borders + 1; - assert(left->start >= 0); - auto newPts = left->ptsCnt - left->start; if (newPts <= 0) return; @@ -708,7 +689,6 @@ static void _endSubPath(SwStroke& stroke) { if (stroke.openSubPath) { auto right = stroke.borders; - assert(right); /* all right, this is an opened path, we need to add a cap between right & left, add the reverse of left, then add a final cap @@ -756,8 +736,6 @@ static void _endSubPath(SwStroke& stroke) static void _getCounts(SwStrokeBorder* border, uint32_t& ptsCnt, uint32_t& cntrsCnt) { - assert(border); - auto count = border->ptsCnt; auto tags = border->tags; uint32_t _ptsCnt = 0; @@ -796,7 +774,6 @@ fail: static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t side) { auto border = stroke.borders + side; - assert(border); if (!border->valid) return; @@ -850,8 +827,6 @@ void strokeFree(SwStroke* stroke) void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform) { - assert(sdata); - if (transform) { stroke->sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); stroke->sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); @@ -941,16 +916,9 @@ SwOutline* strokeExportOutline(SwStroke* stroke) auto cntrsCnt = count2 + count4; auto outline = static_cast(calloc(1, sizeof(SwOutline))); - assert(outline); - outline->pts = static_cast(malloc(sizeof(SwPoint) * ptsCnt)); - assert(outline->pts); - outline->types = static_cast(malloc(sizeof(uint8_t) * ptsCnt)); - assert(outline->types); - outline->cntrs = static_cast(malloc(sizeof(uint32_t) * cntrsCnt)); - assert(outline->cntrs); _exportBorderOutline(*stroke, outline, 0); //left _exportBorderOutline(*stroke, outline, 1); //right diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 0c73b914..66e08bf5 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -25,7 +25,6 @@ #include "config.h" #include -#include #include #include #include diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 1ac57329..e1b5c3c8 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -81,10 +81,7 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t unique_ptr GlCanvas::gen() noexcept { #ifdef THORVG_GL_RASTER_SUPPORT - auto canvas = unique_ptr(new GlCanvas); - assert(canvas); - - return canvas; + return unique_ptr(new GlCanvas); #endif return nullptr; } diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp index 68a0d8aa..bd2dbc17 100644 --- a/src/lib/tvgLinearGradient.cpp +++ b/src/lib/tvgLinearGradient.cpp @@ -76,10 +76,7 @@ Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const unique_ptr LinearGradient::gen() noexcept { - auto fill = unique_ptr(new LinearGradient); - assert(fill); - - return fill; + return unique_ptr(new LinearGradient); } #endif /* _TVG_LINEAR_GRADIENT_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp index 179c51e3..9f123bf9 100644 --- a/src/lib/tvgRadialGradient.cpp +++ b/src/lib/tvgRadialGradient.cpp @@ -73,10 +73,7 @@ Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcep unique_ptr RadialGradient::gen() noexcept { - auto fill = unique_ptr(new RadialGradient); - assert(fill); - - return fill; + return unique_ptr(new RadialGradient); } #endif /* _TVG_RADIAL_GRADIENT_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index b1e8cf0e..30bc906d 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -107,8 +107,6 @@ RenderTransform::RenderTransform() RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) { - assert(lhs && rhs); - m.e11 = lhs->m.e11 * rhs->m.e11 + lhs->m.e12 * rhs->m.e21 + lhs->m.e13 * rhs->m.e31; m.e12 = lhs->m.e11 * rhs->m.e12 + lhs->m.e12 * rhs->m.e22 + lhs->m.e13 * rhs->m.e32; m.e13 = lhs->m.e11 * rhs->m.e13 + lhs->m.e12 * rhs->m.e23 + lhs->m.e13 * rhs->m.e33; diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 3535bf43..c379d0e4 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -76,7 +76,6 @@ struct RenderInitializer static bool init(RenderInitializer& renderInit, RenderMethod* engine) { - assert(engine); if (renderInit.pInst || renderInit.refCnt > 0) return false; renderInit.pInst = engine; renderInit.refCnt = 0; @@ -100,7 +99,6 @@ struct RenderInitializer static uint32_t unref(RenderInitializer& renderInit) { - assert(renderInit.refCnt > 0); --renderInit.refCnt; //engine has been requested to termination @@ -115,7 +113,6 @@ struct RenderInitializer static RenderMethod* inst(RenderInitializer& renderInit) { - assert(renderInit.pInst); return renderInit.pInst; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 1b85c07b..612bfe34 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -144,8 +144,6 @@ struct Shape::Impl bool strokeDash(const float* pattern, uint32_t cnt) { - assert(pattern); - if (!stroke) stroke = new ShapeStroke(); if (!stroke) return false; @@ -155,7 +153,6 @@ struct Shape::Impl } if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); - assert(stroke->dashPattern); for (uint32_t i = 0; i < cnt; ++i) stroke->dashPattern[i] = pattern[i]; diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 75c86ad6..04934dca 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -50,7 +50,6 @@ struct ShapePath if (cmdCnt <= reservedCmdCnt) return; reservedCmdCnt = cmdCnt; cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); - assert(cmds); } void reservePts(uint32_t ptsCnt) @@ -58,7 +57,6 @@ struct ShapePath if (ptsCnt <= reservedPtsCnt) return; reservedPtsCnt = ptsCnt; pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); - assert(pts); } void grow(uint32_t cmdCnt, uint32_t ptsCnt) diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 755d422d..5d280fd3 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -80,10 +80,7 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t unique_ptr SwCanvas::gen() noexcept { #ifdef THORVG_SW_RASTER_SUPPORT - auto canvas = unique_ptr(new SwCanvas); - assert(canvas); - - return canvas; + return unique_ptr(new SwCanvas); #endif return nullptr; } From 06d8d06993118b386a40b341db92a567d662068e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 19 Aug 2020 18:32:32 +0900 Subject: [PATCH 238/244] sw_engine: replace rgba8888 with abgr8888 Actually Dali rendering system requires abgr8888. We could add more colorspaces if it's necessary. Change-Id: Ia42a6575d1313629e55efc3077e302992c47b6c0 --- inc/thorvg.h | 2 +- inc/thorvg_capi.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 14 ++++----- src/lib/sw_engine/tvgSwFill.cpp | 2 +- src/lib/sw_engine/tvgSwRaster.cpp | 52 ++++++++++++++----------------- 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 9ed54988..18013fa5 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -311,7 +311,7 @@ class TVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - enum Colorspace { RGBA8888 = 0, ARGB8888 }; + enum Colorspace { ABGR8888 = 0, ARGB8888 }; Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept; diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 2f1bf967..811c82e3 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -23,7 +23,7 @@ typedef struct _Tvg_Gradient Tvg_Gradient; #define TVG_ENGINE_SW (1 << 1) #define TVG_ENGINE_GL (1 << 2) -#define TVG_COLORSPACE_RGBA8888 0 +#define TVG_COLORSPACE_ABGR8888 0 #define TVG_COLORSPACE_ARGB8888 1 typedef enum { diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index ee705998..a600cb9d 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -229,17 +229,17 @@ static inline SwCoord TO_SWCOORD(float val) return SwCoord(val * 64); } -static inline uint32_t RGBA_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) +static inline uint32_t ALPHA_BLEND(uint32_t c, uint32_t a) { - return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + - ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); + return (((((c >> 8) & 0x00ff00ff) * a) & 0xff00ff00) + + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff)); } -static inline uint32_t RGBA_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) +static inline uint32_t COLOR_INTERPOLATE(uint32_t c1, uint32_t a1, uint32_t c2, uint32_t a2) { - auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; - rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; - return (rgba1 |= t); + auto t = (((c1 & 0xff00ff) * a1 + (c2 & 0xff00ff) * a2) >> 8) & 0xff00ff; + c1 = (((c1 >> 8) & 0xff00ff) * a1 + ((c2 >> 8) & 0xff00ff) * a2) & 0xff00ff00; + return (c1 |= t); } static inline uint8_t ALPHA_MULTIPLY(uint32_t c, uint32_t a) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index ccc05745..72e702b4 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -82,7 +82,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, SwSurface* surfac auto t = (pos - curr->offset) * delta; auto dist = static_cast(256 * t); auto dist2 = 256 - dist; - fill->ctable[i] = RGBA_INTERPOLATE(rgba, dist2, rgba2, dist); + fill->ctable[i] = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); ++i; pos += inc; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 072c74ce..3fec5248 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -28,21 +28,15 @@ /* Internal Class Implementation */ /************************************************************************/ -static uint32_t _rgbaAlpha(uint32_t rgba) +static uint32_t _colorAlpha(uint32_t c) { - return rgba & 0x000000ff; + return (c >> 24) & 0xff; } -static uint32_t _argbAlpha(uint32_t argb) +static uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (argb >> 24) & 0xff; -} - - -static uint32_t _rgbaJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (r << 24 | g << 16 | b << 8 | a); + return (a << 24 | b << 16 | g << 8 | r); } @@ -74,7 +68,7 @@ static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uin for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface->stride]; for (uint32_t x = 0; x < w; ++x) { - dst[x] = color + RGBA_ALPHA_BLEND(dst[x], ialpha); + dst[x] = color + ALPHA_BLEND(dst[x], ialpha); } } return true; @@ -103,11 +97,11 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface->buffer[span->y * surface->stride + span->x]; - if (span->coverage < 255) src = RGBA_ALPHA_BLEND(color, span->coverage); + if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); else src = color; auto ialpha = 255 - surface->comp.alpha(src); for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); + dst[i] = src + ALPHA_BLEND(dst[i], ialpha); } ++span; } @@ -126,10 +120,10 @@ static bool _rasterSolidRle(SwSurface* surface, SwRleData* rle, uint32_t color) rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len); } else { auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto src = RGBA_ALPHA_BLEND(color, span->coverage); + auto src = ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); + dst[i] = src + ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -156,7 +150,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, auto dst = &buffer[y * surface->stride]; fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w); for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x])); + dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x])); } } //Opaque Gradient @@ -187,7 +181,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, auto dst = &buffer[y * surface->stride]; fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x])); + dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x])); } } //Opaque Gradient @@ -217,12 +211,12 @@ static bool _rasterLinearGradientRle(SwSurface* surface, SwRleData* rle, const S fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i])); + dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i])); } } else { for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp)); + auto tmp = ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp)); } } ++span; @@ -237,7 +231,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, SwRleData* rle, const S fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha); + dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -263,12 +257,12 @@ static bool _rasterRadialGradientRle(SwSurface* surface, SwRleData* rle, const S fillFetchRadial(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i])); + dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i])); } } else { for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp)); + auto tmp = ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp)); } } ++span; @@ -283,7 +277,7 @@ static bool _rasterRadialGradientRle(SwSurface* surface, SwRleData* rle, const S fillFetchRadial(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha); + dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -299,11 +293,11 @@ static bool _rasterRadialGradientRle(SwSurface* surface, SwRleData* rle, const S bool rasterCompositor(SwSurface* surface) { - if (surface->cs == SwCanvas::RGBA8888) { - surface->comp.alpha = _rgbaAlpha; - surface->comp.join = _rgbaJoin; + if (surface->cs == SwCanvas::ABGR8888) { + surface->comp.alpha = _colorAlpha; + surface->comp.join = _abgrJoin; } else if (surface->cs == SwCanvas::ARGB8888) { - surface->comp.alpha = _argbAlpha; + surface->comp.alpha = _colorAlpha; surface->comp.join = _argbJoin; } else { //What Color Space ??? From 9d58643a6c17ba4479734ef9a296d168d57ce153 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 20 Aug 2020 12:18:51 +0900 Subject: [PATCH 239/244] sw_engine: fix loss of data when it's converting. if SwCoord type is determined to 4byte, it could lose remarkable value that occur stroking jiggling. This fixes the issue. Change-Id: Ib2fed2a3bfc9188a30522f35837439364d446a73 --- src/lib/sw_engine/tvgSwMath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 5227d794..b3cf4778 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -29,7 +29,7 @@ /* Internal Class Implementation */ /************************************************************************/ -constexpr SwCoord CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 +constexpr SwFixed CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 //this table was generated for SW_FT_PI = 180L << 16, i.e. degrees constexpr static auto ATAN_MAX = 23; From 04c6295974b404dee9b8e89833acdd45bce64948 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 20 Aug 2020 16:16:46 +0900 Subject: [PATCH 240/244] code refactoring remove unnecessary condition. implementation won't be included multiple times not like headers. Thus this condition is unnecessary. Change-Id: Id37e675c40ce7213a06c950da8e5ca17ff7245c9 --- src/lib/gl_engine/tvgGlRenderer.cpp | 8 +------- src/lib/sw_engine/tvgSwFill.cpp | 7 +------ src/lib/sw_engine/tvgSwMath.cpp | 6 +----- src/lib/sw_engine/tvgSwRaster.cpp | 7 +------ src/lib/sw_engine/tvgSwRenderer.cpp | 7 +------ src/lib/sw_engine/tvgSwRle.cpp | 7 +------ src/lib/sw_engine/tvgSwShape.cpp | 8 +------- src/lib/sw_engine/tvgSwStroke.cpp | 7 +------ src/lib/tvgBezier.cpp | 8 +------- src/lib/tvgCanvas.cpp | 7 +------ src/lib/tvgFill.cpp | 7 +------ src/lib/tvgGlCanvas.cpp | 8 +------- src/lib/tvgInitializer.cpp | 7 +------ src/lib/tvgLinearGradient.cpp | 7 +------ src/lib/tvgLoaderMgr.cpp | 7 +------ src/lib/tvgPaint.cpp | 7 +------ src/lib/tvgPicture.cpp | 7 +------ src/lib/tvgRadialGradient.cpp | 7 +------ src/lib/tvgRender.cpp | 7 +------ src/lib/tvgScene.cpp | 7 +------ src/lib/tvgShape.cpp | 8 +------- src/lib/tvgSwCanvas.cpp | 7 +------ src/loaders/svg/tvgSimpleXmlParser.cpp | 3 +-- src/loaders/svg/tvgSvgLoader.cpp | 7 +------ src/loaders/svg/tvgSvgPath.cpp | 8 +------- src/loaders/svg/tvgSvgSceneBuilder.cpp | 10 +--------- 26 files changed, 26 insertions(+), 160 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index a295ed65..f6b31d41 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -19,10 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -#ifndef _TVG_GL_RENDERER_CPP_ -#define _TVG_GL_RENDERER_CPP_ - #include "tvgGlShaderSrc.h" #include "tvgGlGpuBuffer.h" #include "tvgGlGeometry.h" @@ -216,6 +212,4 @@ void GlRenderer::drawPrimitive(GlGeometry& geometry, float r, float g, float b, geometry.draw(mVertexAttrLoc, primitiveIndex, flag); geometry.disableVertex(mVertexAttrLoc); -} - -#endif /* _TVG_GL_RENDERER_CPP_ */ +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 72e702b4..91a064de 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_FILL_CPP_ -#define _TVG_SW_FILL_CPP_ - #include "tvgSwCommon.h" @@ -314,6 +311,4 @@ void fillFree(SwFill* fill) if (fill->ctable) free(fill->ctable); free(fill); -} - -#endif /* _TVG_SW_FILL_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index b3cf4778..56ce40fc 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_MATH_H_ -#define _TVG_SW_MATH_H_ - #include "tvgSwCommon.h" @@ -417,5 +414,4 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2) if (delta > SW_ANGLE_PI) delta -= SW_ANGLE_2PI; return delta; -} -#endif /* _TVG_SW_MATH_H_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 3fec5248..7b5b9868 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_RASTER_CPP_ -#define _TVG_SW_RASTER_CPP_ - #include "tvgSwCommon.h" /************************************************************************/ @@ -369,6 +366,4 @@ bool rasterClear(SwSurface* surface) } } return true; -} - -#endif /* _TVG_SW_RASTER_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index b173ce47..1a1e0bf7 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_RENDERER_CPP_ -#define _TVG_SW_RENDERER_CPP_ - #include "tvgSwCommon.h" #include "tvgSwRenderer.h" @@ -185,6 +182,4 @@ SwRenderer* SwRenderer::inst() { //We know renderer type, avoid dynamic_cast for performance. return static_cast(RenderInitializer::inst(renderInit)); -} - -#endif /* _TVG_SW_RENDERER_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index c9aa6aec..37a860f5 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_RLE_H_ -#define _TVG_SW_RLE_H_ - #include #include #include @@ -754,6 +751,4 @@ void rleFree(SwRleData* rle) if (!rle) return; if (rle->spans) free(rle->spans); free(rle); -} - -#endif /* _TVG_SW_RLE_H_ */ +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index f14d3b65..d0a8f96d 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_SHAPE_H_ -#define _TVG_SW_SHAPE_H_ - #include "tvgSwCommon.h" /************************************************************************/ @@ -672,7 +669,4 @@ void shapeDelFill(SwShape* shape) if (!shape->fill) return; fillFree(shape->fill); shape->fill = nullptr; -} - - -#endif /* _TVG_SW_SHAPE_H_ */ +} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 8400237a..08754f84 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SW_STROKER_H_ -#define _TVG_SW_STROKER_H_ - #include "tvgSwCommon.h" @@ -924,6 +921,4 @@ SwOutline* strokeExportOutline(SwStroke* stroke) _exportBorderOutline(*stroke, outline, 1); //right return outline; -} - -#endif /* _TVG_SW_STROKER_H_ */ +} \ No newline at end of file diff --git a/src/lib/tvgBezier.cpp b/src/lib/tvgBezier.cpp index 0ed4ed21..db4d58be 100644 --- a/src/lib/tvgBezier.cpp +++ b/src/lib/tvgBezier.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_BEZIER_CPP_ -#define _TVG_BEZIER_CPP_ - #include "tvgCommon.h" @@ -143,7 +140,4 @@ void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) bezSplitLeft(right, t, left); } - -} - -#endif //_TVG_BEZIER_CPP_ +} \ No newline at end of file diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 7e7250aa..957940ca 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_CANVAS_CPP_ -#define _TVG_CANVAS_CPP_ - #include "tvgCommon.h" #include "tvgCanvasImpl.h" @@ -75,6 +72,4 @@ Result Canvas::sync() noexcept if (IMPL->renderer->flush()) return Result::Success; return Result::InsufficientCondition; -} - -#endif /* _TVG_CANVAS_CPP_ */ +} \ No newline at end of file diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp index d1240f0d..cc1a13bf 100644 --- a/src/lib/tvgFill.cpp +++ b/src/lib/tvgFill.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_FILL_CPP_ -#define _TVG_FILL_CPP_ - #include "tvgCommon.h" @@ -99,6 +96,4 @@ Result Fill::spread(FillSpread s) noexcept FillSpread Fill::spread() const noexcept { return IMPL->spread; -} - -#endif /* _TVG_FILL_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index e1b5c3c8..7f267a44 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_GLCANVAS_CPP_ -#define _TVG_GLCANVAS_CPP_ - #include "tvgCommon.h" #include "tvgCanvasImpl.h" @@ -84,7 +81,4 @@ unique_ptr GlCanvas::gen() noexcept return unique_ptr(new GlCanvas); #endif return nullptr; -} - - -#endif /* _TVG_GLCANVAS_CPP_ */ +} \ No newline at end of file diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index 3367603a..2185c0f0 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_INITIALIZER_CPP_ -#define _TVG_INITIALIZER_CPP_ - #include "tvgCommon.h" #include "tvgLoaderMgr.h" @@ -107,6 +104,4 @@ Result Initializer::threads(uint32_t cnt) noexcept uint32_t Initializer::threads() noexcept { return threadCnt; -} - -#endif /* _TVG_INITIALIZER_CPP_ */ +} \ No newline at end of file diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp index bd2dbc17..a76239e3 100644 --- a/src/lib/tvgLinearGradient.cpp +++ b/src/lib/tvgLinearGradient.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_LINEAR_GRADIENT_CPP_ -#define _TVG_LINEAR_GRADIENT_CPP_ - #include "tvgCommon.h" /************************************************************************/ @@ -77,6 +74,4 @@ Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const unique_ptr LinearGradient::gen() noexcept { return unique_ptr(new LinearGradient); -} - -#endif /* _TVG_LINEAR_GRADIENT_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index 5e59a447..6ec32132 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_LOADER_MGR_CPP_ -#define _TVG_LOADER_MGR_CPP_ - #include "tvgCommon.h" #ifdef THORVG_SVG_LOADER_SUPPORT @@ -56,6 +53,4 @@ unique_ptr LoaderMgr::loader() return unique_ptr(new SvgLoader); #endif return nullptr; -} - -#endif //_TVG_LOADER_MGR_CPP_ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 7984ac0e..3105e279 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_PAINT_CPP_ -#define _TVG_PAINT_CPP_ - #include "tvgCommon.h" /************************************************************************/ @@ -74,6 +71,4 @@ Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept { if (IMPL->bounds(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; -} - -#endif //_TVG_PAINT_CPP_ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index 70836924..7c20a372 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_PICTURE_CPP_ -#define _TVG_PICTURE_CPP_ - #include "tvgPictureImpl.h" /************************************************************************/ @@ -65,6 +62,4 @@ Result Picture::viewbox(float* x, float* y, float* w, float* h) const noexcept { if (IMPL->viewbox(x, y, w, h)) return Result::Success; return Result::InsufficientCondition; -} - -#endif /* _TVG_PICTURE_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp index 9f123bf9..92e934ee 100644 --- a/src/lib/tvgRadialGradient.cpp +++ b/src/lib/tvgRadialGradient.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_RADIAL_GRADIENT_CPP_ -#define _TVG_RADIAL_GRADIENT_CPP_ - #include "tvgCommon.h" /************************************************************************/ @@ -74,6 +71,4 @@ Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcep unique_ptr RadialGradient::gen() noexcept { return unique_ptr(new RadialGradient); -} - -#endif /* _TVG_RADIAL_GRADIENT_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 30bc906d..10a23e8c 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_RENDER_CPP_ -#define _TVG_RENDER_CPP_ - #include "tvgCommon.h" /************************************************************************/ @@ -118,6 +115,4 @@ RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransfo m.e31 = lhs->m.e31 * rhs->m.e11 + lhs->m.e32 * rhs->m.e21 + lhs->m.e33 * rhs->m.e31; m.e32 = lhs->m.e31 * rhs->m.e12 + lhs->m.e32 * rhs->m.e22 + lhs->m.e33 * rhs->m.e32; m.e33 = lhs->m.e31 * rhs->m.e13 + lhs->m.e32 * rhs->m.e23 + lhs->m.e33 * rhs->m.e33; -} - -#endif //_TVG_RENDER_CPP_ +} \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 9120e00b..df7362fb 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SCENE_CPP_ -#define _TVG_SCENE_CPP_ - #include "tvgSceneImpl.h" /************************************************************************/ @@ -60,6 +57,4 @@ Result Scene::reserve(uint32_t size) noexcept IMPL->paints.reserve(size); return Result::Success; -} - -#endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index c688ffc7..8db945d7 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SHAPE_CPP_ -#define _TVG_SHAPE_CPP_ - #include #include "tvgShapeImpl.h" @@ -405,7 +402,4 @@ StrokeJoin Shape::strokeJoin() const noexcept if (!IMPL->stroke) return StrokeJoin::Bevel; return IMPL->stroke->join; -} - - -#endif //_TVG_SHAPE_CPP_ +} \ No newline at end of file diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 5d280fd3..b56beb46 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SWCANVAS_CPP_ -#define _TVG_SWCANVAS_CPP_ - #include "tvgCommon.h" #include "tvgCanvasImpl.h" @@ -83,6 +80,4 @@ unique_ptr SwCanvas::gen() noexcept return unique_ptr(new SwCanvas); #endif return nullptr; -} - -#endif /* _TVG_SWCANVAS_CPP_ */ +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSimpleXmlParser.cpp b/src/loaders/svg/tvgSimpleXmlParser.cpp index 932d0717..76200aeb 100644 --- a/src/loaders/svg/tvgSimpleXmlParser.cpp +++ b/src/loaders/svg/tvgSimpleXmlParser.cpp @@ -364,5 +364,4 @@ const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength) } return nullptr; -} - +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index f1d94325..b174300e 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -19,9 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SVG_LOADER_CPP_ -#define _TVG_SVG_LOADER_CPP_ - #include #include #include "tvgSvgLoader.h" @@ -2391,6 +2388,4 @@ bool SvgLoader::close() unique_ptr SvgLoader::data() { return move(root); -} - -#endif //_TVG_SVG_LOADER_CPP_ +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index 2d3b86a9..c9b90fe7 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -19,10 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -#ifndef __TVG_SVG_PATH_CPP_ -#define __TVG_SVG_PATH_CPP_ - #include "tvgSvgPath.h" @@ -500,6 +496,4 @@ tuple, vector> svgPathToTvgPath(const char* svgPath) if (curLocale) free(curLocale); return make_tuple(cmds, pts); -} - -#endif //__TVG_SVG_PATH_CPP_ +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index faea2ec4..5496ae87 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -19,11 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -#ifndef _TVG_SVG_SCENE_BUILDER_CPP_ -#define _TVG_SVG_SCENE_BUILDER_CPP_ - - #include "tvgSvgSceneBuilder.h" unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh) @@ -374,7 +369,4 @@ unique_ptr SvgSceneBuilder::build(SvgNode* node) viewBox.h = node->node.doc.vh; preserveAspect = node->node.doc.preserveAspect; return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h, 255); -} - - -#endif //_TVG_SVG_SCENE_BUILDER_CPP_ +} \ No newline at end of file From 5905c0c323f4768ba2298828c389109c6ecfd390 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 16 Aug 2020 15:23:42 +0200 Subject: [PATCH 241/244] svg path: changes in processing cmds T,Q,S Change-Id: I979bb8cbcbdd4fd1374205feac6acedc58bdd3e1 --- src/loaders/svg/tvgSvgPath.cpp | 47 +++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index c9b90fe7..4efc009b 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -239,7 +239,9 @@ static int _numberCount(char cmd) case 'M': case 'm': case 'L': - case 'l': { + case 'l': + case 'T': + case 't': { count = 2; break; } @@ -260,9 +262,7 @@ static int _numberCount(char cmd) case 'S': case 's': case 'Q': - case 'q': - case 'T': - case 't': { + case 'q': { count = 4; break; } @@ -278,7 +278,7 @@ static int _numberCount(char cmd) } -static void _processCommand(vector* cmds, vector* pts, char cmd, float* arr, int count, Point* cur, Point* curCtl) +static void _processCommand(vector* cmds, vector* pts, char cmd, float* arr, int count, Point* cur, Point* curCtl, bool *isQuadratic) { int i; switch (cmd) { @@ -341,12 +341,14 @@ static void _processCommand(vector* cmds, vector* pts, char pts->push_back(p[2]); *curCtl = p[1]; *cur = p[2]; + *isQuadratic = false; break; } case 's': case 'S': { Point p[3], ctrl; - if ((cmds->size() > 1) && (cmds->at(cmds->size() - 1) == PathCommand::CubicTo)) { + if ((cmds->size() > 1) && (cmds->at(cmds->size() - 1) == PathCommand::CubicTo) && + !(*isQuadratic)) { ctrl.x = 2 * cur->x - curCtl->x; ctrl.y = 2 * cur->y - curCtl->y; } else { @@ -361,6 +363,7 @@ static void _processCommand(vector* cmds, vector* pts, char pts->push_back(p[2]); *curCtl = p[1]; *cur = p[2]; + *isQuadratic = false; break; } case 'q': @@ -377,16 +380,35 @@ static void _processCommand(vector* cmds, vector* pts, char pts->push_back(p[0]); pts->push_back(p[1]); pts->push_back(p[2]); - *curCtl = p[1]; + *curCtl = {arr[0], arr[1]}; *cur = p[2]; + *isQuadratic = true; 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]}; + Point p[3], ctrl; + if ((cmds->size() > 1) && (cmds->at(cmds->size() - 1) == PathCommand::CubicTo) && + *isQuadratic) { + ctrl.x = 2 * cur->x - curCtl->x; + ctrl.y = 2 * cur->y - curCtl->y; + } else { + ctrl = *cur; + } + float ctrl_x0 = (cur->x + 2 * ctrl.x) * (1.0 / 3.0); + float ctrl_y0 = (cur->y + 2 * ctrl.y) * (1.0 / 3.0); + float ctrl_x1 = (arr[0] + 2 * ctrl.x) * (1.0 / 3.0); + float ctrl_y1 = (arr[1] + 2 * ctrl.y) * (1.0 / 3.0); + cmds->push_back(PathCommand::CubicTo); + p[0] = {ctrl_x0, ctrl_y0}; + p[1] = {ctrl_x1, ctrl_y1}; + p[2] = {arr[0], arr[1]}; + pts->push_back(p[0]); + pts->push_back(p[1]); + pts->push_back(p[2]); + *curCtl = {ctrl.x, ctrl.y}; + *cur = p[2]; + *isQuadratic = true; break; } case 'h': @@ -479,6 +501,7 @@ tuple, vector> svgPathToTvgPath(const char* svgPath) Point cur = { 0, 0 }; Point curCtl = { 0, 0 }; char cmd = 0; + bool isQuadratic = false; char* path = (char*)svgPath; char* curLocale; @@ -489,7 +512,7 @@ tuple, vector> svgPathToTvgPath(const char* svgPath) while ((path[0] != '\0')) { path = _nextCommand(path, &cmd, numberArray, &numberCount); if (!path) break; - _processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl); + _processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &isQuadratic); } setlocale(LC_NUMERIC, curLocale); From 06cadc79f545d129a487b3b52a8092d866954d44 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 20 Aug 2020 17:52:11 +0900 Subject: [PATCH 242/244] updated AUTHORS Change-Id: Ie0bb862f8ba20e682bf3bb7469455fa52a5d5498 --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 1299d6b8..a600a625 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,3 +3,5 @@ Prudhvi Raj Vasireddi Junsu Choi Pranay Samanta Mateusz Palkowski +Subhransu Mohanty +Mira Grudzinska From 657e6daddb5dfe0aeeb694538f23a26857e0d6cf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 20 Aug 2020 17:04:32 +0900 Subject: [PATCH 243/244] common taskscheduler: revise functionalities. initialization interfaces has been changed for threads count. if you want to set concrete threads count by system, please specify thread count with it. std threads: tvg::Initializer::init(tvg::CanvasEngine::Sw, std::thread::hardware_concurrency()); if your system provides designed threads info, you can use it. efl: tvg_engine_init(TVG_ENGINE_SW, eina_cpu_count()); I recommend to avoid max threads usage for better performance. Change-Id: I22cfa315768f73fa941be136956cdbb2cf837c20 --- inc/thorvg.h | 4 +- inc/thorvg_capi.h | 2 +- src/bindings/capi/tvgCapi.cpp | 10 +- src/lib/meson.build | 3 +- src/lib/tvgCommon.h | 4 + src/lib/tvgInitializer.cpp | 21 +--- src/lib/tvgShapePath.h | 6 +- src/lib/tvgTask.cpp | 156 --------------------------- src/lib/tvgTask.h | 72 ------------- src/lib/tvgTaskScheduler.cpp | 189 +++++++++++++++++++++++++++++++++ src/lib/tvgTaskScheduler.h | 72 +++++++++++++ test/testArc.cpp | 5 +- test/testAsync.cpp | 5 +- test/testBlending.cpp | 5 +- test/testBoundary.cpp | 5 +- test/testCapi.c | 2 +- test/testCommon.h | 1 + test/testCustomTransform.cpp | 5 +- test/testDirectUpdate.cpp | 5 +- test/testGradientTransform.cpp | 39 +++---- test/testLinearGradient.cpp | 5 +- test/testMultiShapes.cpp | 5 +- test/testPath.cpp | 5 +- test/testPathCopy.cpp | 5 +- test/testRadialGradient.cpp | 5 +- test/testScene.cpp | 6 +- test/testSceneTransform.cpp | 5 +- test/testShape.cpp | 5 +- test/testStroke.cpp | 5 +- test/testStrokeLine.cpp | 6 +- test/testSvg.cpp | 5 +- test/testSvg2.cpp | 5 +- test/testTransform.cpp | 5 +- test/testUpdate.cpp | 5 +- 34 files changed, 387 insertions(+), 296 deletions(-) delete mode 100644 src/lib/tvgTask.cpp delete mode 100644 src/lib/tvgTask.h create mode 100644 src/lib/tvgTaskScheduler.cpp create mode 100644 src/lib/tvgTaskScheduler.h diff --git a/inc/thorvg.h b/inc/thorvg.h index 18013fa5..0de9bc02 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -366,10 +366,8 @@ public: * * @see ... */ - static Result init(CanvasEngine engine) noexcept; + static Result init(CanvasEngine engine, uint32_t threads) noexcept; static Result term(CanvasEngine engine) noexcept; - static Result threads(uint32_t cnt) noexcept; - static uint32_t threads() noexcept; _TVG_DISABLE_CTOR(Initializer); }; diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 811c82e3..afc294a5 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -88,7 +88,7 @@ typedef struct /************************************************************************/ /* Engine API */ /************************************************************************/ -TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method); +TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method, unsigned threads); TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method); diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index ac8cdcb1..01551969 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -50,13 +50,13 @@ struct _Tvg_Gradient /* Engine API */ /************************************************************************/ -TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method) { +TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method, unsigned threads) { Result ret = Result::Success; - if (engine_method & TVG_ENGINE_SW) ret = tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (engine_method & TVG_ENGINE_SW) ret = tvg::Initializer::init(tvg::CanvasEngine::Sw, threads); if (ret != Result::Success) return (Tvg_Result) ret; - if (engine_method & TVG_ENGINE_GL) ret = tvg::Initializer::init(tvg::CanvasEngine::Gl); + if (engine_method & TVG_ENGINE_GL) ret = tvg::Initializer::init(tvg::CanvasEngine::Gl, threads); return (Tvg_Result) ret; } @@ -64,10 +64,10 @@ TVG_EXPORT Tvg_Result tvg_engine_init(unsigned engine_method) { TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method) { Result ret = Result::Success; - if (engine_method & TVG_ENGINE_SW) ret = tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (engine_method & TVG_ENGINE_SW) ret = tvg::Initializer::term(tvg::CanvasEngine::Sw); if (ret != Result::Success) return (Tvg_Result) ret; - if (engine_method & TVG_ENGINE_GL) ret = tvg::Initializer::init(tvg::CanvasEngine::Gl); + if (engine_method & TVG_ENGINE_GL) ret = tvg::Initializer::term(tvg::CanvasEngine::Gl); return (Tvg_Result) ret; } diff --git a/src/lib/meson.build b/src/lib/meson.build index 503c35e9..bc0d9592 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -21,6 +21,7 @@ source_file = [ 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', + 'tvgTaskScheduler.h', 'tvgBezier.cpp', 'tvgCanvas.cpp', 'tvgFill.cpp', @@ -35,7 +36,7 @@ source_file = [ 'tvgScene.cpp', 'tvgShape.cpp', 'tvgSwCanvas.cpp', - 'tvgTask.cpp', + 'tvgTaskScheduler.cpp', ] common_dep = declare_dependency( diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 66e08bf5..c07a4cab 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -29,6 +29,9 @@ #include #include #include +#include +#include + #include "thorvg.h" using namespace std; @@ -46,5 +49,6 @@ using namespace tvg; #include "tvgLoaderMgr.h" #include "tvgRender.h" #include "tvgPaint.h" +#include "tvgTaskScheduler.h" #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index 2185c0f0..17b91a00 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -35,13 +35,12 @@ /* Internal Class Implementation */ /************************************************************************/ -static uint32_t threadCnt = 0; /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -Result Initializer::init(CanvasEngine engine) noexcept +Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept { auto nonSupport = true; @@ -63,6 +62,8 @@ Result Initializer::init(CanvasEngine engine) noexcept if (!LoaderMgr::init()) return Result::Unknown; + TaskScheduler::init(threads); + return Result::Success; } @@ -87,21 +88,9 @@ Result Initializer::term(CanvasEngine engine) noexcept if (nonSupport) return Result::NonSupport; + TaskScheduler::term(); + if (!LoaderMgr::term()) return Result::Unknown; return Result::Success; -} - - -Result Initializer::threads(uint32_t cnt) noexcept -{ - threadCnt = cnt; - - return Result::Success; -} - - -uint32_t Initializer::threads() noexcept -{ - return threadCnt; } \ No newline at end of file diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 04934dca..f3e0ae59 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -19,8 +19,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TVG_SHAPE_PATH_CPP_ -#define _TVG_SHAPE_PATH_CPP_ +#ifndef _TVG_SHAPE_PATH_H_ +#define _TVG_SHAPE_PATH_H_ #include "tvgCommon.h" @@ -139,4 +139,4 @@ struct ShapePath } }; -#endif //_TVG_SHAPE_PATH_CPP_ +#endif //_TVG_SHAPE_PATH_H_ diff --git a/src/lib/tvgTask.cpp b/src/lib/tvgTask.cpp deleted file mode 100644 index 81ce22e3..00000000 --- a/src/lib/tvgTask.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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. - * - */ - -#include - -#include - -template -class TaskQueue { - using lock_t = std::unique_lock; - std::deque _q; - bool _done{false}; - std::mutex _mutex; - std::condition_variable _ready; - -public: - bool try_pop(Task &task) - { - lock_t lock{_mutex, std::try_to_lock}; - if (!lock || _q.empty()) return false; - task = std::move(_q.front()); - _q.pop_front(); - return true; - } - - bool try_push(Task &&task) - { - { - lock_t lock{_mutex, std::try_to_lock}; - if (!lock) return false; - _q.push_back(std::move(task)); - } - _ready.notify_one(); - return true; - } - - void done() - { - { - lock_t lock{_mutex}; - _done = true; - } - _ready.notify_all(); - } - - bool pop(Task &task) - { - lock_t lock{_mutex}; - while (_q.empty() && !_done) _ready.wait(lock); - if (_q.empty()) return false; - task = std::move(_q.front()); - _q.pop_front(); - return true; - } - - void push(Task &&task) - { - { - lock_t lock{_mutex}; - _q.push_back(std::move(task)); - } - _ready.notify_one(); - } - -}; - -#include -#include - -namespace tvg -{ - -class Executor -{ - const unsigned _count{std::thread::hardware_concurrency()}; - std::vector _threads; - std::vector> _q{_count}; - std::atomic _index{0}; - void run(unsigned i) - { - // Task Loop - shared_task task; - while (true) { - bool success = false; - - for (unsigned n = 0; n != _count * 2; ++n) { - if (_q[(i + n) % _count].try_pop(task)) { - success = true; - break; - } - } - - if (!success && !_q[i].pop(task)) break; - - (*task)(); - } - } - - Executor() - { - for (unsigned n = 0; n != _count; ++n) { - _threads.emplace_back([&, n] { run(n); }); - } - } - ~Executor() - { - for (auto &e : _q) e.done(); - - for (auto &e : _threads) e.join(); - } - -public: - - static Executor& instance() { - static Executor singleton; - return singleton; - } - - void post(shared_task task) - { - task->prepare(); - - auto i = _index++; - - for (unsigned n = 0; n != _count; ++n) { - if (_q[(i + n) % _count].try_push(std::move(task))) return; - } - - if (_count > 0) { - _q[i % _count].push(std::move(task)); - } - } -}; - -void async(shared_task task) -{ - Executor::instance().post(std::move(task)); -} - -} - - diff --git a/src/lib/tvgTask.h b/src/lib/tvgTask.h deleted file mode 100644 index 9fb250ed..00000000 --- a/src/lib/tvgTask.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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_TASK_H_ -#define _TVG_TASK_H_ - -#include -#include - -namespace tvg -{ - -/* - Task Interface. - Able to run a task in the thread pool. derive from the - task interface and implement run method. - - To get the result call task->get() which will return immidiately if the - task is already finishd otherwise will wait till task completion. - */ - -class Task -{ -public: - virtual ~Task() = default; - void get() { if (_receiver.valid()) _receiver.get(); } - -protected: - virtual void run() = 0; -private: - void operator()() - { - run(); - _sender.set_value(); - } - void prepare() - { - _sender = std::promise(); - _receiver = _sender.get_future(); - } - friend class Executor; - - std::promise _sender; - std::future _receiver; -}; - - -using shared_task = std::shared_ptr; - -/* - async() function takes a shared task and runs it in - a thread pool asyncronously. call get() on the shared_task - to get the ressult out of the shared_task. - */ -void async(shared_task task); - -} - -#endif //_TVG_TASK_H_ \ No newline at end of file diff --git a/src/lib/tvgTaskScheduler.cpp b/src/lib/tvgTaskScheduler.cpp new file mode 100644 index 00000000..31b1e849 --- /dev/null +++ b/src/lib/tvgTaskScheduler.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +namespace tvg { + +struct TaskQueue { + deque> taskDeque; + mutex mtx; + condition_variable ready; + bool done = false; + + bool tryPop(shared_ptr &task) + { + unique_lock lock{mtx, try_to_lock}; + if (!lock || taskDeque.empty()) return false; + task = move(taskDeque.front()); + taskDeque.pop_front(); + + return true; + } + + bool tryPush(shared_ptr &&task) + { + { + unique_lock lock{mtx, try_to_lock}; + if (!lock) return false; + taskDeque.push_back(move(task)); + } + + ready.notify_one(); + + return true; + } + + void complete() + { + { + unique_lock lock{mtx}; + done = true; + } + ready.notify_all(); + } + + bool pop(shared_ptr &task) + { + unique_lock lock{mtx}; + + while (taskDeque.empty() && !done) { + ready.wait(lock); + } + + if (taskDeque.empty()) return false; + + task = move(taskDeque.front()); + taskDeque.pop_front(); + + return true; + } + + void push(shared_ptr &&task) + { + { + unique_lock lock{mtx}; + taskDeque.push_back(move(task)); + } + + ready.notify_one(); + } + +}; + + +class TaskSchedulerImpl +{ +public: + unsigned threadCnt; + vector threads; + vector taskQueues{threadCnt}; + atomic idx{0}; + + TaskSchedulerImpl() + { + for (unsigned i = 0; i < threadCnt; ++i) { + threads.emplace_back([&, i] { run(i); }); + } + } + + ~TaskSchedulerImpl() + { + for (auto& queue : taskQueues) queue.complete(); + for (auto& thread : threads) thread.join(); + } + + void run(unsigned i) + { + shared_ptr task; + + //Thread Loop + while (true) { + auto success = false; + + for (unsigned i = 0; i < threadCnt * 2; ++i) { + if (taskQueues[(i + i) % threadCnt].tryPop(task)) { + success = true; + break; + } + } + + if (!success && !taskQueues[i].pop(task)) break; + + (*task)(); + } + } + + void request(shared_ptr task) + { + //Async + if (threadCnt > 0) { + task->prepare(); + auto i = idx++; + for (unsigned n = 0; n < threadCnt; ++n) { + if (taskQueues[(i + n) % threadCnt].tryPush(move(task))) return; + } + + taskQueues[i % threadCnt].push(move(task)); + + //Sync + } else { + task->run(); + } + } +}; + +} + +static TaskSchedulerImpl* inst = nullptr; + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +void TaskScheduler::init(unsigned threads) +{ + if (inst) return; + inst = new TaskSchedulerImpl; + inst->threadCnt = threads; +} + + +void TaskScheduler::term() +{ + if (!inst) return; + delete(inst); + inst = nullptr; +} + + +void TaskScheduler::request(shared_ptr task) +{ + if (inst) { + inst->request(move(task)); + } +} \ No newline at end of file diff --git a/src/lib/tvgTaskScheduler.h b/src/lib/tvgTaskScheduler.h new file mode 100644 index 00000000..4380a9ca --- /dev/null +++ b/src/lib/tvgTaskScheduler.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _TVG_TASK_SCHEDULER_H_ +#define _TVG_TASK_SCHEDULER_H_ + +#include "tvgCommon.h" + +namespace tvg +{ + +struct Task +{ +private: + std::promise sender; + std::future receiver; + +public: + virtual ~Task() = default; + + void get() + { + if (receiver.valid()) receiver.get(); + } + +protected: + virtual void run() = 0; + +private: + void operator()() + { + run(); + sender.set_value(); + } + + void prepare() + { + sender = std::promise(); + receiver = sender.get_future(); + } + + friend class TaskSchedulerImpl; +}; + +struct TaskScheduler +{ + static void init(unsigned threads); + static void term(); + static void request(shared_ptr task); +}; + +} + +#endif //_TVG_TASK_SCHEDULER_H_ \ No newline at end of file diff --git a/test/testArc.cpp b/test/testArc.cpp index 1f158122..9c307d44 100644 --- a/test/testArc.cpp +++ b/test/testArc.cpp @@ -148,8 +148,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 608cefb2..25e57ba6 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -151,8 +151,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 743b1e09..68623dc3 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -131,8 +131,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 38306877..e2ed1c08 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -120,8 +120,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testCapi.c b/test/testCapi.c index c6df3968..1b0018d5 100644 --- a/test/testCapi.c +++ b/test/testCapi.c @@ -13,7 +13,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void testCapi() { - tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL); + tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL, 0); Tvg_Canvas* canvas = tvg_swcanvas_create(); tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT, TVG_COLORSPACE_ARGB8888); diff --git a/test/testCommon.h b/test/testCommon.h index 13ac86ab..a5f222ef 100644 --- a/test/testCommon.h +++ b/test/testCommon.h @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 9daa6fc1..50033f9d 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -176,8 +176,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 8dcc474a..69105c32 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -139,8 +139,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 77d5f6af..45431e3f 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -204,31 +204,34 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { - elm_init(argc, argv); + elm_init(argc, argv); - Elm_Transit *transit = elm_transit_add(); + Elm_Transit *transit = elm_transit_add(); - 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); - } + 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_duration_set(transit, 2); - elm_transit_repeat_times_set(transit, -1); - elm_transit_auto_reverse_set(transit, EINA_TRUE); - elm_transit_go(transit); + 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(); + elm_run(); + elm_shutdown(); - //Terminate ThorVG Engine - tvg::Initializer::term(tvgEngine); + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index db11682a..d1ed5fa7 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -149,8 +149,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 12009bc2..3db41b9d 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -109,8 +109,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testPath.cpp b/test/testPath.cpp index de6ef60e..a265d03c 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -126,8 +126,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index fb1080b3..b5d97cfc 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -163,8 +163,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index 6e772915..a64e47b5 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -149,8 +149,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testScene.cpp b/test/testScene.cpp index daa5d868..8c464282 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -156,8 +156,12 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { + elm_init(argc, argv); diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index e64fa9aa..ef6c1578 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -200,8 +200,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testShape.cpp b/test/testShape.cpp index af4d0c47..56acfd5c 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -99,8 +99,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 778d7c7b..5ac22659 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -146,8 +146,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 1205bb14..8cc16d0f 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -183,8 +183,12 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { + elm_init(argc, argv); diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 06fe3501..ad720271 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -141,8 +141,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp index 2300f217..c859b042 100644 --- a/test/testSvg2.cpp +++ b/test/testSvg2.cpp @@ -124,8 +124,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 5ef33f44..6cd9be67 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -167,8 +167,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 3ff6c246..6df8533b 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -128,8 +128,11 @@ int main(int argc, char **argv) cout << "tvg engine: opengl" << endl; } + //Threads Count + auto threads = std::thread::hardware_concurrency(); + //Initialize ThorVG Engine - if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) { + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { elm_init(argc, argv); From 8efef7714c17dc615b1dc13537b9c423ac6b9ec0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 21 Aug 2020 15:56:04 +0900 Subject: [PATCH 244/244] common initializer: don't try initialize engine duplicatedly. Change-Id: I58c715745b8db40fe759582545082f2e6e10626a --- inc/thorvg.h | 2 +- src/lib/tvgInitializer.cpp | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 0de9bc02..16252fe9 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -56,7 +56,7 @@ enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; -enum class TVG_EXPORT CanvasEngine { Sw = 0, Gl }; +enum class TVG_EXPORT CanvasEngine { Sw = (1 << 1), Gl = (1 << 2)}; struct Point diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index 17b91a00..7dcc8b91 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -34,7 +34,7 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ - +static bool initialized = false; /************************************************************************/ /* External Class Implementation */ @@ -42,14 +42,16 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept { + if (initialized) return Result::InsufficientCondition; + auto nonSupport = true; - if (engine == CanvasEngine::Sw) { + if (static_cast(engine) & static_cast(CanvasEngine::Sw)) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::init()) return Result::InsufficientCondition; nonSupport = false; #endif - } else if (engine == CanvasEngine::Gl) { + } else if (static_cast(engine) & static_cast(CanvasEngine::Gl)) { #ifdef THORVG_GL_RASTER_SUPPORT if (!GlRenderer::init()) return Result::InsufficientCondition; nonSupport = false; @@ -64,20 +66,24 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept TaskScheduler::init(threads); + initialized = true; + return Result::Success; } Result Initializer::term(CanvasEngine engine) noexcept { + if (!initialized) return Result::InsufficientCondition; + auto nonSupport = true; - if (engine == CanvasEngine::Sw) { + if (static_cast(engine) & static_cast(CanvasEngine::Sw)) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::term()) return Result::InsufficientCondition; nonSupport = false; #endif - } else if (engine == CanvasEngine::Gl) { + } else if (static_cast(engine) & static_cast(CanvasEngine::Gl)) { #ifdef THORVG_GL_RASTER_SUPPORT if (!GlRenderer::term()) return Result::InsufficientCondition; nonSupport = false; @@ -92,5 +98,7 @@ Result Initializer::term(CanvasEngine engine) noexcept if (!LoaderMgr::term()) return Result::Unknown; + initialized = false; + return Result::Success; } \ No newline at end of file