evas vector: Added tvg_scene to container implementation. 32/248032/3 accepted/tizen/unified/20201208.123228 submit/tizen/20201206.210050
authorMichal Szczecinski <m.szczecinsk@partner.samsung.com>
Thu, 19 Nov 2020 13:55:16 +0000 (14:55 +0100)
committerMichal Szczecinski <m.szczecinsk@partner.samsung.com>
Fri, 27 Nov 2020 10:00:35 +0000 (11:00 +0100)
Introduce Tvg Scene as a container implementation. It delegates layer
transparency calculation to thorvg lib which make efl code more
readable. This commit fixed also resources release issue. Now there is
no segfault with thorvg flag on elm-demo-tizen-mobile app. Also
rendering isses with elm_widgets (themed by vector edc) was fixed.

Change-Id: Ib2a3de71728e4c492fc2b20004359b71133f703c

src/lib/evas/canvas/efl_canvas_vg_container.c
src/lib/evas/canvas/efl_canvas_vg_container.eo
src/lib/evas/canvas/efl_canvas_vg_object.c
src/lib/evas/canvas/efl_canvas_vg_shape.c
src/lib/evas/canvas/evas_vg_private.h

index c4d2c55..1004ea1 100644 (file)
@@ -47,6 +47,47 @@ _draw_comp(Evas_Object_Protected_Data *obj, Efl_VG *node,
         ENFN->ector_renderer_draw(engine, output, context, nd->renderer, NULL, EINA_FALSE);
      }
 }
+#else
+static void
+_efl_canvas_vg_container_render_pre_tvg(Evas_Object_Protected_Data *obj,
+                                    Efl_VG *node,
+                                    Efl_Canvas_Vg_Node_Data *nd,
+                                    Eina_Matrix3 *pTransform,
+                                    void *canvas, void *scene, int w, int h)
+{
+   Efl_Canvas_Vg_Container_Data *cd = NULL;
+   Efl_VG *child = NULL;
+   Eina_List *l = NULL;
+
+   if (!nd || !nd->data) return;
+   cd = nd->data;
+
+   if (scene != NULL)
+     {
+        if (eina_hash_find(cd->targets, &scene) == NULL)
+          {
+             tvg_scene_push(scene, cd->scene);
+             eina_hash_add(cd->targets, &scene, scene);
+          }
+     }
+   else if (scene == NULL && canvas != NULL)
+     {
+        if (eina_hash_find(cd->targets, &canvas) == NULL)
+          {
+             tvg_canvas_push(canvas, cd->scene);
+             eina_hash_add(cd->targets, &canvas, canvas);
+          }
+     }
+
+   EFL_CANVAS_VG_COMPUTE_MATRIX(cTransform, pTransform, nd);
+
+   EINA_LIST_FOREACH(cd->children, l, child)
+     {
+        Efl_Canvas_Vg_Node_Data *cnd = efl_data_scope_get(child, EFL_CANVAS_VG_NODE_CLASS);
+        if (cnd && cnd->render_pre_tvg)
+          cnd->render_pre_tvg(obj, child, cnd, cTransform, canvas, cd->scene, w, h);
+     }
+}
 #endif
 
 static Ector_Buffer *
@@ -257,6 +298,13 @@ _efl_canvas_vg_container_efl_object_constructor(Eo *obj,
    nd->flags = EFL_GFX_CHANGE_FLAG_ALL;
 
    efl_gfx_color_set(obj, 255, 255, 255, 255);
+
+#ifdef HAVE_THORVG
+   pd->scene = tvg_scene_new();
+   pd->targets = eina_hash_pointer_new(NULL);
+   nd->render_pre_tvg = _efl_canvas_vg_container_render_pre_tvg;
+#endif
+
    return obj;
 }
 
