common: Introduced Accessor for traversing the scene-tree. 65/288765/1
authorHermet Park <chuneon.park@samsung.com>
Thu, 23 Dec 2021 02:34:31 +0000 (11:34 +0900)
committerMichal Szczecinski <m.szczecinsk@partner.samsung.com>
Wed, 22 Feb 2023 11:30:22 +0000 (12:30 +0100)
Basically, this Accessor is a utility to debug the Scene structure,
by traversing the scene-tree by users.

You can search specific nodes to read the property information,
figure out the structure of the scene tree and its size.

We actually don't recommend you to touch the property unless you really
know the each paint's position and role because it's not visible, difficult to
understand its anatomy.

Also, You must underatnd that modifying the nodes of the scene will be going
well with both the art-design structure and the prorgram logic.

In this first version, Accessor only supports for the Picture class.

@example:

auto picture = tvg::Picture::gen();
picture->load("test.svg");

//The callback function from lambda expression.
//This function will be called for every paint nodes of the tree.
auto f = [](const tvg::Paint* paint) -> bool
{
    if (paint->identifier() == Shape::identifier()) {
        //override properties?
        uint8_t r, g, b, a;
        paint->fillColor(&r, &g, &b, &a);
        paint->fill(r / 2, g / 2, b / 2, a);
    }

    //You can return false, to stop traversing immediately.
    return true;
};

auto accessor = tvg::Accessor::gen();

picture = accessor->access(move(picture), f);

...

@Issue: https://github.com/Samsung/thorvg/issues/693

Change-Id: I4f46754de46dfab9bb5b14f58cc659237344822a

inc/thorvg.h
src/examples/Accessor.cpp [new file with mode: 0644]
src/examples/meson.build
src/lib/meson.build
src/lib/tvgAccessor.cpp [new file with mode: 0644]

index 49e112def54267cae27b1ff70bf5341502c60d83..e542d36555c72091184a989050617b99f6827e9a 100644 (file)
@@ -50,6 +50,7 @@ protected: \
     friend Canvas; \
     friend Scene; \
     friend Picture; \
+    friend Accessor; \
     friend IteratorAccessor
 
 
@@ -61,6 +62,7 @@ class IteratorAccessor;
 class Scene;
 class Picture;
 class Canvas;
+class Accessor;
 
 /**
  * @defgroup ThorVG ThorVG
@@ -1533,6 +1535,49 @@ public:
     _TVG_DECLARE_PRIVATE(Saver);
 };
 
+
+/**
+ * @class Accessor
+ *
+ * @brief The Accessor is a utility class to debug the Scene structure by traversing the scene-tree.
+ *
+ * The Accessor helps you search specific nodes to read the property information, figure out the structure of the scene tree and its size.
+ *
+ * @warning We strongly warn you not to change the paints of a scene unless you really know the design-structure.
+ *
+ * @BETA_API
+ */
+class TVG_EXPORT Accessor final
+{
+public:
+    ~Accessor();
+
+    /**
+     * @brief Access the Picture scene stree nodes.
+     *
+     * @param[in] picture The picture node to traverse the internal scene-tree.
+     * @param[in] func The callback function calling for every paint nodes of the Picture.
+     *
+     * @return Return the given @p picture instance.
+     *
+     * @note The bitmap based picture might not have the scene-tree.
+     *
+     * @BETA_API
+     */
+    std::unique_ptr<Picture> access(std::unique_ptr<Picture> picture, bool(*func)(const Paint* paint)) noexcept;
+
+    /**
+     * @brief Creates a new Accessor object.
+     *
+     * @return A new Accessor object.
+     *
+     * @BETA_API
+     */
+    static std::unique_ptr<Accessor> gen() noexcept;
+
+    _TVG_DECLARE_PRIVATE(Accessor);
+};
+
 /** @}*/
 
 } //namespace
