evas_vg refactoring: thorvg svg loader: evas 47/261147/8
authorMichal Maciola <m.maciola@samsung.com>
Mon, 12 Jul 2021 10:31:13 +0000 (12:31 +0200)
committerHermet Park <chuneon.park@samsung.com>
Tue, 24 Aug 2021 09:40:02 +0000 (09:40 +0000)
This patch changes evas svg loader to using thorvg svg loader.
The patch extands .svg only; .svgz and .svg.gz will be loaded using old loader.
For edje_cc support (edj/edc files), svg file content is written into edj.

Patch is divided into two parts- edje & evas. This is evas part.

Change-Id: I3bbff14058daf737ec4c3c9b3244f1810649b948

src/lib/evas/canvas/efl_canvas_vg_image.c
src/lib/evas/canvas/efl_canvas_vg_image.eo
src/lib/evas/file/evas_module.c
src/lib/evas/meson.build
src/lib/evas/vg/evas_vg_cache.c
src/modules/evas/vg_loaders/tvg/evas_vg_load_tvg.c [new file with mode: 0644]
src/static_libs/vg_common/vg_common_svg.c

index 0cb81cc..5762d64 100644 (file)
@@ -25,24 +25,12 @@ _efl_canvas_vg_image_render_pre(EINA_UNUSED Evas_Object_Protected_Data *vg_pd,
    Tvg_Matrix trans_mat = { 0 };
 
    if (!nd || !nd->data) return;
-
    Efl_Canvas_Vg_Image_Data *pd = nd->data;
 
    if (nd->flags != EFL_GFX_CHANGE_FLAG_NONE)
      {
         nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
 
-        if (!pd->picture && pd->image)
-          {
-             pd->picture = tvg_picture_new();
-             if (tvg_picture_load_raw(pd->picture, pd->image, pd->w, pd->h, true) != TVG_RESULT_SUCCESS)
-                {
-                   printf("Error loading image buffer \n");
-                   return;
-                }
-          }
-        if (!pd->picture) return;
-
         EFL_CANVAS_VG_COMPUTE_MATRIX(cTransform, pTransform, nd);
         tvg_paint_translate(pd->picture, nd->x, nd->y);
         if (cTransform)
@@ -75,14 +63,17 @@ _efl_canvas_vg_image_efl_object_constructor(Eo *obj, Efl_Canvas_Vg_Image_Data *p
 
    nd->render_pre = _efl_canvas_vg_image_render_pre;
 
+   pd->picture = tvg_picture_new();
+
    efl_gfx_color_set(obj , 255, 255, 255, 255);
 
    return obj;
 }
 
 static void
-_efl_canvas_vg_image_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Image_Data *pd EINA_UNUSED)
+_efl_canvas_vg_image_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Image_Data *pd)
 {
+   tvg_paint_del(pd->picture);
    efl_destructor(efl_super(obj, MY_CLASS));
 }
 
@@ -92,9 +83,62 @@ _efl_canvas_vg_image_data_set(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Image_Data *pd,
    if (!data || size.w <= 0 || size.h <= 0)
      return;
 
+   if (pd->image == data && pd->w == size.w && pd->h == size.h)
+     return;
+
+   if (tvg_picture_load_raw(pd->picture, data, size.w, size.h, true) != TVG_RESULT_SUCCESS)
+     {
+        ERR("Error loading image buffer.");
+        return;
+     }
+
    pd->image = data;
    pd->w = size.w;
    pd->h = size.h;
 }
 