@@ -266,7 +314,7 @@ _efl_canvas_vg_container_efl_object_destructor(Eo *obj,
 {
    efl_canvas_vg_container_blend_buffer_clear(obj, pd);
 
-#ifdef HAVE_THORVG
+#ifndef HAVE_THORVG
    //Destroy comp surface
    if (pd->comp.buffer)
      {
@@ -274,6 +322,10 @@ _efl_canvas_vg_container_efl_object_destructor(Eo *obj,
           ector_buffer_unmap(pd->comp.buffer, pd->comp.pixels, pd->comp.length);
         efl_unref(pd->comp.buffer);
      }
+#else
+   tvg_scene_clear(pd->scene);
+   tvg_paint_del(pd->scene);
+   eina_hash_free(pd->targets);
 #endif
 
    efl_unref(pd->comp_target);
@@ -341,6 +393,43 @@ _efl_canvas_vg_container_efl_gfx_path_bounds_get(const Eo *obj EINA_UNUSED,
      }
 }
 
+static void
+_efl_canvas_vg_container_efl_gfx_color_color_set(Eo *obj EINA_UNUSED,
+#ifdef HAVE_THORVG
+                                                 Efl_Canvas_Vg_Container_Data *pd,
+#else
+                                                 Efl_Canvas_Vg_Container_Data *pd EINA_UNUSED,
+#endif
+                                                 int r EINA_UNUSED,
+                                                 int g EINA_UNUSED,
+                                                 int b EINA_UNUSED,
+                                                 int a)
+{
+#ifdef HAVE_THORVG
+   if (pd && pd->scene)
+     tvg_paint_set_opacity(pd->scene, a);
+   efl_canvas_vg_node_change(obj);
+#endif
+}
+
+static void
+_efl_canvas_vg_container_efl_gfx_color_color_get(const Eo *obj EINA_UNUSED,
+#ifdef HAVE_THORVG
+                                                 Efl_Canvas_Vg_Container_Data *pd,
+#else
+                                                 Efl_Canvas_Vg_Container_Data *pd EINA_UNUSED,
+#endif
+                                                 int* r EINA_UNUSED,
+                                                 int* g EINA_UNUSED,
+                                                 int* b EINA_UNUSED,
+                                                 int* a)
+{
+#ifdef HAVE_THORVG
+   if (pd && pd->scene)
+     tvg_paint_get_opacity(pd->scene, (uint8_t*)a);
+#endif
+}
+
 static Efl_VG *
 _efl_canvas_vg_container_child_get(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Container_Data *pd, const char *name)
 {
index 6865ecd..1133e82 100644 (file)
@@ -24,6 +24,7 @@ class @beta Efl.Canvas.Vg.Container extends Efl.Canvas.Vg.Node
       Efl.Object.parent { set; }
       Efl.Gfx.Path.bounds_get;
       Efl.Gfx.Path.interpolate;
+      Efl.Gfx.Color.color { get; set; }
       Efl.Duplicate.duplicate;
       Efl.Canvas.Vg.Node.comp_method { set; }
    }
index 2897ac4..b0783f4 100644 (file)
@@ -390,8 +390,8 @@ _efl_canvas_vg_object_efl_object_invalidate(Eo *eo_obj, Efl_Canvas_Vg_Object_Dat
 
    if (pd->tvg_canvas)
      {
+        tvg_canvas_clear(pd->tvg_canvas, false);
         tvg_canvas_destroy(pd->tvg_canvas);
-        pd->tvg_canvas = NULL;
      }
 #endif
    efl_invalidate(efl_super(eo_obj, MY_CLASS));
@@ -415,6 +415,13 @@ _efl_canvas_vg_object_efl_object_constructor(Eo *eo_obj, Efl_Canvas_Vg_Object_Da
    pd->root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
    pd->sync_render = EINA_FALSE;
 
+#ifdef HAVE_THORVG
+   pd->tvg_canvas = tvg_swcanvas_create();
+   pd->tvg_canvas_size.w = 0;
+   pd->tvg_canvas_size.h = 0;
+#endif
+
+   pd->sync_render = EINA_FALSE;
    eina_array_step_set(&pd->cleanup, sizeof(pd->cleanup), 8);
    return eo_obj;
 }
@@ -439,33 +446,17 @@ _efl_canvas_vg_object_efl_object_finalize(Eo *obj, Efl_Canvas_Vg_Object_Data *pd
 
 #ifdef HAVE_THORVG
 static void
-_evas_vg_render_tvg(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
-                    void *engine, void *output, void *context, Efl_VG *node,
-                    Eina_Array *clips, int w, int h, void *canvas, Eina_Bool do_async)
-{
-   Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(node, EFL_CANVAS_VG_NODE_CLASS);
-
-   if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS)) {
-        Efl_VG *child = NULL;
-        Eina_List *l = NULL;
-
-        Efl_Canvas_Vg_Container_Data *cd = efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
-
-        // Draw child node to changed buffer
-        EINA_LIST_FOREACH(cd->children, l, child)
-              _evas_vg_render_tvg(obj, pd, engine, output, context, child, clips, w, h, canvas, do_async);
-
-   } else {
-      if (!efl_isa(node, EFL_CANVAS_VG_GRADIENT_CLASS))
-         nd->render_pre_tvg(obj, node, nd, canvas);
-   }
-}
-
-static void
 _render_to_buffer_tvg(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
-                      void *engine, Efl_VG *root, int w, int h, Eina_Bool do_async)
+                      Efl_VG *root, int w, int h)
 {
-   _evas_vg_render_tvg(obj, pd, engine, NULL, NULL, root, NULL, w, h, pd->tvg_canvas, do_async);
+   if (!efl_isa(root, EFL_CANVAS_VG_GRADIENT_CLASS))
+     {
+        Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(root, EFL_CANVAS_VG_NODE_CLASS);
+        if (nd && nd->render_pre_tvg && pd)
+          nd->render_pre_tvg(obj, root, nd, NULL, pd->tvg_canvas, NULL, w, h);
+     }
+
+   tvg_canvas_update(pd->tvg_canvas);
 
    if (tvg_canvas_draw(pd->tvg_canvas) == TVG_RESULT_SUCCESS)
      {
@@ -483,7 +474,7 @@ _render_tvg_buffer_to_screen(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Obje
    if (!pd->im)
      {
         pd->im = ENFN->image_new_from_data(engine, w, h, buffer, 255,
-                                       EVAS_COLORSPACE_ARGB8888);
+                                           EVAS_COLORSPACE_ARGB8888);
      }
    else
      {
@@ -893,11 +884,8 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
 #ifdef HAVE_THORVG
    Efl_Canvas_Vg_Node_Data *nd = NULL;
    Eina_Size2D size;
-   Eina_Rect render_rect;
-
-   int w = 0, h = 0;
 
-   if (!pd || !pd->root || !pd->user_entry) return;
+   if (!pd || !pd->root) return;
    if (!obj || !obj->cur) return;
 
    nd = efl_data_scope_get(pd->root, EFL_CANVAS_VG_NODE_CLASS);
@@ -914,8 +902,6 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
         pd->tvg_canvas_size.w = size.w;
         pd->tvg_canvas_size.h = size.h;
 
-        if (!pd->tvg_canvas) pd->tvg_canvas = tvg_swcanvas_create();
-
         tvg_swcanvas_set_target(pd->tvg_canvas, pd->tvg_buffer,
                                 size.w, size.w, size.h,
                                 TVG_COLORSPACE_ARGB8888);
@@ -926,35 +912,30 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
              ENFN->image_free(engine, pd->im);
              pd->im = NULL;
           }
-     }
 
-   _render_to_buffer_tvg(obj, pd, NULL,
-                         pd->user_entry->root,
-                         obj->cur->geometry.w,
-                         obj->cur->geometry.h,
-                         do_async);
+        pd->changed = EINA_TRUE;
+     }
 
-   render_rect = EINA_RECT(x, y, size.w, size.h);
+   if (pd->vg_entry)
+     {
+        Efl_VG *root = evas_cache_vg_tree_get(pd->vg_entry, pd->frame_idx);
+        if (!root) return;
 
-   if (nd && nd->render_tvg)
-      nd->render_tvg(obj, pd->root, nd, pd->tvg_canvas);
+        _render_to_buffer_tvg(obj, pd, root,
+                              pd->vg_entry->w,
+                              pd->vg_entry->h);
+     }
 
-   if (pd->viewbox.w != 0 && pd->viewbox.h !=0)
+   if (pd->user_entry && pd->user_entry->root)
      {
-        double sx = 0, sy= 0;
-        sx = (double)w / (double)pd->viewbox.w;
-        sy = (double)h / (double)pd->viewbox.h;
-        render_rect.x = (render_rect.x - pd->viewbox.x) * sx;
-        render_rect.y = (render_rect.y - pd->viewbox.y) * sy;
-        render_rect.w *= sx;
-        render_rect.h *= sy;
+        _render_to_buffer_tvg(obj, pd, pd->user_entry->root,
+                              obj->cur->geometry.w,
+                              obj->cur->geometry.h);
      }
 
    _render_tvg_buffer_to_screen(obj, pd, engine, output, context, surface,
-                                pd->tvg_buffer, x + render_rect.x,
-                                y + render_rect.y,
-                                render_rect.w, render_rect.h,
-                                do_async);
+                                pd->tvg_buffer, obj->cur->geometry.x + x,
+                                obj->cur->geometry.y + y, size.w, size.h, do_async);
 #else
    //Cache surface?
    Eina_Bool cacheable = EINA_FALSE;