diff --git a/src/examples/Accessor.cpp b/src/examples/Accessor.cpp
new file mode 100644 (file)
index 0000000..975f04f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "Common.h"
+
+/************************************************************************/
+/* Drawing Commands                                                     */
+/************************************************************************/
+
+
+void tvgDrawCmds(tvg::Canvas* canvas)
+{
+    if (!canvas) return;
+
+    //load the tvg file
+    auto picture = tvg::Picture::gen();
+    if (picture->load(EXAMPLE_DIR"/favorite_on.svg") != tvg::Result::Success) return;
+    picture->size(WIDTH, HEIGHT);
+
+    auto accessor = tvg::Accessor::gen();
+
+    //The callback function from lambda expression.
+    //This function will be called for every paint nodes of the picture tree.
+    auto f = [](const tvg::Paint* paint) -> bool
+    {
+        if (paint->identifier() == tvg::Shape::identifier()) {
+            auto shape = (tvg::Shape*) paint;
+            //override color?
+            uint8_t r, g, b, a;
+            shape->fillColor(&r, &g, &b, &a);
+            if (r == 255 && g == 180 && b == 0)
+                shape->fill(0, 0, 255, a);
+        }
+
+        //You can return false, to stop traversing immediately.
+        return true;
+    };
+
+    picture = accessor->access(move(picture), f);
+
+    canvas->push(move(picture));
+}
+
+
+/************************************************************************/
+/* Sw Engine Test Code                                                  */
+/************************************************************************/
+
+static unique_ptr<tvg::SwCanvas> swCanvas;
+
+void tvgSwTest(uint32_t* buffer)
+{
+    //Create a Canvas
+    swCanvas = tvg::SwCanvas::gen();
+    swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
+
+    /* Push the shape into the Canvas drawing list
+       When this shape is into the canvas list, the shape could update & prepare
+       internal data asynchronously for coming rendering.
+       Canvas keeps this shape node unless user call canvas->clear() */
+    tvgDrawCmds(swCanvas.get());
+}
+
+void drawSwView(void* data, Eo* obj)
+{
+    if (swCanvas->draw() == tvg::Result::Success) {
+        swCanvas->sync();
+    }
+}
+
+
+/************************************************************************/
+/* GL Engine Test Code                                                  */
+/************************************************************************/
+
+static unique_ptr<tvg::GlCanvas> glCanvas;
+
+void initGLview(Evas_Object *obj)
+{
+    static constexpr auto BPP = 4;
+
+    //Create a Canvas
+    glCanvas = tvg::GlCanvas::gen();
+    glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT);
+
+    /* Push the shape into the Canvas drawing list
+       When this shape is into the canvas list, the shape could update & prepare
+       internal data asynchronously for coming rendering.
+       Canvas keeps this shape node unless user call canvas->clear() */
+    tvgDrawCmds(glCanvas.get());
+}
+
+void drawGLview(Evas_Object *obj)
+{
+    auto gl = elm_glview_gl_api_get(obj);
+    gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+    gl->glClear(GL_COLOR_BUFFER_BIT);
+
+    if (glCanvas->draw() == tvg::Result::Success) {
+        glCanvas->sync();
+    }
+}
+
+
+/************************************************************************/
+/* Main Code                                                            */
+/************************************************************************/
+
+int main(int argc, char **argv)
+{
+    tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
+
+    if (argc > 1) {
+        if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl;
+    }
+
+    //Initialize ThorVG Engine
+    if (tvgEngine == tvg::CanvasEngine::Sw) {
+        cout << "tvg engine: software" << endl;
+    } else {
+        cout << "tvg engine: opengl" << endl;
+    }
+
+    //Threads Count
+    auto threads = std::thread::hardware_concurrency();
+
+    //Initialize ThorVG Engine
+    if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) {
+
+        elm_init(argc, argv);
+
+        if (tvgEngine == tvg::CanvasEngine::Sw) {
+            createSwView();
+        } else {
+            createGlView();
+        }
+
+        elm_run();
+        elm_shutdown();
+
+        //Terminate ThorVG Engine
+        tvg::Initializer::term(tvgEngine);
+
+    } else {
+        cout << "engine is not supported" << endl;
+    }
+    return 0;
+}
\ No newline at end of file
index 0d533484b45c1b324af3016c4273297afca87adb..31331c8f579f78f66f0ef715a142e0d29df1244e 100644 (file)
@@ -1,6 +1,7 @@
 examples_dep = dependency('elementary', required : true)
 
 source_file = [
+    'Accessor.cpp',
     'AnimateMasking.cpp',
     'Arc.cpp',
     'Async.cpp',
index 9c317003539e7766e11b3159d2105ff17734db1f..f28760d29bf329dadfc65b205fb77cd89266f5d9 100644 (file)
@@ -25,6 +25,7 @@ source_file = [
    'tvgSceneImpl.h',
    'tvgShapeImpl.h',
    'tvgTaskScheduler.h',
+   'tvgAccessor.cpp',
    'tvgBezier.cpp',
    'tvgCanvas.cpp',
    'tvgFill.cpp',
diff --git a/src/lib/tvgAccessor.cpp b/src/lib/tvgAccessor.cpp
new file mode 100644 (file)
index 0000000..085c8a3
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "tvgIteratorAccessor.h"
+
+/************************************************************************/
+/* Internal Class Implementation                                        */
+/************************************************************************/
+
+static bool accessChildren(Iterator* it, bool(*func)(const Paint* paint), IteratorAccessor& itrAccessor)
+{
+    while (auto child = it->next()) {
+        //Access the child
+        if (!func(child)) return false;
+
+        //Access the children of the child
+        if (auto it2 = itrAccessor.iterator(child)) {
+            if (!accessChildren(it2, func, itrAccessor)) {
+                delete(it2);
+                return false;
+            }
+            delete(it2);
+        }
+    }
+    return true;
+}
+
+
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+unique_ptr<Picture> Accessor::access(unique_ptr<Picture> picture, bool(*func)(const Paint* paint)) noexcept
+{
+    auto p = picture.get();
+    if (!p || !func) return picture;
+
+    //Use the Preorder Tree-Search
+
+    //Root
+    if (!func(p)) return picture;
+
+    //Children
+    IteratorAccessor itrAccessor;
+    if (auto it = itrAccessor.iterator(p)) {
+        accessChildren(it, func, itrAccessor);
+        delete(it);
+    }
+    return picture;
+}
+
+
+Accessor::~Accessor()
+{
+
+}
+
+
+Accessor::Accessor()
+{
+
+}
+
+
+unique_ptr<Accessor> Accessor::gen() noexcept
+{
+    return unique_ptr<Accessor>(new Accessor);
+}
\ No newline at end of file