+static Eina_Bool
+_efl_canvas_vg_image_file_set(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Image_Data *pd, const char *path)
+{
+   if (tvg_picture_load(pd->picture, path) == TVG_RESULT_SUCCESS)
+     return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_efl_canvas_vg_image_memfile_set(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Image_Data *pd, const char *data, uint32_t size, const char *mimetype)
+{
+   if (tvg_picture_load_data(pd->picture, data, size, mimetype, true) == TVG_RESULT_SUCCESS)
+     return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Rect
+_efl_canvas_vg_image_viewbox_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Image_Data *pd)
+{
+   float x, y, w, h;
+
+   if (tvg_picture_get_viewbox(pd->picture, &x, &y, &w, &h) == TVG_RESULT_SUCCESS)
+     return EINA_RECT(x, y, w, h);
+   return EINA_RECT(0, 0, 0, 0);
+}
+
+EOLIAN static Efl_Canvas_Vg_Node *
+_efl_canvas_vg_image_efl_duplicate_duplicate(const Eo *obj, Efl_Canvas_Vg_Image_Data *pd)
+{
+   Efl_Canvas_Vg_Node *node = NULL;
+   Efl_Canvas_Vg_Image_Data *sd = NULL;
+
+   node = efl_duplicate(efl_super(obj, MY_CLASS));
+   sd = efl_data_scope_get(node, MY_CLASS);
+
+   if (pd->picture) sd->picture = tvg_paint_duplicate(pd->picture);
+
+   sd->image = pd->image; // note: no memcpy here
+   sd->w = pd->w;
+   sd->h = pd->h;
+
+   return node;
+}
+
 #include "efl_canvas_vg_image.eo.c"
index 05ea4b9..cda9748 100644 (file)
@@ -11,8 +11,37 @@ class @beta Efl.Canvas.Vg.Image extends Efl.Canvas.Vg.Node implements Efl.Gfx.Im
             size: Eina.Size2D; [[The size in pixels.]]
          }
       }
+      @property file {
+         [[Set path for file to be loaded]]
+         set {
+            return: bool; [[$true on success, $false otherwise]]
+         }
+         values {
+            path: string; [[Path for image to be loaded]]
+         }
+      }
+      @property memfile {
+         [[Set image data passing data and size]]
+         set {
+            return: bool; [[$true on success, $false otherwise]]
+         }
+         values {
+            data: ptr(const(char)); [[Data]]
+            size: uint32; [[Size of data]]
+            mimetype: ptr(const(char)); [[Mimetype of data]]
+         }
+      }
+      @property viewbox {
+         [[Get viewbox for loaded]]
+         get {
+         }
+         values {
+            r: Eina.Rect; [[The function returns viewbox coordinates and size for given paint: x y w h]]
+         }
+      }
    }
    implements {
+      Efl.Duplicate.duplicate;
       Efl.Object.constructor;
       Efl.Object.destructor;
    }
index 83f1d80..5d16efe 100644 (file)
@@ -193,6 +193,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(engine, wayland_egl);
 EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, eet);
 EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, svg);
 EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, json);
+EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, tvg);
 #endif
 
 #if !EVAS_MODULE_NO_IMAGE_LOADERS