@@ -974,6 +955,7 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
                                obj->cur->geometry.x + x, obj->cur->geometry.y + y,
                                obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
      }
+
    if (pd->user_entry)
      {
         _user_vg_entry_render(obj, pd,
index 5dbcb8c..0876f1d 100644 (file)
@@ -55,10 +55,9 @@ struct _Efl_Canvas_Vg_Shape_Data
    //scaling using scale * width
    double scale;
 
-   //Flag indicates if shape was pushed to canvas. Shape has access to canvas only in
-   //render function which may be called multiple times, and shape should be pushed
-   //only once.
-   Eina_Bool pushed;
+   //hash array indicates where shape was added. It have to be used to don't double
+   //the same objects stored in one canvas or scene.
+   Eina_Hash *targets;
 
    //Flag indicates if shape was started. It is used to store start position
    //and keep shape current point valid when shape close API is called.
@@ -576,7 +575,6 @@ _shape_interpolate(Evas_Vg_Shape *obj,
 
    _shape_properties_interpolate(obj, from, to, pos_map);
    tvg_shape_append_path(tvg_dest, path_commands_from, cmds_count_from, path_coords_dest, pts_count_from);
-
    return EINA_TRUE;
 }
 #endif
@@ -726,21 +724,36 @@ _convert_eina_to_tvg_mat(const Eina_Matrix3 *eina_mat, Tvg_Matrix *tvg_mat)
 }
 
 static void
-_efl_canvas_vg_shape_render_pre_tvg(EINA_UNUSED Evas_Object_Protected_Data *vg_pd,
+_efl_canvas_vg_shape_render_pre_tvg(Evas_Object_Protected_Data *vg_pd,
                                     Efl_VG *obj,
                                     Efl_Canvas_Vg_Node_Data *nd,
-                                    void *canvas)
+                                    Eina_Matrix3 *pTransform,
+                                    void *canvas, void *scene, int w, int h)
 {
    Efl_Canvas_Vg_Shape_Data *sd = NULL;
 
    Tvg_Matrix trans_mat = { 0 };
-   const Eina_Matrix3 *m = NULL;
 
    int r = 0, g = 0, b = 0, a = 0;
 
-   if (!nd || !nd->data)  return;
+   double scale_x = 1.0;
+   double scale_y = 1.0;
+
+   if (!nd || !nd->data || w == 0 || h == 0)  return;
    sd = nd->data;
 
+   EFL_CANVAS_VG_COMPUTE_MATRIX(cTransform, pTransform, nd);
+
+   if (vg_pd && vg_pd->cur)
+     {
+        if (w != vg_pd->cur->geometry.w || h != vg_pd->cur->geometry.h)
+          {
+             scale_x = vg_pd->cur->geometry.w / (double) w;
+             scale_y = vg_pd->cur->geometry.h / (double) h;
+             eina_matrix3_scale(cTransform, scale_x, scale_y);
+          }
+     }
+
    nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
    tvg_paint_translate(sd->shape, nd->x, nd->y);
 
@@ -750,30 +763,33 @@ _efl_canvas_vg_shape_render_pre_tvg(EINA_UNUSED Evas_Object_Protected_Data *vg_p
         tvg_shape_set_fill_color(sd->shape, r, g, b, a);
      }
 
-   m = evas_vg_node_transformation_get(obj);
-   if (m)
+   if (cTransform)
      {
-        _convert_eina_to_tvg_mat(m, &trans_mat);
+        _convert_eina_to_tvg_mat(cTransform, &trans_mat);
         trans_mat.e13 += nd->x;
         trans_mat.e23 += nd->y;
-
-        tvg_paint_scale(sd->shape, trans_mat.e11);
         tvg_paint_transform(sd->shape, &trans_mat);
      }
 
-
-   if (sd->pushed == EINA_FALSE)
+   if (scene)
+     {
+        if (eina_hash_find(sd->targets, &scene) == NULL)
+          {
+             tvg_scene_push(scene, sd->shape);
+             eina_hash_add(sd->targets, &scene, scene);
+          }
+     }
+   else if (canvas)
      {
-        tvg_canvas_push((Tvg_Canvas *) canvas, sd->shape);
-        sd->pushed = EINA_TRUE;
+        if (eina_hash_find(sd->targets, &canvas) == NULL)
+          {
+             tvg_canvas_push(canvas, sd->shape);
+             eina_hash_add(sd->targets, &canvas, canvas);
+          }
      }
 
-   //get fill color and set it
-   efl_gfx_color_get(obj, &r, &g, &b, &a);
-   tvg_shape_set_fill_color(sd->shape, r, g, b, a);
    uint8_t opacity = nd->visibility ? 255 : 0;
    tvg_paint_set_opacity(sd->shape, opacity);
-   tvg_canvas_update_paint((Tvg_Canvas *) canvas, sd->shape);
 }
 #endif
 
@@ -800,6 +816,11 @@ _efl_canvas_vg_shape_efl_object_constructor(Eo *obj, Efl_Canvas_Vg_Shape_Data *p
    nd->render_pre_tvg = _efl_canvas_vg_shape_render_pre_tvg;
    pd->shape = tvg_shape_new();
    pd->scale = 1.0;
+   pd->targets = eina_hash_pointer_new(NULL);
+
+   //default EFL implementation. We don't want to draw invisible shapes.
+   //when object is visible, renderer changes opacity to valid value.
+   tvg_paint_set_opacity(pd->shape, 0);
 #endif
 
    nd->data = pd;
@@ -814,9 +835,8 @@ _efl_canvas_vg_shape_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Shape_Data *pd
    if (pd->stroke.marker) efl_unref(pd->stroke.marker);
 
 #ifdef HAVE_THORVG
-   //tvg_canvas_destroy is called before and it frees all shapes so there is no need to
-   //call tvg_paint_del API.
-   pd->shape = NULL;
+   tvg_paint_del(pd->shape);
+   eina_hash_free(pd->targets);
 #else
    efl_gfx_path_reset(obj);
 #endif
index 2111d60..f8dac76 100644 (file)
@@ -87,7 +87,7 @@ struct _Efl_Canvas_Vg_Node_Data
          Eina_Matrix3 *ptransform, int opacity, Ector_Buffer *comp, Efl_Gfx_Vg_Composite_Method comp_method, void *data);
 
 #ifdef HAVE_THORVG
-   void (*render_pre_tvg)(Evas_Object_Protected_Data *vg_pd, Efl_VG *node, Efl_Canvas_Vg_Node_Data *nd, void *canvas);
+   void (*render_pre_tvg)(Evas_Object_Protected_Data *vg_pd, Efl_VG *node, Efl_Canvas_Vg_Node_Data *nd, Eina_Matrix3 *ptransform, void *canvas, void *scene, int w, int h);
    void (*render_tvg)(Evas_Object_Protected_Data *vg_pd, Efl_VG *node, Efl_Canvas_Vg_Node_Data *nd, void *canvas);
 #endif
 
@@ -130,6 +130,11 @@ struct _Efl_Canvas_Vg_Container_Data
         unsigned int length;                //blend buffer data size
         unsigned int stride;                //blend buffer stride
    } blend;
+
+#ifdef HAVE_THORVG
+   Tvg_Paint *scene;
+   Eina_Hash *targets;
+#endif
 };
 
 struct _Efl_Canvas_Vg_Gradient_Data