@@ -281,6 +282,9 @@ static const struct {
 #ifdef EVAS_STATIC_BUILD_VG_SVG
   EVAS_EINA_STATIC_MODULE_USE(vg_loader, svg),
 #endif
+#ifdef EVAS_STATIC_BUILD_VG_TVG
+  EVAS_EINA_STATIC_MODULE_USE(vg_loader, tvg),
+#endif
 #ifdef EVAS_STATIC_BUILD_VG_EET
   EVAS_EINA_STATIC_MODULE_USE(vg_loader, eet),
 #endif
index cc9715b..f9b83b1 100644 (file)
@@ -47,6 +47,7 @@ evas_vg_loaders_file = [
   ['eet', [eet]],
   ['json', [json]],
   ['svg', []],
+  ['tvg', []],
 ]
 
 evas_vg_savers_file = ['eet', 'svg']
index 2dc0586..d7e1c4b 100644 (file)
@@ -28,14 +28,14 @@ static const struct ext_loader_s loaders[] =
 { /* map extensions to loaders to use for good first-guess tries */
    MATCHING(".eet", "eet"),
    MATCHING(".edj", "eet"),
-   MATCHING(".svg", "svg"),
+   MATCHING(".svg", "tvg"),
    MATCHING(".svgz", "svg"),
    MATCHING(".svg.gz", "svg")
 };
 
 static const char *loaders_name[] =
 { /* in order of most likely needed */
-  "eet", "json", "svg"
+  "eet", "json", "tvg", "svg"
 };
 
 static const struct ext_saver_s savers[] =
diff --git a/src/modules/evas/vg_loaders/tvg/evas_vg_load_tvg.c b/src/modules/evas/vg_loaders/tvg/evas_vg_load_tvg.c
new file mode 100644 (file)
index 0000000..a43311a
--- /dev/null
@@ -0,0 +1,124 @@
+#include "vg_common.h"
+
+static int _evas_vg_loader_tvg_log_dom = -1;
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_vg_loader_tvg_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_evas_vg_loader_tvg_log_dom, __VA_ARGS__)
+
+static Eina_Bool
+evas_vg_load_file_close_tvg(Vg_File_Data *vfd)
+{
+   if (!vfd) return EINA_FALSE;
+
+   if (vfd->root) efl_unref(vfd->root);
+   free(vfd);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+evas_vg_load_file_data_tvg(Vg_File_Data *vfd EINA_UNUSED)
+{
+   return EINA_TRUE;
+}
+
+static Vg_File_Data*
+evas_vg_load_file_open_tvg(Eina_File *file,
+                            const char *key EINA_UNUSED,
+                            int *error EINA_UNUSED)
+{
+    Vg_File_Data *vfd = calloc(1, sizeof(Vg_File_Data));
+    if (!vfd) return NULL;
+
+    Eina_Bool loaded = EINA_FALSE;
+    Efl_Canvas_Vg_Image *image = efl_add_ref(EFL_CANVAS_VG_IMAGE_CLASS, NULL);
+
+    if (eina_file_virtual(file))
+      {
+         unsigned int length = eina_file_size_get(file);
+         const char *data = (const char*) eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
+         if (!data) goto err;
+         loaded = efl_canvas_vg_image_memfile_set(image, data, length, "svg");
+         eina_file_map_free(file, (void *) data);
+      }
+    else
+      {
+        loaded = efl_canvas_vg_image_file_set(image, eina_file_filename_get(file));
+      }
+
+    if (!loaded) goto err;
+
+    vfd->root = image;
+
+    Eina_Rect r = efl_canvas_vg_image_viewbox_get(image);
+    vfd->view_box.x = r.x;
+    vfd->view_box.y = r.y;
+    vfd->view_box.w = r.w;
+    vfd->view_box.h = r.h;
+
+    vfd->preserve_aspect = EINA_TRUE;
+    vfd->static_viewbox = EINA_TRUE;
+
+    return vfd;
+
+err:
+    efl_unref(image);
+    free(vfd);
+    return NULL;
+}
+
+static Evas_Vg_Load_Func evas_vg_load_tvg_func =
+{
+   evas_vg_load_file_open_tvg,
+   evas_vg_load_file_close_tvg,
+   evas_vg_load_file_data_tvg
+};
+
+static int
+module_open(Evas_Module *em)
+{
+   if (!em) return 0;
+   em->functions = (void *)(&evas_vg_load_tvg_func);
+   _evas_vg_loader_tvg_log_dom = eina_log_domain_register
+     ("vg-load-tvg", EVAS_DEFAULT_LOG_COLOR);
+   if (_evas_vg_loader_tvg_log_dom < 0)
+     {
+        EINA_LOG_ERR("Can not create a module log domain.");
+        return 0;
+     }
+   return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+   if (_evas_vg_loader_tvg_log_dom >= 0)
+     {
+        eina_log_domain_unregister(_evas_vg_loader_tvg_log_dom);
+        _evas_vg_loader_tvg_log_dom = -1;
+     }
+}
+
+static Evas_Module_Api evas_modapi =
+{
+   EVAS_MODULE_API_VERSION,
+   "tvg",
+   "none",
+   {
+     module_open,
+     module_close
+   }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_VG_LOADER, vg_loader, tvg);
+
+#ifndef EVAS_STATIC_BUILD_VG_TVG
+EVAS_EINA_MODULE_DEFINE(vg_loader, tvg);
+#endif
index 26f52a6..ca379cc 100644 (file)
@@ -782,10 +782,8 @@ _apply_vg_property(Svg_Node *node, Efl_VG *vg, Efl_VG *parent, Vg_File_Data *vg_
    if (node->type == SVG_NODE_G || node->type == SVG_NODE_CLIP_PATH)  return;
 
    // apply the fill style property
-#ifndef HAVE_THORVG
-   //FIX_TVG: replace?
-   efl_gfx_shape_fill_rule_set(vg, style->fill.fill_rule);
-#endif
+   evas_vg_shape_fill_rule_set(vg, style->fill.fill_rule);
+
    evas_vg_shape_stroke_width_set(vg, style->stroke.width);
    evas_vg_shape_stroke_cap_set(vg, style->stroke.cap);
    evas_vg_shape_stroke_join_set(vg, style->stroke.join);