svg : backported svg support from opensource. 15/81115/1
authorSubhransu Mohanty <sub.mohanty@samsung.com>
Fri, 22 Jul 2016 06:55:13 +0000 (15:55 +0900)
committerSubhransu Mohanty <sub.mohanty@samsung.com>
Fri, 22 Jul 2016 06:55:13 +0000 (15:55 +0900)
Change-Id: I8f2abb2d4cecf504537c230f5d7991d98649be4f

27 files changed:
src/Makefile_Edje.am
src/Makefile_Evas.am
src/bin/edje/edje_cc.h
src/bin/edje/edje_cc_handlers.c
src/bin/edje/edje_cc_out.c
src/bin/edje/edje_convert.c
src/bin/edje/edje_inspector.c
src/bin/edje/edje_svg_loader.c [new file with mode: 0644]
src/lib/edje/Edje_Common.h
src/lib/edje/edje_cache.c
src/lib/edje/edje_calc.c
src/lib/edje/edje_convert.c
src/lib/edje/edje_data.c
src/lib/edje/edje_edit.c
src/lib/edje/edje_load.c
src/lib/edje/edje_lua.c
src/lib/edje/edje_private.h
src/lib/evas/Evas_Legacy.h
src/lib/evas/canvas/evas_main.c
src/lib/evas/canvas/evas_object_vg.c
src/lib/evas/include/evas_private.h
src/lib/evas/vg/evas_vg_cache.c [new file with mode: 0644]
src/lib/evas/vg/evas_vg_cache.h [new file with mode: 0644]
src/lib/evas/vg/evas_vg_common.h [new file with mode: 0644]
src/lib/evas/vg/evas_vg_eet_handler.c [new file with mode: 0644]
src/modules/evas/engines/gl_generic/evas_engine.c
src/modules/evas/engines/software_generic/evas_engine.c

index 1e5059f..1eabd14 100644 (file)
@@ -151,8 +151,9 @@ bin/edje/edje_cc_parse.c \
 bin/edje/edje_cc_mem.c \
 bin/edje/edje_cc_handlers.c \
 bin/edje/edje_cc_sources.c \
-bin/edje/edje_multisense_convert.c
-bin_edje_edje_cc_CPPFLAGS = -I$(top_builddir)/src/lib/efl $(EDJE_COMMON_CPPFLAGS)
+bin/edje/edje_multisense_convert.c \
+bin/edje/edje_svg_loader.c
+bin_edje_edje_cc_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_srcdir)/src/lib/evas/vg $(EDJE_COMMON_CPPFLAGS)
 bin_edje_edje_cc_LDADD =  $(USE_EDJE_BIN_LIBS)
 bin_edje_edje_cc_DEPENDENCIES = \
 @USE_EDJE_INTERNAL_LIBS@ \
index 4e605fb..45115bc 100755 (executable)
@@ -173,6 +173,13 @@ lib/evas/canvas/render2/evas_render2_th_main.c \
 lib/evas/canvas/render2/region.c \
 lib/evas/canvas/render2/region.h
 
+# Vg
+lib_evas_libevas_la_SOURCES += \
+lib/evas/vg/evas_vg_eet_handler.c \
+lib/evas/vg/evas_vg_cache.c \
+lib/evas/vg/evas_vg_cache.h \
+lib/evas/vg/evas_vg_common.h
+
 # Cache
 lib_evas_libevas_la_SOURCES += \
 lib/evas/cache/evas_cache_image.c \
@@ -350,6 +357,7 @@ lib_evas_libevas_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
 -I$(top_srcdir)/src/lib/evas/include \
 -I$(top_srcdir)/src/static_libs/libunibreak \
 -I$(top_builddir)/src/lib/evas/canvas \
+-I$(top_builddir)/src/lib/evas/vg \
 -I$(top_builddir)/src/modules/evas/engines/software_generic \
 -I$(top_builddir)/src/modules/evas/engines/gl_generic \
 -DPACKAGE_BIN_DIR=\"$(bindir)\" \
index cadc37e..eae4685 100644 (file)
@@ -250,6 +250,8 @@ void edje_cc_handlers_hierarchy_free(void);
 void edje_cc_handlers_pop_notify(const char *token);
 int get_param_index(char *str);
 
+struct _Svg_Node* _svg_load(Eina_File *f, const char *key EINA_UNUSED);
+
 /* global vars */
 extern Eina_List             *ext_dirs;
 extern Eina_List             *img_dirs;
index 6171396..e5cb7eb 100644 (file)
@@ -512,6 +512,9 @@ static void st_collections_group_nomouse(void);
 static void st_collections_group_broadcast(void);
 static void st_collections_group_nobroadcast(void);
 
+static void st_images_vector(void);
+static void _handle_vector_image(void);
+
 // TIZEN_ONLY(20150110): Add plugin keyword.
 #ifdef PLUGIN
 static void ob_plugins_plug(void);
@@ -525,6 +528,7 @@ static void st_collections_plugins_plugin_param(void);
 
 #define IMAGE_STATEMENTS(PREFIX) \
      {PREFIX"images.image", st_images_image}, \
+     {PREFIX"images.vector", st_images_vector}, \
      {PREFIX"images.set.name", st_images_set_name}, \
      {PREFIX"images.set.image.image", st_images_set_image_image}, \
      {PREFIX"images.set.image.size", st_images_set_image_size}, \
@@ -1311,6 +1315,7 @@ New_Object_Handler object_handlers[] =
        proxy{}
        spacer{}
        snapshot{}
+       vector{}
        part {
           desc {
           }
@@ -1338,6 +1343,7 @@ New_Object_Handler object_handlers_short[] =
      {"collections.group.parts.proxy", ob_collections_group_parts_part_short},
      {"collections.group.parts.spacer", ob_collections_group_parts_part_short},
      {"collections.group.parts.part.desc", ob_collections_group_parts_part_desc},
+     {"collections.group.parts.vector", ob_collections_group_parts_part_short},
 };
 
 New_Nested_Handler nested_handlers[] = {
@@ -1356,6 +1362,7 @@ New_Nested_Handler nested_handlers_short[] = {
      {"collections.group.parts", "external", NULL, edje_cc_handlers_hierarchy_pop },
      {"collections.group.parts", "proxy", NULL, edje_cc_handlers_hierarchy_pop },
      {"collections.group.parts", "spacer", NULL, edje_cc_handlers_hierarchy_pop },
+     {"collections.group.parts", "vector", NULL, edje_cc_handlers_hierarchy_pop },
 };
 
 /*****/
@@ -1562,6 +1569,15 @@ _edje_part_description_alloc(unsigned char type, const char *collection, const c
           result = &ed->common;
           break;
        }
+      case EDJE_PART_TYPE_VECTOR:
+        {
+           Edje_Part_Description_Vector *ed;
+
+           ed = mem_alloc(SZ(Edje_Part_Description_Vector));
+
+           result = &ed->common;
+           break;
+        }
      }
 
    if (!result)
@@ -1932,6 +1948,96 @@ st_images_image(void)
      }
 }
 
+static void
+_handle_vector_image(void)
+{
+   Edje_Part_Description_Vector *ed;
+   unsigned int i = 0;
+   char *name;
+
+   ed = (Edje_Part_Description_Vector*) current_desc;
+
+   name = parse_str(0);
+
+   ed->vg.id = -1;
+
+   for (i = 0; i < edje_file->image_dir->vectors_count; ++i)
+     {
+        if (!strcmp(edje_file->image_dir->vectors[i].entry, name))
+          {
+             ed->vg.set = EINA_TRUE;
+             ed->vg.id = edje_file->image_dir->vectors[i].id;
+             break;
+          }
+     }
+   free(name);
+}
+
+/** @edcsubsection{toplevel_images,
+ *                 Images} */
+
+/**
+    @page edcref
+
+    @block
+        images
+    @context
+        vector {
+            vector: "filename1.svg";
+            vector: "filename2.svg";
+            vector: "filename3.svg";
+            ..
+        }
+    @description
+        The "vector" context in the "images" block is used to list each svg image file that will be used in
+        the theme.
+    @endblock
+
+    @property
+        vector
+    @parameters
+        [image file]
+    @endproperty
+ */
+static void
+st_images_vector(void)
+{
+   Edje_Vector_Directory_Entry *vector;
+   const char *tmp;
+   unsigned int i;
+
+   check_min_arg_count(1);
+
+   if (!edje_file->image_dir)
+     edje_file->image_dir = mem_alloc(SZ(Edje_Image_Directory));
+
+   tmp = parse_str(0);
+
+   for (i = 0; i < edje_file->image_dir->vectors_count; ++i)
+     if (!strcmp(edje_file->image_dir->vectors[i].entry, tmp))
+       {
+          free((char*) tmp);
+          return;
+       }
+
+   edje_file->image_dir->vectors_count++;
+   vector = realloc(edje_file->image_dir->vectors,
+                 sizeof (Edje_Vector_Directory_Entry) * edje_file->image_dir->vectors_count);
+   if (!vector)
+     {
+        ERR("No enough memory.");
+        exit(-1);
+     }
+   edje_file->image_dir->vectors = vector;
+   memset(edje_file->image_dir->vectors + edje_file->image_dir->vectors_count - 1,
+    0, sizeof (Edje_Vector_Directory_Entry));
+
+   vector = edje_file->image_dir->vectors + edje_file->image_dir->vectors_count - 1;
+
+   vector->entry = tmp;
+   vector->id = edje_file->image_dir->vectors_count;
+}
+
 /**
    @edcsubsection{toplevel_models,model}
  */
@@ -5021,6 +5127,7 @@ ob_collections_group_parts_part_short(void)
                   "proxy", EDJE_PART_TYPE_PROXY,
                   "spacer", EDJE_PART_TYPE_SPACER,
                   "snapshot", EDJE_PART_TYPE_SNAPSHOT,
+                  "vector", EDJE_PART_TYPE_VECTOR,
                   NULL);
 
    stack_pop_quick(EINA_TRUE, EINA_TRUE);
@@ -5453,6 +5560,7 @@ st_collections_group_parts_part_type(void)
                      "PROXY", EDJE_PART_TYPE_PROXY,
                      "SPACER", EDJE_PART_TYPE_SPACER,
                      "SNAPSHOT", EDJE_PART_TYPE_SNAPSHOT,
+                     "VECTOR", EDJE_PART_TYPE_VECTOR,
                      NULL);
 
    _part_type_set(type);
@@ -7323,6 +7431,11 @@ st_collections_group_parts_part_description_inherit(void)
                 }
               break;
            }
+      case EDJE_PART_TYPE_VECTOR:
+           {
+              // TODO
+              break;
+           }
      }
 
 #undef STRDUP
@@ -8242,6 +8355,7 @@ st_collections_group_parts_part_description_rel2_to_y(void)
             ..
             image {
                 normal: "filename.ext";
+                normal: "filename.svg";
                 tween:  "filename2.ext";
                 ..
                 tween:  "filenameN.ext";
@@ -8271,6 +8385,11 @@ st_collections_group_parts_part_description_image_normal(void)
 
    check_arg_count(1);
 
+   if (current_part->type == EDJE_PART_TYPE_VECTOR)
+     {
+        return _handle_vector_image();
+     }
+
    if (current_part->type != EDJE_PART_TYPE_IMAGE)
      {
         ERR("parse error %s:%i. "
index 1282c62..6c728e8 100644 (file)
@@ -21,6 +21,7 @@
 #include "edje_cc.h"
 #include "edje_convert.h"
 #include "edje_multisense_convert.h"
+#include "evas_vg_common.h"
 
 #include <lua.h>
 #include <lauxlib.h>
@@ -168,6 +169,13 @@ struct _Sound_Write
    int i;
 };
 
+struct _Vector_Write
+{
+   Eet_File *ef;
+   Svg_Node *root;
+   int i;
+};
+
 struct _Mo_Write
 {
    Eet_File *ef;
@@ -1126,6 +1134,54 @@ data_image_preload_done(void *data, Evas *e EINA_UNUSED, Evas_Object *o, void *e
 }
 
 static void
+data_write_vectors(Eet_File *ef, int *vector_num)
+{
+   unsigned int i;
+   Svg_Node *root;
+   Eet_Data_Descriptor *svg_node_eet;
+   Eina_List *ll;
+   char *s;
+   Eina_File *f = NULL;
+   Edje_Vector_Directory_Entry *vector;
+   Eina_Strbuf *buf;
+   Eina_Bool found = EINA_FALSE;
+
+   if (!((edje_file) && (edje_file->image_dir))) return;
+
+   svg_node_eet = _evas_vg_svg_node_eet();
+   buf = eina_strbuf_new();
+   for (i = 0; i < edje_file->image_dir->vectors_count; i++)
+     {
+        vector = &edje_file->image_dir->vectors[i];
+        EINA_LIST_FOREACH(img_dirs, ll, s)
+          {
+             eina_strbuf_reset(buf);
+             eina_strbuf_append_printf(buf, "%s/%s", s, vector->entry);
+             f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
+             if (!f) continue;
+             root = _svg_load(f, NULL);
+             if(!root)
+               error_and_abort(ef, "Failed to parse svg : %s", vector->entry);
+             eina_strbuf_reset(buf);
+             eina_strbuf_append_printf(buf, "edje/vectors/%i", vector->id);
+             if(!eet_data_write(ef, svg_node_eet, eina_strbuf_string_get(buf), root, compress_mode))
+               error_and_abort(ef, "Failed to write data in Eet for svg :%s", vector->entry);
+             *vector_num += 1;
+             eina_file_close(f);
+             found = EINA_TRUE;
+             _evas_vg_svg_node_free(root);
+             break;
+          }
+        if (!found)
+          error_and_abort(ef, "Unable to find the svg :%s", vector->entry);
+        found = EINA_FALSE;
+     }
+   eina_strbuf_free(buf);
+   _evas_vg_svg_node_eet_destroy();
+}
+
+static void
 data_write_images(Eet_File *ef, int *image_num)
 {
    int i;
@@ -2334,6 +2390,7 @@ data_write(void)
    int vibration_num = 0;
    int font_num = 0;
    int collection_num = 0;
+   int vector_num = 0;
    double t;
 
    if (!edje_file)
@@ -2388,6 +2445,8 @@ data_write(void)
    INF("fontmap: %3.5f", ecore_time_get() - t); t = ecore_time_get();
    data_write_images(ef, &image_num);
    INF("images: %3.5f", ecore_time_get() - t); t = ecore_time_get();
+   data_write_vectors(ef, &vector_num);
+   INF("vectors: %3.5f", ecore_time_get() - t); t = ecore_time_get();
    data_write_fonts(ef, &font_num);
    INF("fonts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
    data_write_sounds(ef, &sound_num);
index 25afe10..1aff944 100644 (file)
@@ -232,6 +232,7 @@ _edje_collection_convert(Eet_File *ef, Edje_Part_Collection_Directory_Entry *ce,
             CSP(BOX, ce);
             CSP(TABLE, ce);
             CSP(EXTERNAL, ce);
+       CSP(VECTOR, ce);
           default:
              count = &dummy;
              break;
@@ -256,6 +257,7 @@ _edje_collection_convert(Eet_File *ef, Edje_Part_Collection_Directory_Entry *ce,
    CONVERT_EMN(TABLE, Edje_Part_Description_Table, ce);
    CONVERT_EMN(EXTERNAL, Edje_Part_Description_External, ce);
    CONVERT_EMN(part, Edje_Part, ce);
+   CONVERT_EMN(VECTOR, Edje_Part_Description_Vector, ce);
 
    /* Change structure layout */
    edc = calloc(1, sizeof (Edje_Part_Collection));
@@ -449,6 +451,7 @@ _edje_description_convert(int type,
         CONVERT_ALLOC_POOL(BOX, Box, box);
         CONVERT_ALLOC_POOL(TABLE, Table, table);
         CONVERT_ALLOC_POOL(EXTERNAL, External, external_params);
+   CONVERT_ALLOC_POOL(VECTOR, Vector, vector);
      }
 
    if (result)
index c6f8bd3..b071034 100644 (file)
@@ -208,6 +208,8 @@ part_type_name_get(Edje_Part_Type t)
          return "EXTERNAL";
       case EDJE_PART_TYPE_SPACER:
          return "SPACER";
+      case EDJE_PART_TYPE_VECTOR:
+         return "VECTOR";
 
       case EDJE_PART_TYPE_NONE:
       case EDJE_PART_TYPE_LAST:
diff --git a/src/bin/edje/edje_svg_loader.c b/src/bin/edje/edje_svg_loader.c
new file mode 100644 (file)
index 0000000..a6377f6
--- /dev/null
@@ -0,0 +1,2026 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <edje_private.h>
+#include <ctype.h>
+
+#include <Eet.h>
+#include <Eina.h>
+#include <Evas.h>
+#include <eina_matrix.h>
+#include "evas_vg_common.h"
+
+#ifndef A_VAL
+#ifndef WORDS_BIGENDIAN
+/* x86 */
+#define A_VAL(p) (((uint8_t *)(p))[3])
+#define R_VAL(p) (((uint8_t *)(p))[2])
+#define G_VAL(p) (((uint8_t *)(p))[1])
+#define B_VAL(p) (((uint8_t *)(p))[0])
+#define AR_VAL(p) ((uint16_t *)(p)[1])
+#define GB_VAL(p) ((uint16_t *)(p)[0])
+#else
+/* ppc */
+#define A_VAL(p) (((uint8_t *)(p))[0])
+#define R_VAL(p) (((uint8_t *)(p))[1])
+#define G_VAL(p) (((uint8_t *)(p))[2])
+#define B_VAL(p) (((uint8_t *)(p))[3])
+#define AR_VAL(p) ((uint16_t *)(p)[0])
+#define GB_VAL(p) ((uint16_t *)(p)[1])
+#endif
+#endif
+
+#define ARGB_JOIN(a,r,g,b) \
+        (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
+
+
+typedef Svg_Node *(*Factory_Method)(Svg_Node *parent, const char *buf, unsigned buflen);
+
+typedef Svg_Style_Gradient *(*Gradient_Factory_Method)(const char *buf, unsigned buflen);
+
+typedef struct _Evas_SVG_Loader Evas_SVG_Loader;
+struct _Evas_SVG_Loader
+{
+   Eina_Array *stack;
+   Svg_Node *doc;
+   Svg_Node *def;
+   Svg_Style_Gradient *gradient;
+   int level;
+   Eina_Bool result:1;
+};
+
+char *
+_skip_space(const char *str, const char *end)
+{
+   while (((end != NULL && str < end) || (end == NULL && *str != '\0')) && isspace(*str))
+     ++str;
+   return (char *)str;
+}
+
+static inline Eina_Stringshare *
+_copy_id(const char* str)
+{
+   if (str == NULL) return NULL;
+
+   return eina_stringshare_add(str);
+}
+
+static const char *
+_skipcomma(const char *content)
+{
+   content = _skip_space(content, NULL);
+   if (*content == ',') return content + 1;
+   return content;
+}
+
+static inline Eina_Bool
+_parse_number(const char **content, double *number)
+{
+   char *end = NULL;
+
+   *number = strtod(*content, &end);
+   // if the start of string is not number
+   if ((*content) == end) return EINA_FALSE;
+   //skip comma if any
+   *content = _skipcomma(end);
+   return EINA_TRUE;
+}
+
+static inline double
+_to_double(const char *str)
+{
+   char *end = NULL;
+
+   return strtod(str, &end);
+}
+
+static inline int
+_to_opacity(const char *str)
+{
+   char *end = NULL;
+   int a = 0;
+   double opacity = strtod(str, &end);
+
+   if (*end == '\0')
+     a = lrint(opacity * 255);
+   return a;
+}
+
+#define _PARSE_TAG(Type, Short_Name, Tags_Array, Default)               \
+  static Type _to_##Short_Name(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].Short_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 struct {
+   Efl_Gfx_Cap line_cap;
+   const char *tag;
+} line_cap_tags[] = {
+  { EFL_GFX_CAP_BUTT, "butt" },
+  { EFL_GFX_CAP_ROUND, "round" },
+  { EFL_GFX_CAP_SQUARE, "square" }
+};
+
+_PARSE_TAG(Efl_Gfx_Cap, line_cap, line_cap_tags, EFL_GFX_CAP_LAST);
+
+/* 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 struct {
+   Efl_Gfx_Join line_join;
+   const char *tag;
+} line_join_tags[] = {
+  { EFL_GFX_JOIN_MITER, "miter" },
+  { EFL_GFX_JOIN_ROUND, "round" },
+  { EFL_GFX_JOIN_BEVEL, "bevel" }
+};
+
+_PARSE_TAG(Efl_Gfx_Join, line_join, line_join_tags, EFL_GFX_JOIN_LAST);
+
+/* parse the fill rule used during filling a path.
+ * Value:   nonzero | evenodd | inherit
+ * Initial:    nonzero
+ * https://www.w3.org/TR/SVG/painting.html
+ */
+
+static struct {
+   Efl_Gfx_Fill_Rule fill_rule;
+   const char *tag;
+} fill_rule_tags[] = {
+  { EFL_GFX_FILL_RULE_ODD_EVEN, "evenodd" }
+};
+
+_PARSE_TAG(Efl_Gfx_Fill_Rule, fill_rule, fill_rule_tags, EFL_GFX_FILL_RULE_WINDING);
+
+#if 0
+// unused at the moment
+/* parse the dash pattern used during stroking a path.
+ * Value:   none | <dasharray> | inherit
+ * Initial:    none
+ * https://www.w3.org/TR/SVG/painting.html
+ */
+static inline void
+_parse_dash_array(const char *str, Efl_Gfx_Dash** dash, int *length)
+{
+   double tmp[30];
+   char *end = NULL;
+   int leni, gapi, count = 0, index = 0;
+
+   while (*str)
+     {
+        // skip white space, comma
+        str = _skipcomma(str);
+        tmp[count++] = strtod(str, &end);
+        str = _skipcomma(end);
+     }
+
+   if (count & 0x1)
+     { // odd case.
+        *length = count;
+        *dash = calloc(*length, sizeof(Efl_Gfx_Dash));
+        while (index < count)
+          {
+             leni = (2 * index) % count;
+             gapi = (2 * index + 1) % count;
+             (*dash)[index].length = tmp[leni];
+             (*dash)[index].gap = tmp[gapi];
+          }
+     }
+   else
+     { // even case
+        *length = count/2;
+        *dash = calloc(*length, sizeof(Efl_Gfx_Dash));
+        while (index < count)
+          {
+             (*dash)[index].length = tmp[2 * index];
+             (*dash)[index].gap = tmp[2 * index + 1];
+          }
+     }
+}
+#endif
+
+static Eina_Stringshare *
+ _id_from_url(const char *url)
+{
+   char tmp[50];
+   int i = 0;
+
+   url = _skip_space(url, NULL);
+   if ((*url) == '(')
+     ++url;
+   url = _skip_space(url, NULL);
+   if ((*url) == '#')
+     ++url;
+
+   while ((*url) != ')')
+     {
+        tmp[i++] = *url;
+        ++url;
+     }
+   tmp[i] = '\0';
+
+   return eina_stringshare_add(tmp);
+}
+
+static unsigned char
+_color_parser(const char *value, char **end)
+{
+   double r;
+
+   r = strtod(value + 4, end);
+   *end = _skip_space(*end, NULL);
+   if (**end == '%')
+     r = 255 * r / 100;
+   *end = _skip_space(*end, NULL);
+
+   if (r < 0 || r > 255)
+     {
+        *end = NULL;
+        return 0;
+     }
+
+   return lrint(r);
+}
+
+static const 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 inline void
+_to_color(const char *str, int *r, int *g, int *b, Eina_Stringshare** 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, NULL, 16);
+             tmp[0] = str[2]; tmp[1] = str[2]; *g = strtol(tmp, NULL, 16);
+             tmp[0] = str[3]; tmp[1] = str[3]; *b = strtol(tmp, NULL, 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, NULL, 16);
+             tmp[0] = str[3]; tmp[1] = str[4]; *g = strtol(tmp, NULL, 16);
+             tmp[0] = str[5]; tmp[1] = str[6]; *b = strtol(tmp, NULL, 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 = _color_parser(str + 4, &red);
+        if (red && *red == ',')
+          {
+             tg = _color_parser(red + 1, &green);
+             if (green && *green == ',')
+               {
+                  tb = _color_parser(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 = _id_from_url(str+3);
+     }
+   else
+     {
+        //handle named color
+        for (i = 0; i < (sizeof (colors) / sizeof (colors[0])); i++)
+          if (!strcasecmp(colors[i].name, str))
+            {
+               *r = R_VAL(&(colors[i].value));
+               *g = G_VAL(&(colors[i].value));
+               *b = B_VAL(&(colors[i].value));
+            }
+     }
+}
+
+static inline char *
+parse_numbers_array(char *str, double *points, int *pt_count)
+{
+   int count = 0;
+   char *end = NULL;
+
+   str = _skip_space(str, NULL);
+   while (isdigit(*str) ||
+          *str == '-' ||
+          *str == '+' ||
+          *str == '.')
+     {
+        points[count++] = strtod(str, &end);
+        str = end;
+        str = _skip_space(str, NULL);
+        if (*str == ',')
+          ++str;
+        //eat the rest of space
+        str = _skip_space(str, NULL);
+     }
+   *pt_count = count;
+   return str;
+}
+
+typedef enum _Matrix_State
+{
+  SVG_MATRIX_UNKNOWN,
+  SVG_MATRIX_MATRIX,
+  SVG_MATRIX_TRANSLATE,
+  SVG_MATRIX_ROTATE,
+  SVG_MATRIX_SCALE,
+  SVG_MATRIX_SKEWX,
+  SVG_MATRIX_SKEWY
+} Matrix_State;
+
+#define MATRIX_DEF(Name, Value)                 \
+  { #Name, sizeof (#Name), Value}
+
+static const struct {
+   const char *tag;
+   int sz;
+   Matrix_State state;
+} matrix_tags[] = {
+  MATRIX_DEF(matrix, SVG_MATRIX_MATRIX),
+  MATRIX_DEF(translate, SVG_MATRIX_TRANSLATE),
+  MATRIX_DEF(rotate, SVG_MATRIX_ROTATE),
+  MATRIX_DEF(scale, SVG_MATRIX_SCALE),
+  MATRIX_DEF(skewX, SVG_MATRIX_SKEWX),
+  MATRIX_DEF(skewY, SVG_MATRIX_SKEWY)
+};
+
+/* parse transform attribute
+ * https://www.w3.org/TR/SVG/coords.html#TransformAttribute
+ */
+static Eina_Matrix3 *
+_parse_transformation_matrix(const char *value)
+{
+   unsigned int i;
+   double points[8];
+   int pt_count = 0;
+   double sx, sy;
+   Matrix_State state = SVG_MATRIX_UNKNOWN;
+   Eina_Matrix3 *matrix = calloc(1, sizeof(Eina_Matrix3));
+   char *str = (char *)value;
+   char *end = str + strlen(str);
+
+   eina_matrix3_identity(matrix);
+   while (str < end)
+     {
+        if (isspace(*str) || (*str == ','))
+          {
+             ++str;
+             continue;
+          }
+        for (i = 0; i < sizeof (matrix_tags) / sizeof(matrix_tags[0]); i++)
+          if (!strncmp(matrix_tags[i].tag, str, matrix_tags[i].sz -1))
+            {
+               state = matrix_tags[i].state;
+               str += (matrix_tags[i].sz -1);
+            }
+        if ( state == SVG_MATRIX_UNKNOWN)
+          goto error;
+
+        str = _skip_space(str, end);
+        if (*str != '(')
+          goto error;
+        ++str;
+        str = parse_numbers_array(str, points, &pt_count);
+        if (*str != ')')
+          goto error;
+        ++str;
+
+        if (state == SVG_MATRIX_MATRIX)
+          {
+             Eina_Matrix3 tmp;
+
+             if (pt_count != 6) goto error;
+
+             eina_matrix3_identity(&tmp);
+             eina_matrix3_values_set(&tmp,
+                                     points[0], points[2], points[4],
+                                     points[1], points[3], points[5],
+                                     0, 0, 1);
+             eina_matrix3_compose(matrix, &tmp, matrix);
+          }
+        else if (state == SVG_MATRIX_TRANSLATE)
+          {
+             if (pt_count == 1)
+               eina_matrix3_translate(matrix, points[0], 0);
+             else if (pt_count == 2)
+               eina_matrix3_translate(matrix, points[0], points[1]);
+             else
+               goto error;
+          }
+        else if (state == SVG_MATRIX_ROTATE)
+          {
+             if (pt_count == 1)
+               {
+                  eina_matrix3_rotate(matrix, points[0] * (M_PI/180.0));
+               }
+             else if (pt_count == 3)
+               {
+                  eina_matrix3_translate(matrix, points[1], points[2]);
+                  eina_matrix3_rotate(matrix, points[0] * (M_PI/180.0));
+                  eina_matrix3_translate(matrix, -points[1], -points[2]);
+               }
+             else
+               {
+                  goto error;
+               }
+          }
+        else if (state == SVG_MATRIX_SCALE)
+          {
+             if (pt_count < 1 || pt_count > 2) goto error;
+
+             sx = points[0];
+             sy = sx;
+             if (pt_count == 2)
+               sy = points[1];
+             eina_matrix3_scale(matrix, sx, sy);
+          }
+     }
+ error:
+   return matrix;
+}
+
+#define LENGTH_DEF(Name, Value)                 \
+  { #Name, sizeof (#Name), Value}
+
+static const struct {
+   const char *tag;
+   int sz;
+   Svg_Length_Type type;
+} length_tags[] = {
+  LENGTH_DEF(%, SVG_LT_PERCENT),
+  LENGTH_DEF(px, SVG_LT_PX),
+  LENGTH_DEF(pc, SVG_LT_PC),
+  LENGTH_DEF(pt, SVG_LT_PT),
+  LENGTH_DEF(mm, SVG_LT_MM),
+  LENGTH_DEF(cm, SVG_LT_CM),
+  LENGTH_DEF(in, SVG_LT_IN)
+};
+
+static double
+parse_length(const char *str, Svg_Length_Type *type)
+{
+   unsigned int i;
+   double value;
+   int sz = strlen(str);
+
+   *type = SVG_LT_PX;
+   for (i = 0; i < sizeof (length_tags) / sizeof(length_tags[0]); i++)
+     if (length_tags[i].sz - 1 == sz && !strncmp(length_tags[i].tag, str, sz))
+       {
+          *type = length_tags[i].type;
+       }
+   value = strtod(str, NULL);
+   return value;
+}
+
+static Eina_Bool _parse_style_attr(void *data, const char *key, const char *value);
+static Eina_Bool _attr_style_node(void *data, const char *str);
+
+static Eina_Bool
+_attr_parse_svg_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+   Svg_Doc_Node *doc = &(node->node.doc);
+   Svg_Length_Type type;
+
+   // @TODO handle lenght unit.
+   if (!strcmp(key, "width"))
+     {
+        doc->width = parse_length(value, &type);
+     }
+   else if (!strcmp(key, "height"))
+     {
+        doc->height = parse_length(value, &type);
+     }
+   else if (!strcmp(key, "viewBox"))
+     {
+        if (_parse_number(&value, &doc->vx))
+          if (_parse_number(&value, &doc->vy))
+            if (_parse_number(&value, &doc->vw))
+              _parse_number(&value, &doc->vh);
+     }
+   else if (!strcmp(key, "style"))
+     {
+        _attr_style_node(node, value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+   return EINA_TRUE;
+}
+
+//https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint
+static void
+_handle_paint_attr(Svg_Paint* paint, const char *value)
+{
+   if (!strcmp(value, "none"))
+     {
+        // no paint property
+        paint->none = EINA_TRUE;
+        return;
+     }
+   paint->none = EINA_FALSE;
+   if (!strcmp(value, "currentColor"))
+     {
+        paint->cur_color = EINA_TRUE;
+        return;
+     }
+   _to_color(value, &paint->r, &paint->g, &paint->b, &paint->url);
+}
+
+static void
+_handle_color_attr(Svg_Node* node, const char *value)
+{
+   Svg_Style_Property *style = node->style;
+   _to_color(value, &style->r, &style->g, &style->b, NULL);
+}
+
+static void
+_handle_fill_attr(Svg_Node* node, const char *value)
+{
+   Svg_Style_Property *style = node->style;
+   style->fill.flags |= SVG_FILL_FLAGS_PAINT;
+   _handle_paint_attr(&style->fill.paint, value);
+}
+
+static void
+_handle_stroke_attr(Svg_Node* node, const char *value)
+{
+   Svg_Style_Property *style = node->style;
+   style->stroke.flags |= SVG_STROKE_FLAGS_PAINT;
+   _handle_paint_attr(&style->stroke.paint, value);
+}
+
+static void
+_handle_stroke_opacity_attr(Svg_Node* node, const char *value)
+{
+   node->style->stroke.flags |= SVG_STROKE_FLAGS_OPACITY;
+   node->style->stroke.opacity = _to_opacity(value);
+}
+
+static void
+_handle_stroke_width_attr(Svg_Node* node, const char *value)
+{
+   node->style->stroke.flags |= SVG_STROKE_FLAGS_WIDTH;
+   node->style->stroke.width = _to_double(value);
+}
+
+static void
+_handle_stroke_linecap_attr(Svg_Node* node, const char *value)
+{
+   node->style->stroke.flags |= SVG_STROKE_FLAGS_CAP;
+   node->style->stroke.cap = _to_line_cap(value);
+}
+
+static void
+_handle_stroke_linejoin_attr(Svg_Node* node, const char *value)
+{
+   node->style->stroke.flags |= SVG_STROKE_FLAGS_JOIN;
+   node->style->stroke.join = _to_line_join(value);
+}
+
+static void
+_handle_fill_rule_attr(Svg_Node* node, const char *value)
+{
+   node->style->fill.flags |= SVG_FILL_FLAGS_FILL_RULE;
+   node->style->fill.fill_rule = _to_fill_rule(value);
+}
+
+static void
+_handle_fill_opacity_attr(Svg_Node* node, const char *value)
+{
+   node->style->fill.flags |= SVG_FILL_FLAGS_OPACITY;
+   node->style->fill.opacity = _to_opacity(value);
+}
+
+static void
+_handle_transform_attr(Svg_Node* node, const char *value)
+{
+   node->transform = _parse_transformation_matrix(value);
+}
+
+
+typedef void (*Style_Method)(Svg_Node *node, const char *value);
+
+#define STYLE_DEF(Name, Name1)       \
+  { #Name, sizeof (#Name), _handle_##Name1##_attr}
+
+static const struct {
+   const char *tag;
+   int sz;
+   Style_Method tag_handler;;
+} style_tags[] = {
+  STYLE_DEF(color, color),
+  STYLE_DEF(fill, fill),
+  STYLE_DEF(fill-rule, fill_rule),
+  STYLE_DEF(fill-opacity, fill_opacity),
+  STYLE_DEF(stroke, stroke),
+  STYLE_DEF(stroke-width, stroke_width),
+  STYLE_DEF(stroke-linejoin, stroke_linejoin),
+  STYLE_DEF(stroke-linecap, stroke_linecap),
+  STYLE_DEF(stroke-opacity, stroke_opacity),
+  STYLE_DEF(transform, transform)
+};
+
+static Eina_Bool
+_parse_style_attr(void *data, const char *key, const char *value)
+{
+   Svg_Node* node = data;
+   unsigned int i;
+   int sz;
+
+   // trim the white space
+   key = _skip_space(key, NULL);
+
+   value = _skip_space(value, NULL);
+
+   sz = strlen(key);
+   for (i = 0; i < sizeof (style_tags) / sizeof(style_tags[0]); i++)
+     if (style_tags[i].sz - 1 == sz && !strncmp(style_tags[i].tag, key, sz))
+       {
+          style_tags[i].tag_handler(node, value);
+          return EINA_TRUE;
+       }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_attr_style_node(void *data, const char *str)
+{
+   eina_simple_xml_attribute_w3c_parse(str,
+                                       _parse_style_attr, data);
+   return EINA_TRUE;
+}
+
+/* parse g node
+ * https://www.w3.org/TR/SVG/struct.html#Groups
+ */
+static Eina_Bool
+_attr_parse_g_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+
+   if (!strcmp(key, "style"))
+     {
+        return _attr_style_node(node, value);
+     }
+   else if (!strcmp(key, "transform"))
+     {
+        node->transform = _parse_transformation_matrix(value);
+     }
+   else if (!strcmp(key, "id"))
+     {
+        node->id = _copy_id(value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+   return EINA_TRUE;
+}
+
+
+static Svg_Node *
+_create_node(Svg_Node *parent, Svg_Node_Type type)
+{
+   Svg_Node *node = calloc(1, sizeof(Svg_Node));
+
+   // default fill property
+   node->style = calloc(1, sizeof(Svg_Style_Property));
+
+   // update the default value of stroke and fill
+   //https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint
+   // default fill color is black
+   node->style->fill.paint.r = 0;
+   node->style->fill.paint.g = 0;
+   node->style->fill.paint.b = 0;
+   node->style->fill.paint.none = EINA_FALSE;
+   // default fill opacity is 1
+   node->style->fill.opacity = 255;
+
+   // default fill rule is nonzero
+   node->style->fill.fill_rule = EFL_GFX_FILL_RULE_WINDING;
+
+   // default stroke is none
+   node->style->stroke.paint.none = EINA_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 = EFL_GFX_CAP_BUTT;
+   // default line join is miter
+   node->style->stroke.join = EFL_GFX_JOIN_MITER;
+   node->style->stroke.scale = 1.0;
+
+   node->parent = parent;
+   node->type = type;
+   node->child = NULL;
+
+   if (parent)
+     parent->child = eina_list_append(parent->child, node);
+   return node;
+}
+
+static Svg_Node *
+_create_defs_node(Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED)
+{
+   Svg_Node *node = _create_node(NULL, SVG_NODE_DEFS);
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    NULL, node);
+   return node;
+}
+
+static Svg_Node *
+_create_g_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_G);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_g_node, node);
+   return node;
+}
+
+static Svg_Node *
+_create_svg_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_DOC);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_svg_node, node);
+   return node;
+}
+
+static Svg_Node *
+_create_switch_node(Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED)
+{
+   return NULL;
+}
+
+static Eina_Bool
+_attr_parse_path_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+   Svg_Path_Node *path = &(node->node.path);
+
+   if (!strcmp(key, "d"))
+     {
+        path->path = eina_stringshare_add(value);
+     }
+   else if (!strcmp(key, "style"))
+     {
+        _attr_style_node(node, value);
+     }
+   else if (!strcmp(key, "id"))
+     {
+        node->id = _copy_id(value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+   return EINA_TRUE;
+}
+
+static Svg_Node *
+_create_path_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_PATH);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_path_node, node);
+   return node;
+}
+
+#define CIRCLE_DEF(Name, Field)       \
+  { #Name, sizeof (#Name), offsetof(Svg_Circle_Node, Field)}
+
+static const struct {
+   const char *tag;
+   int sz;
+   size_t offset;
+} circle_tags[] = {
+  CIRCLE_DEF(cx, cx),
+  CIRCLE_DEF(cy, cy),
+  CIRCLE_DEF(r, r)
+};
+
+/* parse the attributes for a circle element.
+ * https://www.w3.org/TR/SVG/shapes.html#CircleElement
+ */
+static Eina_Bool
+_attr_parse_circle_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+   Svg_Circle_Node *circle = &(node->node.circle);
+   unsigned int i;
+   unsigned char *array;
+   int sz = strlen(key);
+
+   array = (unsigned char*) circle;
+   for (i = 0; i < sizeof (circle_tags) / sizeof(circle_tags[0]); i++)
+     if (circle_tags[i].sz - 1 == sz && !strncmp(circle_tags[i].tag, key, sz))
+       {
+          *((double*) (array + circle_tags[i].offset)) = _to_double(value);
+          return EINA_TRUE;
+       }
+
+   if (!strcmp(key, "style"))
+     {
+        _attr_style_node(node, value);
+     }
+   else if (!strcmp(key, "id"))
+     {
+        node->id = _copy_id(value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+   return EINA_TRUE;
+}
+
+static Svg_Node *
+_create_circle_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_CIRCLE);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_circle_node, node);
+   return node;
+}
+
+#define ELLIPSE_DEF(Name, Field)       \
+  { #Name, sizeof (#Name), offsetof(Svg_Ellipse_Node, Field)}
+
+static const struct {
+   const char *tag;
+   int sz;
+   size_t offset;
+} ellipse_tags[] = {
+  ELLIPSE_DEF(cx,cx),
+  ELLIPSE_DEF(cy,cy),
+  ELLIPSE_DEF(rx,rx),
+  ELLIPSE_DEF(ry,ry)
+};
+
+/* parse the attributes for an ellipse element.
+ * https://www.w3.org/TR/SVG/shapes.html#EllipseElement
+ */
+static Eina_Bool
+_attr_parse_ellipse_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+   Svg_Ellipse_Node *ellipse = &(node->node.ellipse);
+   unsigned int i;
+   unsigned char *array;
+   int sz = strlen(key);
+
+   array = (unsigned char*) ellipse;
+   for (i = 0; i < sizeof (ellipse_tags) / sizeof(ellipse_tags[0]); i++)
+     if (ellipse_tags[i].sz - 1 == sz && !strncmp(ellipse_tags[i].tag, key, sz))
+       {
+          *((double*) (array + ellipse_tags[i].offset)) = _to_double(value);
+          return EINA_TRUE;
+       }
+
+   if (!strcmp(key, "id"))
+     {
+        node->id = _copy_id(value);
+     }
+   else if (!strcmp(key, "style"))
+     {
+        _attr_style_node(node, value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+   return EINA_TRUE;
+}
+
+static Svg_Node *
+_create_ellipse_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_ELLIPSE);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_ellipse_node, node);
+   return node;
+}
+
+static void
+_attr_parse_polygon_points(const char *str, double **points, int *point_count)
+{
+   double tmp[50];
+   int tmp_count=0;
+   int count = 0;
+   double num;
+   double *point_array = NULL;
+
+   while (_parse_number(&str, &num))
+     {
+        tmp[tmp_count++] = num;
+        if (tmp_count == 50)
+          {
+             point_array = realloc(point_array, (count + tmp_count) * sizeof(double));
+             memcpy(&point_array[count], tmp, tmp_count * sizeof(double));
+             count += tmp_count;
+          }
+     }
+
+   if (tmp_count > 0)
+     {
+        point_array = realloc(point_array, (count + tmp_count) * sizeof(double));
+        memcpy(&point_array[count], tmp, tmp_count * sizeof(double));
+        count += tmp_count;
+     }
+   *point_count = count;
+   *points = point_array;
+}
+
+/* parse the attributes for a polygon element.
+ * https://www.w3.org/TR/SVG/shapes.html#PolylineElement
+ */
+static Eina_Bool
+_attr_parse_polygon_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+   Svg_Polygon_Node *polygon = &(node->node.polygon);
+
+   if (!strcmp(key, "points"))
+     {
+        _attr_parse_polygon_points(value, &polygon->points, &polygon->points_count);
+     }
+   else if (!strcmp(key, "style"))
+     {
+        _attr_style_node(node, value);
+     }
+   else if (!strcmp(key, "id"))
+     {
+        node->id = _copy_id(value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+   return EINA_TRUE;
+}
+
+static Svg_Node *
+_create_polygon_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_POLYGON);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_polygon_node, node);
+   return node;
+}
+
+static Svg_Node *
+_create_polyline_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_POLYLINE);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_polygon_node, node);
+   return node;
+}
+
+#define RECT_DEF(Name, Field)       \
+  { #Name, sizeof (#Name), offsetof(Svg_Rect_Node, Field)}
+
+static const struct {
+   const char *tag;
+   int sz;
+   size_t offset;
+} rect_tags[] = {
+  RECT_DEF(x,x),
+  RECT_DEF(y, y),
+  RECT_DEF(width, w),
+  RECT_DEF(height, h),
+  RECT_DEF(rx, rx),
+  RECT_DEF(ry, ry)
+};
+
+/* parse the attributes for a rect element.
+ * https://www.w3.org/TR/SVG/shapes.html#RectElement
+ */
+static Eina_Bool
+_attr_parse_rect_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *node = data;
+   Svg_Rect_Node *rect = & (node->node.rect);
+   unsigned int i;
+   unsigned char *array;
+   int sz = strlen(key);
+
+   array = (unsigned char*) rect;
+   for (i = 0; i < sizeof (rect_tags) / sizeof(rect_tags[0]); i++)
+     if (rect_tags[i].sz - 1 == sz && !strncmp(rect_tags[i].tag, key, sz))
+       {
+          *((double*) (array + rect_tags[i].offset)) = _to_double(value);
+          return EINA_TRUE;
+       }
+
+   if (!strcmp(key, "id"))
+     {
+        node->id = _copy_id(value);
+     }
+   else if (!strcmp(key, "style"))
+     {
+        _attr_style_node(node, value);
+     }
+   else
+     {
+        _parse_style_attr(node, key, value);
+     }
+
+   if (rect->rx != 0 && rect->ry == 0) rect->ry = rect->rx;
+   if (rect->ry != 0 && rect->rx == 0) rect->rx = rect->ry;
+
+   return EINA_TRUE;
+}
+
+static Svg_Node *
+_create_rect_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_RECT);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_rect_node, node);
+   return node;
+}
+
+static Eina_Stringshare *
+_id_from_href(const char *href)
+{
+   href = _skip_space(href, NULL);
+   if ((*href) == '#')
+     href++;
+   return eina_stringshare_add(href);
+}
+
+static Svg_Node*
+_get_defs_node(Svg_Node *node)
+{
+   if (!node) return NULL;
+
+   while (node->parent != NULL)
+     {
+        node = node->parent;
+     }
+
+   if (node->type == SVG_NODE_DOC)
+     return node->node.doc.defs;
+
+   return NULL;
+}
+
+static Svg_Node*
+_find_child_by_id(Svg_Node *node, const char *id)
+{
+   Eina_List *l;
+   Svg_Node *child;
+
+   if (!node) return NULL;
+
+   EINA_LIST_FOREACH(node->child, l, child)
+     {
+        if ((child->id != NULL) && !strcmp(child->id, id))
+          return child;
+     }
+   return NULL;
+}
+
+static Eina_List *
+_clone_grad_stops(Eina_List *from)
+{
+   Efl_Gfx_Gradient_Stop *stop;
+   Eina_List *l;
+   Eina_List *res = NULL;
+
+   EINA_LIST_FOREACH(from, l, stop)
+     {
+        Efl_Gfx_Gradient_Stop *new_stop;
+
+        new_stop = calloc(1, sizeof(Efl_Gfx_Gradient_Stop));
+        memcpy(new_stop, stop, sizeof(Efl_Gfx_Gradient_Stop));
+        res = eina_list_append(res, new_stop);
+     }
+
+   return res;
+}
+
+static Svg_Style_Gradient *
+_clone_gradient(Svg_Style_Gradient *from)
+{
+   Svg_Style_Gradient *grad;
+
+   if (!from) return NULL;
+
+   grad= calloc(1, sizeof(Svg_Style_Gradient));
+   grad->type = from->type;
+   grad->id = _copy_id(from->id);
+   grad->ref = _copy_id(from->ref);
+   grad->spread = from->spread;
+   grad->stops = _clone_grad_stops(from->stops);
+   if (grad->type == SVG_LINEAR_GRADIENT)
+     {
+        grad->linear = calloc(1, sizeof(Svg_Linear_Gradient));
+        memcpy(grad->linear, from->linear, sizeof(Svg_Linear_Gradient));
+     }
+   else if (grad->type == SVG_RADIAL_GRADIENT)
+     {
+        grad->radial = calloc(1, sizeof(Svg_Radial_Gradient));
+        memcpy(grad->radial, from->radial, sizeof(Svg_Radial_Gradient));
+     }
+
+   return grad;
+}
+
+static void
+_copy_attribute(Svg_Node *to, Svg_Node *from)
+{
+   // copy matrix attribute
+   if (from->transform)
+     {
+        to->transform = calloc(1, sizeof(Eina_Matrix3));
+        eina_matrix3_copy(to->transform, from->transform);
+     }
+   // copy style attribute;
+   memcpy(to->style, from->style, sizeof(Svg_Style_Property));
+
+   // copy node attribute
+   switch (from->type)
+     {
+        case SVG_NODE_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 SVG_NODE_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 SVG_NODE_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 SVG_NODE_PATH:
+           to->node.path.path = eina_stringshare_add(from->node.path.path);
+           break;
+        case SVG_NODE_POLYGON:
+           to->node.polygon.points_count = from->node.polygon.points_count;
+           to->node.polygon.points = calloc(to->node.polygon.points_count, sizeof(double));
+           break;
+        default:
+           break;
+     }
+
+}
+
+static void
+_clone_node(Svg_Node *from, Svg_Node *parent)
+{
+   Svg_Node *new_node;
+   Eina_List *l;
+   Svg_Node *child;
+
+   if (!from) return;
+
+   new_node = _create_node(parent, from->type);
+   _copy_attribute(new_node, from);
+
+   EINA_LIST_FOREACH(from->child, l, child)
+     {
+         _clone_node(child, new_node);
+     }
+
+}
+
+static Eina_Bool
+_attr_parse_use_node(void *data, const char *key, const char *value)
+{
+   Svg_Node *defs, *node_from, *node = data;
+   Eina_Stringshare *id;
+
+   if (!strcmp(key, "xlink:href"))
+     {
+        id = _id_from_href(value);
+        defs = _get_defs_node(node);
+        node_from = _find_child_by_id(defs, id);
+        _clone_node(node_from, node);
+        eina_stringshare_del(id);
+     }
+   else
+     {
+        _attr_parse_g_node(data, key, value);
+     }
+   return EINA_TRUE;
+}
+
+static Svg_Node *
+_create_use_node(Svg_Node *parent, const char *buf, unsigned buflen)
+{
+   Svg_Node *node = _create_node(parent, SVG_NODE_G);
+
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_use_node, node);
+   return node;
+}
+
+#define TAG_DEF(Name)                                   \
+  { #Name, sizeof (#Name), _create_##Name##_node }
+
+static const struct {
+   const char *tag;
+   int sz;
+   Factory_Method tag_handler;
+} graphics_tags[] = {
+  TAG_DEF(use),
+  TAG_DEF(circle),
+  TAG_DEF(ellipse),
+  TAG_DEF(path),
+  TAG_DEF(polygon),
+  TAG_DEF(rect),
+  TAG_DEF(polyline),
+};
+
+static const struct {
+   const char *tag;
+   int sz;
+   Factory_Method tag_handler;
+} group_tags[] = {
+  TAG_DEF(defs),
+  TAG_DEF(g),
+  TAG_DEF(svg),
+  TAG_DEF(switch)
+};
+
+#define FIND_FACTORY(Short_Name, Tags_Array)                            \
+  static Factory_Method                                                 \
+  _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].tag_handler;                           \
+         }                                                              \
+     return NULL;                                                       \
+  }
+
+FIND_FACTORY(group, group_tags);
+FIND_FACTORY(graphics, graphics_tags);
+
+Efl_Gfx_Gradient_Spread
+_parse_spread_value(const char *value)
+{
+   Efl_Gfx_Gradient_Spread spread = EFL_GFX_GRADIENT_SPREAD_PAD;
+
+   if (!strcmp(value, "reflect"))
+     {
+        spread = EFL_GFX_GRADIENT_SPREAD_REFLECT;
+     }
+   else if (!strcmp(value, "repeat"))
+     {
+        spread = EFL_GFX_GRADIENT_SPREAD_REPEAT;
+     }
+
+   return spread;
+}
+
+static void
+_handle_radial_cx_attr(Svg_Radial_Gradient* radial, const char *value)
+{
+   radial->cx = _to_double(value);
+}
+
+static void
+_handle_radial_cy_attr(Svg_Radial_Gradient* radial, const char *value)
+{
+   radial->cy = _to_double(value);
+}
+
+static void
+_handle_radial_fx_attr(Svg_Radial_Gradient* radial, const char *value)
+{
+   radial->fx = _to_double(value);
+}
+
+static void
+_handle_radial_fy_attr(Svg_Radial_Gradient* radial, const char *value)
+{
+   radial->fy = _to_double(value);
+}
+
+static void
+_handle_radial_r_attr(Svg_Radial_Gradient* radial, const char *value)
+{
+   radial->r = _to_double(value);
+}
+
+
+typedef void (*Radial_Method)(Svg_Radial_Gradient *radial, const char *value);
+
+#define RADIAL_DEF(Name)       \
+  { #Name, sizeof (#Name), _handle_radial_##Name##_attr}
+
+static const struct {
+   const char *tag;
+   int sz;
+   Radial_Method tag_handler;;
+} radial_tags[] = {
+  RADIAL_DEF(cx),
+  RADIAL_DEF(cy),
+  RADIAL_DEF(fx),
+  RADIAL_DEF(fy),
+  RADIAL_DEF(r)
+};
+
+static Eina_Bool
+_attr_parse_radial_gradient_node(void *data, const char *key, const char *value)
+{
+   Svg_Style_Gradient *grad = data;
+   Svg_Radial_Gradient *radial = grad->radial;
+   unsigned int i;
+   int sz = strlen(key);
+
+   for (i = 0; i < sizeof (radial_tags) / sizeof(radial_tags[0]); i++)
+     if (radial_tags[i].sz - 1 == sz && !strncmp(radial_tags[i].tag, key, sz))
+       {
+          radial_tags[i].tag_handler(radial, value);
+          return EINA_TRUE;
+       }
+
+   if (!strcmp(key, "id"))
+     {
+        grad->id = _copy_id(value);
+     }
+   else if (!strcmp(key, "spreadMethod"))
+     {
+        grad->spread = _parse_spread_value(value);
+     }
+   else if (!strcmp(key, "xlink:href"))
+     {
+        grad->ref = _id_from_href(value);
+     }
+
+   return EINA_TRUE;
+}
+
+static Svg_Style_Gradient *
+_create_radialGradient(const char *buf, unsigned buflen)
+{
+   Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient));
+
+   grad->type = SVG_RADIAL_GRADIENT;
+   grad->radial = calloc(1, sizeof(Svg_Radial_Gradient));
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_radial_gradient_node, grad);
+   return grad;
+
+}
+
+static Eina_Bool
+_attr_parse_stops(void *data, const char *key, const char *value)
+{
+   Efl_Gfx_Gradient_Stop *stop = data;
+
+   if (!strcmp(key, "offset"))
+     {
+        stop->offset = _to_double(value);
+     }
+   else if (!strcmp(key, "stop-opacity"))
+     {
+        stop->a = _to_opacity(value);
+     }
+   else if (!strcmp(key, "stop-color"))
+     {
+        _to_color(value, &stop->r, &stop->g, &stop->b, NULL);
+     }
+   else if (!strcmp(key, "style"))
+     {
+        eina_simple_xml_attribute_w3c_parse(value,
+                                            _attr_parse_stops, data);
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value)
+{
+   linear->x1 = _to_double(value);
+}
+
+static void
+_handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value)
+{
+   linear->y1 = _to_double(value);
+}
+
+static void
+_handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value)
+{
+   linear->x2 = _to_double(value);
+}
+
+static void
+_handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value)
+{
+   linear->y2 = _to_double(value);
+}
+
+
+typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value);
+
+#define LINEAR_DEF(Name)       \
+  { #Name, sizeof (#Name), _handle_linear_##Name##_attr}
+
+static const struct {
+   const char *tag;
+   int sz;
+   Linear_Method tag_handler;;
+} linear_tags[] = {
+  LINEAR_DEF(x1),
+  LINEAR_DEF(y1),
+  LINEAR_DEF(x2),
+  LINEAR_DEF(y2)
+};
+
+static Eina_Bool
+_attr_parse_linear_gradient_node(void *data, const char *key, const char *value)
+{
+   Svg_Style_Gradient *grad = data;
+   Svg_Linear_Gradient *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].tag_handler(linear, value);
+          return EINA_TRUE;
+       }
+
+   if (!strcmp(key, "id"))
+     {
+        grad->id = _copy_id(value);
+     }
+   else if (!strcmp(key, "spreadMethod"))
+     {
+        grad->spread = _parse_spread_value(value);
+     }
+   else if (!strcmp(key, "xlink:href"))
+     {
+        grad->ref = _id_from_href(value);
+     }
+
+   return EINA_TRUE;
+}
+
+static Svg_Style_Gradient *
+_create_linearGradient(const char *buf, unsigned buflen)
+{
+   Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient));
+
+   grad->type = SVG_LINEAR_GRADIENT;
+   grad->linear = calloc(1, sizeof(Svg_Linear_Gradient));
+   eina_simple_xml_attributes_parse(buf, buflen,
+                                    _attr_parse_linear_gradient_node, grad);
+   return grad;
+
+}
+
+#define GRADIENT_DEF(Name)                                   \
+  { #Name, sizeof (#Name), _create_##Name }
+
+static const struct {
+   const char *tag;
+   int sz;
+   Gradient_Factory_Method tag_handler;
+} gradient_tags[] = {
+  GRADIENT_DEF(linearGradient),
+  GRADIENT_DEF(radialGradient)
+};
+
+static Gradient_Factory_Method
+_find_gradient_factory(const char  *name)
+{
+   unsigned int i;
+   int sz = strlen(name);
+
+   for (i = 0; i < sizeof (gradient_tags) / sizeof(gradient_tags[0]); i++)
+     if (gradient_tags[i].sz - 1 == sz && !strncmp(gradient_tags[i].tag, name, sz))
+       {
+          return gradient_tags[i].tag_handler;
+       }
+   return NULL;
+}
+
+static void
+_evas_svg_loader_xml_open_parser(Evas_SVG_Loader *loader,
+                                 const char *content, unsigned int length)
+{
+   const char *attrs = NULL;
+   int attrs_length = 0;
+   int sz = length;
+   char tag_name[20];
+   Factory_Method method;
+   Gradient_Factory_Method gradient_method;
+   Svg_Node *node = NULL, *parent;
+   loader->level++;
+   attrs = eina_simple_xml_tag_attributes_find(content, length);
+
+   if (!attrs)
+     {
+        // parse the empty tag
+        attrs = content;
+        while ((attrs != NULL) && *attrs != '>')
+          attrs++;
+     }
+
+   if (attrs)
+     {
+        // find out the tag name starting from content till sz length
+        sz = attrs - content;
+        attrs_length = length - sz;
+        while ((sz > 0) && (isspace(content[sz - 1])))
+          sz--;
+        strncpy(tag_name, content, sz);
+        tag_name[sz] = '\0';
+     }
+
+   if ((method = _find_group_factory(tag_name)))
+     {
+        //group
+        if (!loader->doc)
+          {
+             if (strcmp(tag_name, "svg"))
+               return; // Not a valid svg document
+             node = method(NULL, attrs, attrs_length);
+             loader->doc = node;
+          }
+        else
+          {
+             parent = eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1);
+             node = method(parent, attrs, attrs_length);
+          }
+        eina_array_push(loader->stack, node);
+
+        if (node->type == SVG_NODE_DEFS)
+        {
+          loader->doc->node.doc.defs = node;
+          loader->def = node;
+        }
+     }
+   else if ((method = _find_graphics_factory(tag_name)))
+     {
+        parent = eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1);
+        node = method(parent, attrs, attrs_length);
+     }
+   else if ((gradient_method = _find_gradient_factory(tag_name)))
+     {
+        Svg_Style_Gradient *gradient;
+        gradient = gradient_method(attrs, attrs_length);
+        if (loader->doc->node.doc.defs)
+          {
+             loader->def->node.defs.gradients = eina_list_append(loader->def->node.defs.gradients, gradient);
+          }
+        loader->gradient = gradient;
+     }
+   else if (!strcmp(tag_name, "stop"))
+     {
+        Efl_Gfx_Gradient_Stop *stop = calloc(1, sizeof(Efl_Gfx_Gradient_Stop));
+        eina_simple_xml_attributes_parse(attrs, attrs_length,
+                                    _attr_parse_stops, stop);
+        if (loader->gradient)
+          loader->gradient->stops = eina_list_append(loader->gradient->stops, stop);
+     }
+
+}
+
+#define POP_TAG(Tag)                            \
+  { #Tag, sizeof (#Tag) }
+
+static const struct {
+   const char *tag;
+   size_t sz;
+} pop_array[] = {
+  POP_TAG(g),
+  POP_TAG(svg),
+  POP_TAG(defs)
+};
+
+static void
+_evas_svg_loader_xml_close_parser(Evas_SVG_Loader *loader,
+                                  const char *content,
+                                  unsigned int length EINA_UNUSED)
+{
+   unsigned int i;
+
+   content = _skip_space(content, NULL);
+
+   for (i = 0; i < sizeof (pop_array) / sizeof (pop_array[0]); i++)
+     if (!strncmp(content, pop_array[i].tag, pop_array[i].sz - 1))
+       {
+          eina_array_pop(loader->stack);
+          break ;
+       }
+
+   loader->level--;
+}
+
+static Eina_Bool
+_evas_svg_loader_parser(void *data, Eina_Simple_XML_Type type,
+                        const char *content,
+                        unsigned int offset EINA_UNUSED, unsigned int length)
+{
+   Evas_SVG_Loader *loader = data;
+
+   switch (type)
+     {
+      case EINA_SIMPLE_XML_OPEN:
+         _evas_svg_loader_xml_open_parser(loader, content, length);
+         break;
+      case EINA_SIMPLE_XML_OPEN_EMPTY:
+         _evas_svg_loader_xml_open_parser(loader, content, length);
+      case EINA_SIMPLE_XML_CLOSE:
+         _evas_svg_loader_xml_close_parser(loader, content, length);
+         break;
+      case EINA_SIMPLE_XML_DATA:
+      case EINA_SIMPLE_XML_CDATA:
+      case EINA_SIMPLE_XML_DOCTYPE_CHILD:
+         break;
+      case EINA_SIMPLE_XML_IGNORED:
+      case EINA_SIMPLE_XML_COMMENT:
+      case EINA_SIMPLE_XML_DOCTYPE:
+         break;
+
+      default:
+         break;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_inherit_style(Svg_Style_Property *child, Svg_Style_Property *parent)
+{
+   if (parent == NULL)
+     return;
+   // inherit the property of parent if not present in child. 
+   // fill
+   if (!(child->fill.flags & SVG_FILL_FLAGS_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.cur_color = parent->fill.paint.cur_color;
+        child->fill.paint.url = _copy_id(parent->fill.paint.url);
+     }
+   if (!(child->fill.flags & SVG_FILL_FLAGS_OPACITY))
+     {
+        child->fill.opacity = parent->fill.opacity;
+     }
+   if (!(child->fill.flags & SVG_FILL_FLAGS_FILL_RULE))
+     {
+        child->fill.fill_rule = parent->fill.fill_rule;
+     }
+   // stroke
+   if (!(child->stroke.flags & SVG_STROKE_FLAGS_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.cur_color = parent->stroke.paint.cur_color;
+        child->stroke.paint.url = _copy_id(parent->stroke.paint.url);
+     }
+   if (!(child->stroke.flags & SVG_STROKE_FLAGS_OPACITY))
+     {
+        child->stroke.opacity = parent->stroke.opacity;
+     }
+   if (!(child->stroke.flags & SVG_STROKE_FLAGS_WIDTH))
+     {
+        child->stroke.width = parent->stroke.width;
+     }
+   if (!(child->stroke.flags & SVG_STROKE_FLAGS_CAP))
+     {
+        child->stroke.cap = parent->stroke.cap;
+     }
+   if (!(child->stroke.flags & SVG_STROKE_FLAGS_JOIN))
+     {
+        child->stroke.join = parent->stroke.join;
+     }
+}
+
+void
+_update_style(Svg_Node *node, Svg_Style_Property *parent_style)
+{
+   Eina_List *l;
+   Svg_Node *child;
+
+   _inherit_style(node->style, parent_style);
+
+   EINA_LIST_FOREACH(node->child, l, child)
+     {
+        _update_style(child, node->style);
+     }
+}
+
+static Svg_Style_Gradient*
+_dup_gradient(Eina_List *grad_list, const char *id)
+{
+   Svg_Style_Gradient *grad;
+   Svg_Style_Gradient *result = NULL;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(grad_list, l, grad)
+     {
+        if (!strcmp(grad->id, id))
+          {
+             result = _clone_gradient(grad);
+             break;
+          }
+     }
+
+   if (result && result->ref)
+     {
+        EINA_LIST_FOREACH(grad_list, l, grad)
+          {
+             if (!strcmp(grad->id, result->ref))
+               {
+                  if (!result->stops)
+                    {
+                       result->stops = _clone_grad_stops(grad->stops);
+                    }
+                  //TODO properly inherit other property
+                  break;
+               }
+         }
+     }
+
+   return result;
+}
+
+void
+_update_gradient(Svg_Node *node, Eina_List *grad_list)
+{
+   Eina_List *l;
+   Svg_Node *child;
+
+   if (node->child)
+     {
+        EINA_LIST_FOREACH(node->child, l, child)
+          {
+             _update_gradient(child, grad_list);
+          }
+     }
+   else
+     {
+        if (node->style->fill.paint.url)
+          {
+             node->style->fill.paint.gradient = _dup_gradient(grad_list, node->style->fill.paint.url);
+          }
+        else if (node->style->stroke.paint.url)
+          {
+             node->style->stroke.paint.gradient = _dup_gradient(grad_list, node->style->stroke.paint.url);
+          }
+     }
+}
+
+Svg_Node *
+_svg_load(Eina_File *f, const char *key EINA_UNUSED)
+{
+   Evas_SVG_Loader loader = {
+     NULL, NULL, NULL, NULL, 0, EINA_FALSE
+   };
+   const char *content;
+   unsigned int length;
+   Svg_Node *defs;
+
+   if (!f) return NULL;
+
+   length = eina_file_size_get(f);
+   content = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+   if (content)
+     {
+       loader.stack = eina_array_new(8);
+       eina_simple_xml_parse(content, length, EINA_TRUE,
+                                 _evas_svg_loader_parser, &loader);
+
+       eina_array_free(loader.stack);
+       eina_file_map_free(f, (void*) content);
+     }
+
+   if (loader.doc)
+     {
+        _update_style(loader.doc, NULL);
+        defs = loader.doc->node.doc.defs;
+        if (defs)
+          _update_gradient(loader.doc, defs->node.defs.gradients);
+     }
+
+   return loader.doc;
+}
index 2e433e6..d5f1c26 100644 (file)
@@ -1236,7 +1236,8 @@ typedef enum _Edje_Part_Type
    EDJE_PART_TYPE_LIGHT     = 14,
    EDJE_PART_TYPE_CAMERA    = 15,
    EDJE_PART_TYPE_SNAPSHOT  = 16, /**< Snapshot @since 1.16 */
-   EDJE_PART_TYPE_LAST      = 17  /**< Last type value */
+   EDJE_PART_TYPE_VECTOR    = 17, /**< Vector @since 1.18 */
+   EDJE_PART_TYPE_LAST      = 18  /**< Last type value */
 } Edje_Part_Type;
 /**
  * @}
index 3806221..1724b32 100644 (file)
@@ -34,6 +34,7 @@ edje_cache_emp_alloc(Edje_Part_Collection_Directory_Entry *ce)
   INIT_EMP_BOTH(EXTERNAL, Edje_Part_Description_External, ce);
   INIT_EMP_BOTH(SPACER, Edje_Part_Description_Common, ce);
   INIT_EMP_BOTH(SNAPSHOT, Edje_Part_Description_Snapshot, ce);
+  INIT_EMP_BOTH(VECTOR, Edje_Part_Description_Vector, ce);
   INIT_EMP(part, Edje_Part, ce);
 }
 
@@ -53,6 +54,7 @@ edje_cache_emp_free(Edje_Part_Collection_Directory_Entry *ce)
   eina_mempool_del(ce->mp.EXTERNAL);
   eina_mempool_del(ce->mp.SPACER);
   eina_mempool_del(ce->mp.SNAPSHOT);
+  eina_mempool_del(ce->mp.VECTOR);
   eina_mempool_del(ce->mp.part);
   memset(&ce->mp, 0, sizeof (ce->mp));
 
index ef47b81..9737002 100644 (file)
@@ -413,6 +413,7 @@ case EDJE_PART_TYPE_##Short:                                          \
         EDIT_ALLOC_POOL_RTL(CAMERA, Camera, camera);
         EDIT_ALLOC_POOL_RTL(LIGHT, Light, light);
         EDIT_ALLOC_POOL_RTL(MESH_NODE, Mesh_Node, mesh_node);
+        EDIT_ALLOC_POOL_RTL(VECTOR, Vector, vector);
      }
 
    if (desc_rtl)
@@ -2858,6 +2859,7 @@ _edje_part_recalc_single(Edje *ed,
       case EDJE_PART_TYPE_LIGHT:
       case EDJE_PART_TYPE_CAMERA:
       case EDJE_PART_TYPE_SNAPSHOT:
+      case EDJE_PART_TYPE_VECTOR:
         break;
 
       case EDJE_PART_TYPE_GRADIENT:
@@ -3112,6 +3114,7 @@ _edje_proxy_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edj
            case EDJE_PART_TYPE_TABLE:
            case EDJE_PART_TYPE_PROXY:
            case EDJE_PART_TYPE_SNAPSHOT:
+           case EDJE_PART_TYPE_VECTOR:
              evas_object_image_source_set(ep->object, pp->object);
              break;
 
@@ -3208,6 +3211,32 @@ _edje_image_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edj
      evas_object_image_border_center_fill_set(ep->object, EVAS_BORDER_FILL_SOLID);
 }
 
+static void
+_edje_svg_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3 EINA_UNUSED, Edje_Part_Description_Vector *chosen_desc, FLOAT_T pos)
+{
+   int new_svg = 0;
+   int w, h;
+
+   evas_object_geometry_get(ep->object, NULL, NULL, &w, &h);
+   if( (w == 0) || (h == 0)) return;
+
+   if (ep->param2)
+     {
+        Edje_Part_Description_Vector *next_state = (Edje_Part_Description_Vector *)ep->param2->description;
+        if (chosen_desc->vg.id != next_state->vg.id)
+          {
+             new_svg = next_state->vg.id;
+          }
+        else
+          {
+             new_svg = 0;
+             pos = 0;
+          }
+          
+     }
+   evas_object_vg_path_set(ep->object, ed->file->path, chosen_desc->vg.id, new_svg, pos);
+}
+
 static Edje_Real_Part *
 _edje_real_part_state_get(Edje *ed, Edje_Real_Part *ep, int flags, int id, int *state)
 {
@@ -4494,6 +4523,7 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta
            case EDJE_PART_TYPE_BOX:
            case EDJE_PART_TYPE_TABLE:
            case EDJE_PART_TYPE_SNAPSHOT:
+           case EDJE_PART_TYPE_VECTOR:
              evas_object_color_set(ep->object,
                                    (pf->color.r * pf->color.a) / 255,
                                    (pf->color.g * pf->color.a) / 255,
@@ -4824,6 +4854,10 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta
              _edje_textblock_recalc_apply(ed, ep, pf, (Edje_Part_Description_Text *)chosen_desc);
              break;
 
+           case EDJE_PART_TYPE_VECTOR:
+             _edje_svg_recalc_apply(ed, ep, pf, (Edje_Part_Description_Vector *)chosen_desc, pos);
+             break;
+
            case EDJE_PART_TYPE_EXTERNAL:
            case EDJE_PART_TYPE_RECTANGLE:
            case EDJE_PART_TYPE_SWALLOW:
index 4316004..a491fd3 100644 (file)
@@ -285,6 +285,7 @@ case EDJE_PART_TYPE_##Tp: \
              CSP(BOX, ce);
              CSP(TABLE, ce);
              CSP(EXTERNAL, ce);
+             CSP(VECTOR, ce);
 
            default:
              count = &dummy;
@@ -308,6 +309,7 @@ case EDJE_PART_TYPE_##Tp: \
    CONVERT_EMN(TABLE, Edje_Part_Description_Table, ce);
    CONVERT_EMN(EXTERNAL, Edje_Part_Description_External, ce);
    CONVERT_EMN(part, Edje_Part, ce);
+   CONVERT_EMN(VECTOR, Edje_Part_Description_Vector, ce);
 
    /* Change structure layout */
    edc = calloc(1, sizeof (Edje_Part_Collection));
@@ -492,6 +494,7 @@ case EDJE_PART_TYPE_##Short:
         CONVERT_ALLOC_POOL(BOX, Box, box);
         CONVERT_ALLOC_POOL(TABLE, Table, table);
         CONVERT_ALLOC_POOL(EXTERNAL, External, external_params);
+        CONVERT_ALLOC_POOL(VECTOR, Vector, vector);
      }
 
    *result = oed->common;
index e00d011..b8e52df 100644 (file)
@@ -84,6 +84,16 @@ Eet_Data_Descriptor *_edje_edd_edje_map_colors = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_map_colors_pointer = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_filter = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_filter_directory = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_part_description_vector = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_part_description_vector_pointer = NULL;
+
+
+#define FREE_DESCRIPTOR(eed)                      \
+  if (eed)                              \
+    {                                   \
+       eet_data_descriptor_free((eed)); \
+       (eed) = NULL;                    \
+    }
 
 /* allocate a description struct.
  * this initializes clip_to_id as this field will not be present in most
@@ -125,6 +135,7 @@ EMP(MESH_NODE, mesh_node)
 EMP(LIGHT, light)
 EMP(CAMERA, camera)
 EMP(SNAPSHOT, snapshot)
+EMP(VECTOR, vector)
 #undef EMP
 
 EAPI Eina_Mempool *_emp_part = NULL;
@@ -174,7 +185,8 @@ struct
    { EDJE_PART_TYPE_MESH_NODE, "mesh_node" },
    { EDJE_PART_TYPE_LIGHT, "light" },
    { EDJE_PART_TYPE_CAMERA, "camera" },
-   { EDJE_PART_TYPE_SNAPSHOT, "snapshot" }
+   { EDJE_PART_TYPE_SNAPSHOT, "snapshot" },
+   { EDJE_PART_TYPE_VECTOR, "vector" }
 };
 
 static const char *
@@ -514,6 +526,7 @@ _edje_edd_init(void)
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection_directory_entry, Edje_Part_Collection_Directory_Entry, "count.CAMERA", count.CAMERA, EET_T_INT);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection_directory_entry, Edje_Part_Collection_Directory_Entry, "count.part", count.part, EET_T_INT);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection_directory_entry, Edje_Part_Collection_Directory_Entry, "group_alias", group_alias, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection_directory_entry, Edje_Part_Collection_Directory_Entry, "count.VECTOR", count.VECTOR, EET_T_INT);
 
    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Style_Tag);
    _edje_edd_edje_style_tag =
@@ -895,6 +908,17 @@ _edje_edd_init(void)
      eet_data_descriptor_file_new(&eddc);
    EDJE_DATA_DESCRIPTOR_DESCRIPTION_COMMON(_edje_edd_edje_part_description_rectangle, Edje_Part_Description_Common);
 
+   // SVG, since 1.18
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Description_Vector);
+   eddc.func.mem_free = mem_free_vector;
+   eddc.func.mem_alloc = mem_alloc_vector;
+   _edje_edd_edje_part_description_vector =
+     eet_data_descriptor_file_new(&eddc);
+   EDJE_DATA_DESCRIPTOR_DESCRIPTION_COMMON_SUB(_edje_edd_edje_part_description_vector, Edje_Part_Description_Vector, common);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_vector, Edje_Part_Description_Vector, "vg.id", vg.id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_vector, Edje_Part_Description_Vector, "vg.set", vg.set, EET_T_UCHAR);
+
+
    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Description_Common);
    eddc.func.mem_free = mem_free_spacer;
    eddc.func.mem_alloc = mem_alloc_spacer;
@@ -1180,6 +1204,7 @@ _edje_edd_init(void)
    EDJE_DEFINE_POINTER_TYPE(Part_Description_Mesh_Node, part_description_mesh_node);
    EDJE_DEFINE_POINTER_TYPE(Part_Description_Camera, part_description_camera);
    EDJE_DEFINE_POINTER_TYPE(Part_Description_Light, part_description_light);
+   EDJE_DEFINE_POINTER_TYPE(Part_Description_Vector, part_description_vector);
 
    eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
    eddc.func.type_get = _edje_description_variant_type_get;
@@ -1201,6 +1226,7 @@ _edje_edd_init(void)
    EET_DATA_DESCRIPTOR_ADD_MAPPING(_edje_edd_edje_part_description_variant, "mesh_node", _edje_edd_edje_part_description_mesh_node);
    EET_DATA_DESCRIPTOR_ADD_MAPPING(_edje_edd_edje_part_description_variant, "light", _edje_edd_edje_part_description_light);
    EET_DATA_DESCRIPTOR_ADD_MAPPING(_edje_edd_edje_part_description_variant, "camera", _edje_edd_edje_part_description_camera);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(_edje_edd_edje_part_description_variant, "vector", _edje_edd_edje_part_description_vector);
 
 #define EDJE_ADD_ARRAY_MAPPING(Variant, Type, Minus)                                     \
   {                                                                                      \
@@ -1230,6 +1256,7 @@ _edje_edd_init(void)
    EDJE_ADD_ARRAY_MAPPING(_edje_edd_edje_part_description_variant_list, "mesh_node", mesh_node);
    EDJE_ADD_ARRAY_MAPPING(_edje_edd_edje_part_description_variant_list, "light", light);
    EDJE_ADD_ARRAY_MAPPING(_edje_edd_edje_part_description_variant_list, "camera", camera);
+   EDJE_ADD_ARRAY_MAPPING(_edje_edd_edje_part_description_variant_list, "vector", vector);
 
    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Pack_Element);
    _edje_edd_edje_pack_element =
index 2fa00ed..bdb96a5 100644 (file)
@@ -3103,6 +3103,12 @@ _edje_edit_real_part_add(Evas_Object *obj, const char *name, Edje_Part_Type type
 
    if (ep->type == EDJE_PART_TYPE_RECTANGLE)
      rp->object = evas_object_rectangle_add(ed->base->evas);
+   else if (ep->type == EDJE_PART_TYPE_VECTOR)
+     {
+        rp->type = EDJE_PART_TYPE_VECTOR;
+        rp->typedata.vector = calloc(1, sizeof(Edje_Real_Part_Vector));
+        rp->object = evas_object_vg_add(ed->base->evas);
+     }
    else if (ep->type == EDJE_PART_TYPE_IMAGE || ep->type == EDJE_PART_TYPE_PROXY)
      rp->object = evas_object_image_add(ed->base->evas);
    else if (ep->type == EDJE_PART_TYPE_TEXT)
@@ -5491,6 +5497,7 @@ case EDJE_PART_TYPE_##Short:                                          \
         EDIT_ALLOC_POOL(BOX, Box, box);
         EDIT_ALLOC_POOL(TABLE, Table, table);
         EDIT_ALLOC_POOL(EXTERNAL, External, external_params);
+        EDIT_ALLOC_POOL(VECTOR, Vector, vector);
      }
 
    return pd;
index 0a04ec2..9ada9c0 100644 (file)
@@ -670,6 +670,12 @@ _edje_object_file_set_internal(Evas_Object *obj, const Eina_File *file, const ch
                        if (!rp->typedata.text) memerr = EINA_TRUE;
                        break;
 
+                     case EDJE_PART_TYPE_VECTOR:
+                       rp->type = EDJE_PART_TYPE_VECTOR;
+                       rp->typedata.vector = calloc(1, sizeof(Edje_Real_Part_Vector));
+                       if (!rp->typedata.vector) memerr = EINA_TRUE;
+                       break;
+
                      case EDJE_PART_TYPE_GROUP:
                      case EDJE_PART_TYPE_SWALLOW:
                      case EDJE_PART_TYPE_EXTERNAL:
@@ -715,6 +721,10 @@ _edje_object_file_set_internal(Evas_Object *obj, const Eina_File *file, const ch
                        rp->object = evas_object_rectangle_add(ed->base->evas);
                        break;
 
+                     case EDJE_PART_TYPE_VECTOR:
+                       rp->object = evas_object_vg_add(ed->base->evas);
+                       break;
+
                      case EDJE_PART_TYPE_PROXY:
                      case EDJE_PART_TYPE_IMAGE:
                        rp->object = evas_object_image_add(ed->base->evas);
@@ -1475,7 +1485,6 @@ _edje_file_del(Edje *ed, Eina_Bool reuse_ic)
    _edje_message_del(ed);
    _edje_block_violate(ed);
    _edje_var_shutdown(ed);
-
    if (!((ed->file) && (ed->collection)))
      {
         if (tev)
@@ -2225,3 +2234,6 @@ _cb_signal_repeat(void *data, Evas_Object *obj, const char *sig, const char *sou
                              EDJE_MESSAGE_SIGNAL, 0, &emsg);
 }
 
+
+
+
index 9253dbe..63021a2 100644 (file)
@@ -4982,6 +4982,7 @@ _edje_lua_open(lua_State *L)
    _edje_lua_new_const(L, "PART_TYPE_GRADIENT", EDJE_PART_TYPE_GRADIENT);
    _edje_lua_new_const(L, "PART_TYPE_GROUP", EDJE_PART_TYPE_GROUP);
    _edje_lua_new_const(L, "PART_TYPE_BOX", EDJE_PART_TYPE_BOX);
+   _edje_lua_new_const(L, "PART_TYPE_VECTOR", EDJE_PART_TYPE_VECTOR);
 
    _edje_lua_new_const(L, "TEXT_EFFECT_NONE", EDJE_TEXT_EFFECT_NONE);
    _edje_lua_new_const(L, "TEXT_EFFECT_PLAIN", EDJE_TEXT_EFFECT_PLAIN);
index 2424f58..0b8c613 100644 (file)
@@ -333,6 +333,7 @@ typedef struct _Edje_Mo                              Edje_Mo;
 typedef struct _Edje_Mo_Directory                    Edje_Mo_Directory;
 typedef struct _Edje_Gfx_Filter                      Edje_Gfx_Filter;
 typedef struct _Edje_Gfx_Filter_Directory            Edje_Gfx_Filter_Directory;
+typedef struct _Edje_Vector_Directory_Entry          Edje_Vector_Directory_Entry;
 
 typedef struct _Edje_Vibration_Sample                Edje_Vibration_Sample;
 typedef struct _Edje_Vibration_Directory             Edje_Vibration_Directory;
@@ -373,6 +374,10 @@ typedef struct _Edje_Physics_Face                    Edje_Physics_Face;
 typedef struct _Edje_Patterns                        Edje_Patterns;
 typedef struct _Edje_Part_Box_Animation              Edje_Part_Box_Animation;
 typedef struct _Edje_Part_Limit                      Edje_Part_Limit;
+typedef struct _Edje_Part_Description_Vector         Edje_Part_Description_Vector;
+typedef struct _Edje_Part_Description_Spec_Svg       Edje_Part_Description_Spec_Svg;
+typedef struct _Edje_Real_Part_Vector                Edje_Real_Part_Vector;
+typedef struct _Edje_Vector_Data                     Edje_Vector_Data;
 
 typedef struct _Edje Edje;
 typedef struct _Edje_Real_Part_Text Edje_Real_Part_Text;
@@ -630,7 +635,15 @@ struct _Edje_Image_Directory
    unsigned int entries_count;
 
    Edje_Image_Directory_Set *sets; /* an array of Edje_Image_Directory_Set */
+   Edje_Vector_Directory_Entry *vectors; /* an array of Edje_Image_Directory_Entry */
    unsigned int sets_count;
+   unsigned int vectors_count;
+};
+
+struct _Edje_Vector_Directory_Entry
+{
+   const char *entry; /* the nominal name of the vector image - if any */
+   int   id; /* the id no. of the image */
 };
 
 struct _Edje_Image_Directory_Entry
@@ -865,7 +878,8 @@ struct _Edje_Limit
       TYPE      MESH_NODE;        \
       TYPE      LIGHT;            \
       TYPE      CAMERA;           \
-      TYPE      SNAPSHOT;
+      TYPE      SNAPSHOT;         \
+      TYPE      VECTOR;
 
 struct _Edje_Part_Collection_Directory_Entry
 {
@@ -1518,6 +1532,12 @@ struct _Edje_Part_Description_Spec_Camera
    } orientation;
 };
 
+struct _Edje_Part_Description_Spec_Svg
+{
+   int            id; /* the svg id to use */
+   Eina_Bool      set; /* if vg condition it's content */
+};
+
 struct _Edje_Part_Description_Image
 {
    Edje_Part_Description_Common common;
@@ -1581,6 +1601,12 @@ struct _Edje_Part_Description_Camera
    Edje_Part_Description_Spec_Camera camera;
 };
 
+struct _Edje_Part_Description_Vector
+{
+   Edje_Part_Description_Common common;
+   Edje_Part_Description_Spec_Svg vg;
+};
+
 /*----------*/
 
 struct _Edje_Signal_Source_Char
@@ -1620,6 +1646,7 @@ struct _Edje
    Eina_List            *subobjs;
    Eina_List            *text_insert_filter_callbacks;
    Eina_List            *markup_filter_callbacks;
+   Eina_List            *vector_cache; /* list of Edje_Vector_Data */
 
    Eina_List            *groups;
 
@@ -1896,6 +1923,19 @@ struct _Edje_Real_Part_Swallow
    } swallow_params; // 28 // FIXME: only if type SWALLOW
 };
 
+struct _Edje_Vector_Data
+{
+   int svg_id;
+   double x, y, w, h;
+   Eina_Bool preserve_aspect;
+   Efl_VG *vg;
+};
+
+struct _Edje_Real_Part_Vector
+{
+   Edje_Vector_Data cur;
+};
+
 struct _Edje_Real_Part
 {
    Edje_Real_Part_State      param1; // 32
@@ -1918,6 +1958,7 @@ struct _Edje_Real_Part
       Edje_Real_Part_Text      *text;
       Edje_Real_Part_Container *container;
       Edje_Real_Part_Swallow   *swallow;
+      Edje_Real_Part_Vector    *vector;
    } typedata; // 4
    FLOAT_T                   description_pos; // 8
    Edje_Rectangle            req; // 16
@@ -2285,6 +2326,7 @@ EAPI extern Eina_Mempool *_emp_LIGHT;
 EAPI extern Eina_Mempool *_emp_CAMERA;
 EAPI extern Eina_Mempool *_emp_SNAPSHOT;
 EAPI extern Eina_Mempool *_emp_part;
+EAPI extern Eina_Mempool *_emp_VECTOR;
 
 void  _edje_part_pos_set(Edje *ed, Edje_Real_Part *ep, int mode, FLOAT_T pos, FLOAT_T v1, FLOAT_T v2, FLOAT_T v3, FLOAT_T v4);
 
index 2100b64..9743636 100644 (file)
@@ -1792,6 +1792,8 @@ EAPI Evas_Object *evas_object_rectangle_add(Evas *e) EINA_WARN_UNUSED_RESULT EIN
  */
 EAPI Evas_Object *evas_object_vg_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
 
+EAPI void evas_object_vg_path_set(Evas_Object *vg, const char *path, int src_vg, int dest_vg, float pos) EINA_ARG_NONNULL(1);
+
 #include "canvas/evas_vg.eo.legacy.h"
 
 /**
index e5b184d..90df47e 100644 (file)
@@ -5,6 +5,8 @@
 #include "evas_cs2_private.h"
 #endif
 
+#include "evas_vg_cache.h"
+
 #define MY_CLASS EVAS_CANVAS_CLASS
 
 #ifdef LKDEBUG
@@ -63,6 +65,7 @@ evas_init(void)
 #endif
    _evas_preload_thread_init();
    evas_filter_init();
+   evas_cache_svg_init();
 
    evas_thread_init();
 
@@ -104,6 +107,7 @@ evas_shutdown(void)
    if (evas_cserve2_use_get())
      evas_cserve2_shutdown();
 #endif
+   evas_cache_svg_shutdown();
 
    evas_font_path_global_clear();
    eina_cow_del(evas_object_proxy_cow);
index 6fcca7b..84de3c0 100644 (file)
@@ -4,6 +4,8 @@
 #include "evas_vg_private.h"
 #include "efl_vg_root_node.eo.h"
 
+#include "evas_vg_cache.h"
+
 #define MY_CLASS EVAS_VG_CLASS
 
 /* private magic number for rectangle objects */
@@ -18,7 +20,7 @@ struct _Evas_VG_Data
 {
    void   *engine_data;
    Efl_VG *root;
-
+   Svg_Entry *svg;
    Eina_Rectangle fill;
 
    unsigned int width, height;
@@ -90,6 +92,29 @@ evas_object_vg_add(Evas *e)
    return eo_obj;
 }
 
+EAPI void
+evas_object_vg_path_set(Eo *obj, const char *path, int src_vg,
+                        int dest_vg, float pos)
+{
+   int w, h;
+   Evas_VG_Data *pd;
+   Svg_Entry *entry;
+
+   if (!obj) return ;
+
+   evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+   pd = eo_data_scope_get(obj, MY_CLASS);
+   entry = evas_cache_svg_find(path, src_vg, dest_vg, pos, w, h);
+   if (entry != pd->svg)
+     {
+        if (pd->svg)
+          {
+             evas_cache_svg_entry_del(pd->svg);
+          }
+        pd->svg = entry;
+     }
+}
+
 Efl_VG *
 _evas_vg_root_node_get(Eo *obj EINA_UNUSED, Evas_VG_Data *pd)
 {
@@ -194,6 +219,68 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Evas_VG_Data *vd,
 }
 
 static void
+_svg_data_render(Evas_Object_Protected_Data *obj,
+                 Evas_VG_Data *vd,
+                 void *output, void *context, void *surface,
+                 int x, int y, Eina_Bool do_async)
+{
+   Svg_Entry *svg = vd->svg;
+   Efl_VG *root;
+   void *buffer;
+   Ector_Surface *ector;
+   RGBA_Draw_Context *ct;
+
+   // if the size changed in between path set and the draw call;
+   if (!(svg->w == obj->cur->geometry.w &&
+         svg->h == obj->cur->geometry.h))
+     {
+         evas_cache_svg_entry_del(svg);
+         svg = evas_cache_svg_find(svg->file, svg->src_vg, svg->dest_vg, 
+                                   svg->key_frame, obj->cur->geometry.w, obj->cur->geometry.h);
+         vd->svg = svg;
+     }
+   // if the buffer is not created yet
+   buffer = obj->layer->evas->engine.func->ector_surface_cache_get(output, svg->key);
+   if (!buffer)
+     {
+        root = evas_cache_svg_vg_tree_get(svg);
+        if (!root) return;
+        // manual render the vg tree
+        ector = evas_ector_get(obj->layer->evas);
+        if (!ector) return;
+        //1. render pre
+        _evas_vg_render_pre(root, ector, NULL);
+        // 2. create surface
+        buffer = obj->layer->evas->engine.func->ector_surface_create(output,
+                                                                     NULL,
+                                                                     svg->w,
+                                                                     svg->h);
+        //3. draw into the buffer
+        ct = evas_common_draw_context_new();
+        evas_common_draw_context_set_render_op(ct, _EVAS_RENDER_COPY);
+        evas_common_draw_context_set_color(ct, 255, 255, 255, 255);
+        obj->layer->evas->engine.func->ector_begin(output, ct,
+                                                   ector, buffer,
+                                                   0, 0,
+                                                   do_async);
+        _evas_vg_render(obj, vd,
+                        output, ct, buffer,
+                        root, NULL,
+                        do_async);
+        obj->layer->evas->engine.func->ector_end(output, ct, ector, buffer, do_async);
+
+        obj->layer->evas->engine.func->ector_surface_cache_set(output, svg->key, buffer);
+        evas_common_draw_context_free(ct);
+     }
+   // draw the buffer as image to canvas
+   obj->layer->evas->engine.func->image_draw(output, context, surface,
+                                             buffer, 0, 0,
+                                             obj->cur->geometry.w, obj->cur->geometry.h, obj->cur->geometry.x + x,
+                                             obj->cur->geometry.y + y, obj->cur->geometry.w, obj->cur->geometry.h,
+                                             EINA_TRUE, do_async);
+}
+
+static void
 evas_object_vg_render(Evas_Object *eo_obj EINA_UNUSED,
                       Evas_Object_Protected_Data *obj,
                       void *type_private_data,
@@ -202,11 +289,7 @@ evas_object_vg_render(Evas_Object *eo_obj EINA_UNUSED,
 {
    Evas_VG_Data *vd = type_private_data;
    Ector_Surface *ector = evas_ector_get(obj->layer->evas);
-   if (vd->content_changed || !vd->backing_store)
-     vd->backing_store = obj->layer->evas->engine.func->ector_surface_create(output,
-                                                                             vd->backing_store,
-                                                                             obj->cur->geometry.w,
-                                                                             obj->cur->geometry.h);
+
    // FIXME: Set context (that should affect Ector_Surface) and
    // then call Ector_Renderer render from bottom to top. Get the
    // Ector_Surface that match the output from Evas engine API.
@@ -231,6 +314,20 @@ evas_object_vg_render(Evas_Object *eo_obj EINA_UNUSED,
                                                          obj->cur->anti_alias);
    obj->layer->evas->engine.func->context_render_op_set(output, context,
                                                         obj->cur->render_op);
+
+   if (vd->svg)
+     {
+        _svg_data_render(obj, vd, output,
+                         context, surface,
+                         x, y, do_async);
+        return;
+     }
+
+   if (vd->content_changed || !vd->backing_store)
+     vd->backing_store = obj->layer->evas->engine.func->ector_surface_create(output,
+                                                                             vd->backing_store,
+                                                                             obj->cur->geometry.w,
+                                                                             obj->cur->geometry.h);
    if (!vd->backing_store)
      {
         obj->layer->evas->engine.func->ector_begin(output, context, ector, surface,
index b925b7a..97597f2 100755 (executable)
@@ -527,6 +527,15 @@ typedef enum _Evas_Font_Weight              Evas_Font_Weight;
 typedef enum _Evas_Font_Width               Evas_Font_Width;
 typedef enum _Evas_Font_Spacing             Evas_Font_Spacing;
 
+// ector cache
+typedef struct _Ector_Surface_Cache Ector_Surface_Cache;
+
+struct _Ector_Surface_Cache
+{
+   Eina_Hash    *suface_hash;
+   void         *output;
+};
+
 /* General types - used for script type chceking */
 #define OPAQUE_TYPE(type) struct __##type { int a; }; \
    typedef struct __##type type
@@ -1463,6 +1472,8 @@ struct _Evas_Func
    void  (*ector_renderer_draw)          (void *data, void *context, void *surface, Ector_Renderer *r, Eina_Array *clips, Eina_Bool do_async);
    void  (*ector_end)                    (void *data, void *context, Ector_Surface *ector, void *surface, Eina_Bool do_async);
    void *(*ector_surface_create)          (void *data, void *surface, int w, int h);
+   void  (*ector_surface_cache_set)      (void *data, const char *key, void *surface);
+   void *(*ector_surface_cache_get)      (void *data, const char *key);
 };
 
 struct _Evas_Image_Save_Func
diff --git a/src/lib/evas/vg/evas_vg_cache.c b/src/lib/evas/vg/evas_vg_cache.c
new file mode 100644 (file)
index 0000000..e84a738
--- /dev/null
@@ -0,0 +1,146 @@
+#include "evas_vg_cache.h"
+#include "evas_vg_common.h"
+
+static Evas_Cache_Svg* svg_cache = NULL;
+
+static void
+_evas_cache_vg_data_free_cb(void *data)
+{
+   Vg_Data *val = data;
+
+   eo_del(val->vg);
+   free(val);
+}
+
+static void
+_evas_cache_svg_entry_free_cb(void *data)
+{
+   Svg_Entry *entry = data;
+
+   eina_stringshare_del(entry->file);
+   free(entry->key);
+   eo_del(entry->root);
+   free(entry);
+}
+
+void
+evas_cache_svg_init(void)
+{
+   if (svg_cache)
+     {
+        svg_cache->ref++;
+        return;
+     }
+
+   svg_cache =  calloc(1, sizeof(Evas_Cache_Svg));
+   svg_cache->vg_hash = eina_hash_string_superfast_new(_evas_cache_vg_data_free_cb);
+   svg_cache->active = eina_hash_string_superfast_new(_evas_cache_svg_entry_free_cb);
+   svg_cache->ref++;
+}
+
+void
+evas_cache_svg_shutdown(void)
+{
+   if (!svg_cache) return;
+   svg_cache->ref--;
+   if (svg_cache->ref) return;
+   _evas_vg_svg_node_eet_destroy();
+   eina_hash_free(svg_cache->vg_hash);
+   eina_hash_free(svg_cache->active);
+   svg_cache = NULL;
+}
+
+static Vg_Data *
+_evas_cache_vg_data_find(const char *path, int vg_id)
+{
+   Vg_Data *vd;
+   Eina_Strbuf *key;
+
+   key = eina_strbuf_new();
+   eina_strbuf_append_printf(key, "%s/%d", path, vg_id);
+   vd = eina_hash_find(svg_cache->vg_hash, eina_strbuf_string_get(key));
+   if (!vd)
+     {
+        vd = _evas_vg_load_vg_data(path, vg_id);
+        eina_hash_add(svg_cache->vg_hash, eina_strbuf_string_get(key), vd);
+     }
+   eina_strbuf_free(key);
+   return vd;
+}
+
+static void
+_evas_cache_svg_vg_tree_update(Svg_Entry *entry)
+{
+   Vg_Data *src_vg = NULL, *dst_vg = NULL;
+   if(!entry) return;
+
+   if (!entry->src_vg)
+     {
+        entry->root = NULL;
+        return;
+     } 
+
+   if (!entry->dest_vg)
+     {
+        src_vg = _evas_cache_vg_data_find(entry->file, entry->src_vg);
+     }
+   else
+     {
+        dst_vg = _evas_cache_vg_data_find(entry->file, entry->dest_vg);
+     }
+   entry->root = _evas_vg_dup_vg_tree(src_vg, dst_vg, entry->key_frame, entry->w, entry->h);
+   eina_stringshare_del(entry->file);
+   entry->file = NULL;
+}
+
+Svg_Entry*
+evas_cache_svg_find(const char *path,
+                    int src_vg, int dest_vg,
+                    float key_frame, int w, int h)
+{
+   Svg_Entry* se;
+   Eina_Strbuf *key;
+
+   if (!svg_cache) return NULL;
+
+   key = eina_strbuf_new();
+   eina_strbuf_append_printf(key, "%s/%d/%d/%.2f/%d/%d",
+                             path, src_vg, dest_vg, key_frame, w, h);
+   se = eina_hash_find(svg_cache->active, eina_strbuf_string_get(key));
+   if (!se)
+     {
+        se = calloc(1, sizeof(Svg_Entry));
+        se->file = eina_stringshare_add(path);
+        se->key_frame = key_frame;
+        se->src_vg = src_vg;
+        se->dest_vg = dest_vg;
+        se->w = w;
+        se->h = h;
+        se->key = eina_strbuf_string_steal(key);
+        eina_hash_direct_add(svg_cache->active, se->key, se);
+     }
+   eina_strbuf_free(key);
+   se->ref++;
+   return se;
+}
+
+Efl_VG*
+evas_cache_svg_vg_tree_get(Svg_Entry *entry)
+{
+   if (entry->root) return entry->root;
+
+   if (entry->file)
+     {
+        _evas_cache_svg_vg_tree_update(entry);
+     }
+   return entry->root;
+}
+
+void
+evas_cache_svg_entry_del(Svg_Entry *svg_entry)
+{
+   if (!svg_entry) return;
+
+   svg_entry->ref--;
+}
+
diff --git a/src/lib/evas/vg/evas_vg_cache.h b/src/lib/evas/vg/evas_vg_cache.h
new file mode 100644 (file)
index 0000000..2d41cac
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _EVAS_CACHE_SVG_H
+#define _EVAS_CACHE_SVG_H
+
+#include <Evas.h>
+
+typedef struct _Svg_Entry             Svg_Entry;
+typedef struct _Evas_Cache_Svg        Evas_Cache_Svg;
+
+struct _Evas_Cache_Svg
+{
+   Eina_Hash             *vg_hash;
+   Eina_Hash             *active;
+   int                    ref;
+};
+
+struct _Svg_Entry
+{
+   Eina_Stringshare     *file;
+   char                 *key;
+   int                   src_vg;
+   int                   dest_vg;
+   float                 key_frame;
+   int                   w;
+   int                   h;
+   Efl_VG               *root;
+   int                   ref;
+};
+
+void              evas_cache_svg_init(void);
+void              evas_cache_svg_shutdown(void);
+Svg_Entry*        evas_cache_svg_find(const char *path,
+                                      int src_svg, int dest_svg,
+                                      float key_frame, int w, int h);
+Efl_VG*           evas_cache_svg_vg_tree_get(Svg_Entry *svg_entry);
+void              evas_cache_svg_entry_del(Svg_Entry *svg_entry);
+
+#endif /* _EVAS_CACHE_SVG_H */
\ No newline at end of file
diff --git a/src/lib/evas/vg/evas_vg_common.h b/src/lib/evas/vg/evas_vg_common.h
new file mode 100644 (file)
index 0000000..8052e4f
--- /dev/null
@@ -0,0 +1,317 @@
+#ifndef EVAS_VG_COMMON_H_
+# define EVAS_VG_COMMON_H_
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Eet.h>
+#include <Evas.h>
+
+
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EVAS_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_EVAS_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+// Svg Node
+typedef enum _Svg_Node_Type Svg_Node_Type;
+typedef enum _Svg_Length_Type Svg_Length_Type;
+
+typedef struct _Svg_Node Svg_Node;
+typedef struct _Svg_Doc_Node Svg_Doc_Node;
+typedef struct _Svg_G_Node Svg_G_Node;
+typedef struct _Svg_Defs_Node Svg_Defs_Node;
+typedef struct _Svg_Arc_Node Svg_Arc_Node;
+typedef struct _Svg_Circle_Node Svg_Circle_Node;
+typedef struct _Svg_Ellipse_Node Svg_Ellipse_Node;
+typedef struct _Svg_Polygon_Node Svg_Polygon_Node;
+typedef struct _Svg_Rect_Node Svg_Rect_Node;
+typedef struct _Svg_Path_Node Svg_Path_Node;
+typedef struct _Svg_Style_Property Svg_Style_Property;
+
+typedef struct  _Svg_Style_Stroke   Svg_Style_Stroke;
+typedef struct  _Svg_Style_Fill     Svg_Style_Fill;
+typedef enum    _Svg_Fill_Flags     Svg_Fill_Flags;
+typedef enum    _Svg_Stroke_Flags   Svg_Stroke_Flags;
+
+
+typedef enum   _Svg_Gradient_Type   Svg_Gradient_Type;
+typedef struct _Svg_Style_Gradient  Svg_Style_Gradient;
+typedef struct _Svg_Linear_Gradient Svg_Linear_Gradient;
+typedef struct _Svg_Radial_Gradient Svg_Radial_Gradient;
+typedef struct _Svg_Paint           Svg_Paint;
+
+typedef struct _Vg_Data             Vg_Data;
+
+enum _Svg_Node_Type
+{
+   SVG_NODE_DOC,
+   SVG_NODE_G,
+   SVG_NODE_DEFS,
+   SVG_NODE_SWITCH,
+   SVG_NODE_ANIMATION,
+   SVG_NODE_ARC,
+   SVG_NODE_CIRCLE,
+   SVG_NODE_ELLIPSE,
+   SVG_NODE_IMAGE,
+   SVG_NODE_LINE,
+   SVG_NODE_PATH,
+   SVG_NODE_POLYGON,
+   SVG_NODE_POLYLINE,
+   SVG_NODE_RECT,
+   SVG_NODE_TEXT,
+   SVG_NODE_TEXTAREA,
+   SVG_NODE_TSPAN,
+   SVG_NODE_USE,
+   SVG_NODE_VIDEO,
+   SVG_NODE_UNKNOWN
+};
+
+enum _Svg_Length_Type
+{
+   SVG_LT_PERCENT,
+   SVG_LT_PX,
+   SVG_LT_PC,
+   SVG_LT_PT,
+   SVG_LT_MM,
+   SVG_LT_CM,
+   SVG_LT_IN,
+};
+
+struct _Svg_Doc_Node
+{
+   double width;
+   double height;
+   double vx;
+   double vy;
+   double vw;
+   double vh;
+   Svg_Node *defs;
+};
+
+struct _Svg_G_Node
+{
+
+};
+
+struct _Svg_Defs_Node
+{
+   Eina_List   *gradients;
+};
+
+struct _Svg_Arc_Node
+{
+
+};
+
+struct _Svg_Ellipse_Node
+{
+   double cx;
+   double cy;
+   double rx;
+   double ry;
+};
+
+struct _Svg_Circle_Node
+{
+   double cx;
+   double cy;
+   double r;
+};
+
+struct _Svg_Rect_Node
+{
+   double x;
+   double y;
+   double w;
+   double h;
+   double rx;
+   double ry;
+};
+
+struct _Svg_Path_Node
+{
+   Eina_Stringshare *path;
+};
+
+struct _Svg_Polygon_Node
+{
+   int points_count;
+   double *points;
+};
+
+
+enum _Svg_Gradient_Type
+{
+   SVG_LINEAR_GRADIENT,
+   SVG_RADIAL_GRADIENT
+};
+struct _Svg_Linear_Gradient
+{
+   double x1;
+   double y1;
+   double x2;
+   double y2;
+};
+
+struct _Svg_Radial_Gradient
+{
+   double cx;
+   double cy;
+   double fx;
+   double fy;
+   double r;
+};
+
+struct _Svg_Style_Gradient
+{
+   Svg_Gradient_Type type;
+   Eina_Stringshare  *id;
+   Eina_Stringshare  *ref;
+   Efl_Gfx_Gradient_Spread spread;
+   Eina_List   *stops; // Efl_Gfx_Gradient_Stop
+   Svg_Radial_Gradient *radial;
+   Svg_Linear_Gradient *linear;
+};
+
+struct _Svg_Paint
+{
+   int        r;
+   int        g;
+   int        b;
+   Eina_Bool  none;
+   Eina_Bool  cur_color;
+   Svg_Style_Gradient  *gradient;
+   Eina_Stringshare    *url;
+};
+
+enum _Svg_Fill_Flags
+{
+   SVG_FILL_FLAGS_PAINT     = 0x1,
+   SVG_FILL_FLAGS_OPACITY   = 0x2,
+   SVG_FILL_FLAGS_GRADIENT  = 0x4,
+   SVG_FILL_FLAGS_FILL_RULE = 0x8
+};
+
+enum _Svg_Stroke_Flags
+{
+   SVG_STROKE_FLAGS_PAINT    = 0x1,
+   SVG_STROKE_FLAGS_OPACITY  = 0x2,
+   SVG_STROKE_FLAGS_GRADIENT = 0x4,
+   SVG_STROKE_FLAGS_SCALE    = 0x8,
+   SVG_STROKE_FLAGS_WIDTH    = 0x10,
+   SVG_STROKE_FLAGS_CAP      = 0x20,
+   SVG_STROKE_FLAGS_JOIN     = 0x40,
+   SVG_STROKE_FLAGS_DASH     = 0x80,
+};
+
+struct _Svg_Style_Fill
+{
+   Svg_Fill_Flags       flags;
+   Svg_Paint            paint;
+   int                  opacity;
+   Efl_Gfx_Fill_Rule    fill_rule;
+};
+
+struct _Svg_Style_Stroke
+{
+   Svg_Stroke_Flags     flags;
+   Svg_Paint            paint;
+   int                  opacity;
+   double               scale;
+   double               width;
+   double               centered;
+   Efl_Gfx_Cap          cap;
+   Efl_Gfx_Join         join;
+   Efl_Gfx_Dash        *dash;
+   int                  dash_count;
+};
+
+struct _Svg_Style_Property
+{
+   Svg_Style_Fill     fill;
+   Svg_Style_Stroke   stroke;
+   // the color property indirectly 
+   // used by fill and stroke
+   int                r;
+   int                g;
+   int                b;
+};
+
+struct _Svg_Node
+{
+   Svg_Node_Type        type;
+   Svg_Node            *parent;
+   Eina_List           *child;
+   Eina_Stringshare    *id;
+   Svg_Style_Property  *style;
+   Eina_Matrix3        *transform;
+   union
+     {
+        Svg_G_Node   g;
+        Svg_Doc_Node doc;
+        Svg_Defs_Node defs;
+        Svg_Arc_Node arc;
+        Svg_Circle_Node circle;
+        Svg_Ellipse_Node ellipse;
+        Svg_Polygon_Node polygon;
+        Svg_Rect_Node rect;
+        Svg_Path_Node path;
+     }node;
+};
+
+enum _Svg_Style_Type
+{
+   SVG_STYLE_QUALITY,
+   SVG_STYLE_FILL,
+   SVG_STYLE_VIEWPORT_FILL,
+   SVG_STYLE_FONT,
+   SVG_STYLE_STROKE,
+   SVG_STYLE_SOLID_COLOR,
+   SVG_STYLE_GRADIENT,
+   SVG_STYLE_TRANSFORM,
+   SVG_STYLE_OPACITY,
+   SVG_STYLE_COMP_OP
+};
+
+struct _Vg_Data
+{
+   int svg_id;
+   double x, y, w, h;
+   Eina_Bool preserve_aspect;
+   Efl_VG *vg;
+};
+
+EAPI Eet_Data_Descriptor * _evas_vg_svg_node_eet(void);
+EAPI void _evas_vg_svg_node_eet_destroy(void);
+EAPI void _evas_vg_svg_node_free(Svg_Node *node);
+Vg_Data * _evas_vg_load_vg_data(Eina_Stringshare *path, int svg_id);
+Efl_VG * _evas_vg_dup_vg_tree(Vg_Data *src, Vg_Data *dst, float pos, double w, double h);
+
+#undef EAPI
+#define EAPI
+
+#endif //EVAS_VG_COMMON_H_
\ No newline at end of file
diff --git a/src/lib/evas/vg/evas_vg_eet_handler.c b/src/lib/evas/vg/evas_vg_eet_handler.c
new file mode 100644 (file)
index 0000000..df9ec5f
--- /dev/null
@@ -0,0 +1,789 @@
+#include "evas_vg_common.h"
+
+Eet_Data_Descriptor *_edje_edd_edje_rect_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_circle_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_ellipse_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_gradient_stops_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_linear_gradient_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_radial_gradient_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_style_gradient_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_style_property_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_matrix3_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_doc_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_defs_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_g_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_arc_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_path_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_polygon_node = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_vg_node = NULL;
+
+#define FREE_DESCRIPTOR(eed)                      \
+  if (eed)                              \
+    {                                   \
+       eet_data_descriptor_free((eed)); \
+       (eed) = NULL;                    \
+    }
+
+static inline Eet_Data_Descriptor*
+_eet_for_rect_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Rect_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "x", x, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "y", y, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "w", w, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "h", h, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "rx", rx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "ry", ry, EET_T_DOUBLE);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_circle_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Circle_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Circle_Node, "cx", cx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Circle_Node, "cy", cy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Circle_Node, "r", r, EET_T_DOUBLE);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_ellipse_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Ellipse_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "cx", cx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "cy", cy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "rx", rx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "ry", ry, EET_T_DOUBLE);
+   return eet;
+}
+
+
+static inline Eet_Data_Descriptor*
+_eet_for_gradient_stops(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Efl_Gfx_Gradient_Stop);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "offset", offset, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "r", r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "g", g, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "b", b, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "a", a, EET_T_INT);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_linear_gradient(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Linear_Gradient);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "x1", x1, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "y1", y1, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "x2", x2, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "y2", y2, EET_T_DOUBLE);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_radial_gradient(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Radial_Gradient);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "cx", cx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "cy", cy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "fx", fx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "fy", fy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "r", r, EET_T_DOUBLE);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_style_gradient(void)
+{
+   Eet_Data_Descriptor_Class eetc;
+
+   if (_edje_edd_edje_style_gradient_node) return _edje_edd_edje_style_gradient_node;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Style_Gradient);
+   _edje_edd_edje_style_gradient_node = eet_data_descriptor_stream_new(&eetc);
+   _edje_edd_edje_gradient_stops_node = _eet_for_gradient_stops();
+   _edje_edd_edje_linear_gradient_node = _eet_for_linear_gradient();
+   _edje_edd_edje_radial_gradient_node = _eet_for_radial_gradient();
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "type", type, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "id", id, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "spread", spread, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "stops", stops, _edje_edd_edje_gradient_stops_node);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "radial", radial, _edje_edd_edje_radial_gradient_node);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "linear", linear, _edje_edd_edje_linear_gradient_node);
+
+   return _edje_edd_edje_style_gradient_node;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_style_property(void)
+{
+   Eet_Data_Descriptor *eet, *eet_gradient, *eet_dash;
+   Eet_Data_Descriptor_Class eetc, eetc_dash;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Style_Property);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   eet_gradient = _eet_for_style_gradient();
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc_dash, Efl_Gfx_Dash);
+   eet_dash = eet_data_descriptor_stream_new(&eetc_dash);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet_dash, Efl_Gfx_Dash, "length", length, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet_dash, Efl_Gfx_Dash, "gap", gap, EET_T_DOUBLE);
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "r", r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "g", g, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "b", b, EET_T_INT);
+   // for fill
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.flags", fill.flags, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.r", fill.paint.r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.g", fill.paint.g, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.b", fill.paint.b, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.none", fill.paint.none, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.cur_color", fill.paint.cur_color, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_SUB(eet, Svg_Style_Property, "fill.paint.gradient", fill.paint.gradient, eet_gradient);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.url", fill.paint.url, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.opacity", fill.opacity, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.fill_rule", fill.fill_rule, EET_T_INT);
+
+   // for stroke
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.flags", stroke.flags, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.r", stroke.paint.r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.g", stroke.paint.g, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.b", stroke.paint.b, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.none", stroke.paint.none, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.cur_color", stroke.paint.cur_color, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_SUB(eet, Svg_Style_Property, "stroke.paint.gradient", stroke.paint.gradient, eet_gradient);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.url", stroke.paint.url, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.opacity", stroke.opacity, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.scale", stroke.scale, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.width", stroke.width, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.centered", stroke.centered, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.cap", stroke.cap, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.join", stroke.join, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(eet, Svg_Style_Property, "stroke.dash", stroke.dash, eet_dash);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.dash_count", stroke.dash_count, EET_T_INT);
+
+   return eet;
+}
+
+static Eet_Data_Descriptor*
+_eet_for_eina_matrix3(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Eina_Matrix3);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "xx", xx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "xy", xy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "xz", xz, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "yx", yx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "yy", yy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "yz", yz, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "zx", zx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "zy", zy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "zz", zz, EET_T_DOUBLE);
+
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_doc_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Doc_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "width", width, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "height", height, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vx", vx, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vy", vy, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vw", vw, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vh", vh, EET_T_DOUBLE);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_defs_node(void)
+{
+   Eet_Data_Descriptor *eet, *eet_gradient;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Defs_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   eet_gradient = _eet_for_style_gradient();
+
+   EET_DATA_DESCRIPTOR_ADD_LIST(eet, Svg_Defs_Node, "gradients", gradients, eet_gradient);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_g_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_G_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_arc_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Arc_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_polygon_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Polygon_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC_VAR_ARRAY(eet, Svg_Polygon_Node, "points", points, EET_T_DOUBLE);
+   return eet;
+}
+
+static inline Eet_Data_Descriptor*
+_eet_for_path_node(void)
+{
+   Eet_Data_Descriptor *eet;
+   Eet_Data_Descriptor_Class eetc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Path_Node);
+   eet = eet_data_descriptor_stream_new(&eetc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Path_Node, "path", path, EET_T_STRING);
+   return eet;
+}
+
+struct
+{
+   Svg_Node_Type u;
+   const char       *name;
+} eet_mapping[] = {
+   { SVG_NODE_DOC, "doc" },
+   { SVG_NODE_G, "g" },
+   { SVG_NODE_DEFS, "defs" },
+   { SVG_NODE_ARC, "arc" },
+   { SVG_NODE_CIRCLE, "circle" },
+   { SVG_NODE_ELLIPSE, "ellipse" },
+   { SVG_NODE_POLYGON, "polygon" },
+   { SVG_NODE_POLYLINE, "polygon" },
+   { SVG_NODE_RECT, "rect" },
+   { SVG_NODE_PATH, "path" },
+   { SVG_NODE_UNKNOWN, NULL }
+};
+
+static const char *
+/* union
+   type_get() */
+_union_type_get(const void *data,
+                Eina_Bool  *unknow)
+{
+   const Svg_Node_Type *u = data;
+   int i;
+
+   if (unknow)
+     *unknow = EINA_FALSE;
+
+   for (i = 0; eet_mapping[i].name != NULL; ++i)
+     if (*u == eet_mapping[i].u)
+       return eet_mapping[i].name;
+
+   if (unknow)
+     *unknow = EINA_TRUE;
+   return NULL;
+} /* _union_type_get */
+
+static Eina_Bool
+_union_type_set(const char *type,
+                void       *data,
+                Eina_Bool   unknow)
+{
+   Svg_Node_Type *u = data;
+   int i;
+
+   if (unknow)
+     return EINA_FALSE;
+
+   for (i = 0; eet_mapping[i].name != NULL; ++i)
+     if (strcmp(eet_mapping[i].name, type) == 0)
+       {
+          *u = eet_mapping[i].u;
+          return EINA_TRUE;
+       }
+   return EINA_FALSE;
+} /* _union_type_set */
+
+EAPI Eet_Data_Descriptor *
+_evas_vg_svg_node_eet(void)
+{
+   Eet_Data_Descriptor *eet_union;
+   Eet_Data_Descriptor_Class eetc;
+
+   if (_edje_edd_edje_vg_node) return _edje_edd_edje_vg_node;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Node);
+   _edje_edd_edje_vg_node = eet_data_descriptor_stream_new(&eetc);
+
+   eetc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
+   eetc.func.type_get = _union_type_get;
+   eetc.func.type_set = _union_type_set;
+   eet_union = eet_data_descriptor_stream_new(&eetc);
+
+   _edje_edd_edje_doc_node = _eet_for_doc_node();
+   _edje_edd_edje_g_node = _eet_for_g_node();
+   _edje_edd_edje_defs_node = _eet_for_defs_node();
+   _edje_edd_edje_arc_node = _eet_for_arc_node();
+   _edje_edd_edje_circle_node = _eet_for_circle_node();
+   _edje_edd_edje_ellipse_node = _eet_for_ellipse_node();
+   _edje_edd_edje_rect_node = _eet_for_rect_node();
+   _edje_edd_edje_path_node = _eet_for_path_node();
+   _edje_edd_edje_polygon_node = _eet_for_polygon_node();
+   _edje_edd_edje_style_property_node = _eet_for_style_property();
+   _edje_edd_edje_matrix3_node = _eet_for_eina_matrix3();
+
+
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "doc", _edje_edd_edje_doc_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "g", _edje_edd_edje_g_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "defs", _edje_edd_edje_defs_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "arc", _edje_edd_edje_arc_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "circle", _edje_edd_edje_circle_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "ellipse", _edje_edd_edje_ellipse_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "rect", _edje_edd_edje_rect_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "path", _edje_edd_edje_path_node);
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "polygon", _edje_edd_edje_polygon_node);
+
+   EET_DATA_DESCRIPTOR_ADD_UNION(_edje_edd_edje_vg_node, Svg_Node, "node", node, type, eet_union);
+
+
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_vg_node, Svg_Node, "child", child, _edje_edd_edje_vg_node);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_vg_node, Svg_Node, "id", id, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_vg_node, Svg_Node, "style", style, _edje_edd_edje_style_property_node);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_vg_node, Svg_Node, "transform", transform, _edje_edd_edje_matrix3_node);
+
+   return _edje_edd_edje_vg_node;
+}
+
+EAPI void 
+_evas_vg_svg_node_eet_destroy(void)
+{
+   FREE_DESCRIPTOR(_edje_edd_edje_rect_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_circle_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_ellipse_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_gradient_stops_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_linear_gradient_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_radial_gradient_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_style_gradient_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_style_property_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_matrix3_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_doc_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_defs_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_g_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_arc_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_path_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_polygon_node);
+   FREE_DESCRIPTOR(_edje_edd_edje_vg_node);
+}
+
+
+
+static Efl_VG *
+_apply_gradient_property(Svg_Style_Gradient *g)
+{
+   Efl_VG *grad_obj = NULL;
+   Efl_Gfx_Gradient_Stop *stops, *stop;
+   int stop_count = 0, i = 0;
+   Eina_List *l;
+
+   if (g->type == SVG_LINEAR_GRADIENT)
+     {
+        grad_obj = eo_add(EFL_VG_GRADIENT_LINEAR_CLASS, NULL);
+        evas_vg_gradient_linear_start_set(grad_obj, g->linear->x1, g->linear->y1);
+        evas_vg_gradient_linear_end_set(grad_obj, g->linear->x2, g->linear->y2);
+     }
+   else if (g->type == SVG_RADIAL_GRADIENT)
+     {
+        grad_obj = eo_add(EFL_VG_GRADIENT_RADIAL_CLASS, NULL);
+        evas_vg_gradient_radial_center_set(grad_obj, g->radial->cx, g->radial->cy);
+        evas_vg_gradient_radial_radius_set(grad_obj, g->radial->r);
+        evas_vg_gradient_radial_focal_set(grad_obj, g->radial->fx, g->radial->fy);
+     }
+   else
+     {
+        // not a known gradient
+        return NULL;
+     }
+   // apply common prperty
+   evas_vg_gradient_spread_set(grad_obj, g->spread);
+   // update the stops
+   stop_count = eina_list_count(g->stops);
+   if (stop_count)
+     {
+        stops = calloc(stop_count, sizeof(Efl_Gfx_Gradient_Stop));
+        i = 0;
+        EINA_LIST_FOREACH(g->stops, l, stop)
+          {
+             stops[i].r = stop->r;
+             stops[i].g = stop->g;
+             stops[i].b = stop->b;
+             stops[i].a = stop->a;
+             stops[i].offset = stop->offset;
+             i++;
+          }
+        evas_vg_gradient_stop_set(grad_obj, stops, stop_count);
+        free(stops);
+     }
+   return grad_obj;
+}
+
+// vg tree creation
+static void
+_apply_vg_property(Svg_Node *node, Efl_VG *vg)
+{
+   Svg_Style_Property *style = node->style;
+
+   // update the vg name
+   if (node->id)
+     evas_vg_node_name_set(vg, node->id);
+
+   // apply the transformation
+   if (node->transform)
+     evas_vg_node_transformation_set(vg, node->transform);
+
+   if (node->type == SVG_NODE_G) return;
+
+   // apply the fill style property
+   eo_do(vg, efl_gfx_shape_fill_rule_set(style->fill.fill_rule));
+   // if fill property is NULL then do nothing
+   if (style->fill.paint.none)
+     {
+        //do nothing
+     }
+   else if (style->fill.paint.gradient)
+     {
+        // if the fill has gradient then apply.
+        evas_vg_shape_fill_set(vg, _apply_gradient_property(style->fill.paint.gradient));
+     }
+   else if (style->fill.paint.cur_color)
+     {
+        // apply the current style color
+        evas_vg_node_color_set(vg, style->r, style->g,
+                               style->b, style->fill.opacity);
+     }
+   else
+     {
+        // apply the fill color
+        evas_vg_node_color_set(vg, style->fill.paint.r, style->fill.paint.g,
+                               style->fill.paint.b, style->fill.opacity);
+     }
+
+   // apply the stroke style property
+   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);
+   evas_vg_shape_stroke_scale_set(vg, style->stroke.scale);
+   // if stroke property is NULL then do nothing
+   if (style->stroke.paint.none)
+     {
+        //do nothing
+     }
+   else if (style->stroke.paint.gradient)
+     {
+        // if the fill has gradient then apply.
+        evas_vg_shape_stroke_fill_set(vg, _apply_gradient_property(style->stroke.paint.gradient));
+     }
+   else if (style->stroke.paint.url)
+     {
+        // apply the color pointed by url
+        // TODO
+     }
+   else if (style->stroke.paint.cur_color)
+     {
+        // apply the current style color
+        evas_vg_shape_stroke_color_set(vg, style->r, style->g,
+                                       style->b, style->stroke.opacity);
+     }
+   else
+     {
+        // apply the stroke color
+        evas_vg_shape_stroke_color_set(vg, style->stroke.paint.r, style->stroke.paint.g,
+                                       style->stroke.paint.b, style->stroke.opacity);
+     }
+}
+
+static void
+_add_polyline(Efl_VG *vg, double *array, int size, Eina_Bool polygon)
+{
+   int i;
+
+   if (size < 2) return;
+
+   evas_vg_shape_shape_append_move_to(vg, array[0], array[1]);
+   for (i=2; i < size; i+=2)
+     evas_vg_shape_shape_append_line_to(vg, array[i], array[i+1]);
+
+   if (polygon)
+     evas_vg_shape_shape_append_close(vg);
+}
+
+static void
+_create_vg_node(Svg_Node *node, Efl_VG *parent)
+{
+   Efl_VG *vg = NULL;
+   Svg_Node *child;
+   Eina_List *l;
+
+   switch (node->type)
+     {
+        case SVG_NODE_G:
+           {
+              vg = evas_vg_container_add(parent);
+              _apply_vg_property(node, vg);
+              EINA_LIST_FOREACH(node->child, l, child)
+                {
+                   _create_vg_node(child, vg);
+                }
+              return;
+           }
+           break;
+        case SVG_NODE_PATH:
+           vg = evas_vg_shape_add(parent);
+           evas_vg_shape_shape_append_svg_path(vg, node->node.path.path);
+           break;
+        case SVG_NODE_POLYGON:
+           vg = evas_vg_shape_add(parent);
+           _add_polyline(vg, node->node.polygon.points, node->node.polygon.points_count, EINA_TRUE);
+           break;
+        case SVG_NODE_POLYLINE:
+           _add_polyline(vg, node->node.polygon.points, node->node.polygon.points_count, EINA_FALSE);
+           break;
+        case SVG_NODE_ELLIPSE:
+           vg = evas_vg_shape_add(parent);
+           evas_vg_shape_shape_append_arc(vg, node->node.ellipse.cx - node->node.ellipse.rx,
+                                          node->node.ellipse.cy - node->node.ellipse.ry,
+                                          2*node->node.ellipse.rx, 2*node->node.ellipse.ry, 0, 360);
+           evas_vg_shape_shape_append_close(vg);
+           break;
+        case SVG_NODE_CIRCLE:
+           vg = evas_vg_shape_add(parent);
+           evas_vg_shape_shape_append_circle(vg, node->node.circle.cx, node->node.circle.cy, node->node.circle.r);
+           break;
+        case SVG_NODE_RECT:
+           vg = evas_vg_shape_add(parent);
+           evas_vg_shape_shape_append_rect(vg, 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;
+       default:
+           break;
+     }
+   _apply_vg_property(node, vg);
+}
+
+Vg_Data *
+_evas_vg_load_vg_data(Eina_Stringshare *path, int svg_id)
+{
+   Eina_List *l;
+   Vg_Data *vector;
+   char svg_key[20];
+   Eet_Data_Descriptor *svg_node_eet;
+   Svg_Node *child;
+   Svg_Node *node;
+   Eet_File *ef;
+   Efl_VG *root = NULL;
+
+   ef = eet_open(path, EET_FILE_MODE_READ);
+   if (!ef) return NULL;
+
+   // create and put it in the cache.
+   vector = calloc(1, sizeof(Vg_Data));
+   vector->svg_id = svg_id;
+
+   snprintf(svg_key, sizeof(svg_key), "edje/vectors/%i", svg_id);
+   svg_node_eet = _evas_vg_svg_node_eet();
+   node = eet_data_read(ef, svg_node_eet, svg_key);
+
+   if (!node || (node->type != SVG_NODE_DOC))
+     {
+        root = NULL;
+     }
+   else
+     {
+        root = evas_vg_container_add(NULL);
+        EINA_LIST_FOREACH(node->child, l, child)
+          {
+             _create_vg_node(child, root);
+          }
+        vector->x = node->node.doc.vx;
+        vector->y = node->node.doc.vy;
+        vector->w = node->node.doc.vw;
+        vector->h = node->node.doc.vh;
+     }
+   vector->vg = root;
+   _evas_vg_svg_node_free(node);
+   eet_close(ef);
+
+   return vector;
+}
+
+Efl_VG *
+_evas_vg_dup_vg_tree(Vg_Data *src, Vg_Data *dest, float pos, double w, double h)
+{
+   double sx, sy;
+   Efl_VG *root;
+   Eina_Matrix3 matrix;
+
+   if (!src) return NULL;
+   if (w==0 || h ==0 ) return NULL;
+   if (!dest)
+     {
+        root = evas_vg_container_add(NULL);
+        evas_vg_node_dup(root, src->vg);
+        sx = w/src->w;
+        sy = h/src->h;
+        eina_matrix3_identity(&matrix);
+        eina_matrix3_scale(&matrix, sx, sy);
+        eina_matrix3_translate(&matrix, -src->x, -src->y);
+        evas_vg_node_transformation_set(root, &matrix);
+     }
+   else
+     {
+        root = evas_vg_container_add(NULL);
+        evas_vg_node_dup(root, src->vg);
+
+        // for start vector
+        sx = w/src->w;
+        sy = h/src->h;
+        eina_matrix3_identity(&matrix);
+        eina_matrix3_scale(&matrix, sx, sy);
+        eina_matrix3_translate(&matrix, -src->x, -src->y);
+        evas_vg_node_transformation_set(src->vg, &matrix);
+
+        // for end vector
+        sx = w/dest->w;
+        sy = h/dest->h;
+        eina_matrix3_identity(&matrix);
+        eina_matrix3_scale(&matrix, sx, sy);
+        eina_matrix3_translate(&matrix, -dest->x, -dest->y);
+        evas_vg_node_transformation_set(dest->vg, &matrix);
+
+        // do the interpolation
+        if (!evas_vg_node_interpolate(root, src->vg, dest->vg, pos))
+          {
+             ;//ERR(" Can't interpolate check the svg file \n");
+          }
+        // performance hack
+        // instead of duplicating the tree and applying the transformation
+        // i just updated the transformation matrix and reset it back to null.
+        // assumption is that the root vg will never have a transformation
+        eina_matrix3_identity(&matrix);
+        evas_vg_node_transformation_set(src->vg, &matrix);
+        evas_vg_node_transformation_set(dest->vg, &matrix);
+     }
+   return root;
+}
+
+static void
+_svg_style_gradient_free(Svg_Style_Gradient *grad)
+{
+   Efl_Gfx_Gradient_Stop *stop;
+
+   if (!grad) return;
+
+   eina_stringshare_del(grad->id);
+   eina_stringshare_del(grad->ref);
+   free(grad->radial);
+   free(grad->linear);
+
+   EINA_LIST_FREE(grad->stops, stop)
+     {
+        free(stop);
+     }
+   free(grad);
+}
+
+static void
+_node_style_free(Svg_Style_Property *style)
+{
+   if (!style) return;
+
+   _svg_style_gradient_free(style->fill.paint.gradient);
+   eina_stringshare_del(style->fill.paint.url);
+   _svg_style_gradient_free(style->stroke.paint.gradient);
+   eina_stringshare_del(style->stroke.paint.url);
+   free(style);
+}
+
+EAPI void
+_evas_vg_svg_node_free(Svg_Node *node)
+{
+   Svg_Node *child;
+   Svg_Style_Gradient *grad;
+
+   if (!node) return;
+
+   EINA_LIST_FREE(node->child, child)
+     {
+        _evas_vg_svg_node_free(child);
+     }
+
+   eina_stringshare_del(node->id);
+   free(node->transform);
+   _node_style_free(node->style);
+   switch (node->type)
+     {
+        case SVG_NODE_PATH:
+           eina_stringshare_del(node->node.path.path);
+           break;
+        case SVG_NODE_POLYGON:
+        case SVG_NODE_POLYLINE:
+           free(node->node.polygon.points);
+           break;
+        case SVG_NODE_DOC:
+           _evas_vg_svg_node_free(node->node.doc.defs);
+           break;
+        case SVG_NODE_DEFS:
+           EINA_LIST_FREE(node->node.defs.gradients, grad)
+             {
+                _svg_style_gradient_free(grad);
+             }
+           break;
+        default:
+           break;
+     }
+  free(node);
+}
index 0ccea59..0ae044c 100644 (file)
@@ -2552,6 +2552,51 @@ eng_ector_end(void *data EINA_UNUSED, void *context EINA_UNUSED, Ector_Surface *
      }
 }
 
+static Ector_Surface_Cache *gl_cache = NULL;
+
+static void
+_ector_surface_cache_free_cb(void *data)
+{
+   eng_image_free(gl_cache->output, data);
+}
+
+static void 
+_ector_surface_cache_init(void *output)
+{
+   if (!gl_cache)
+     {
+        gl_cache = calloc(1, sizeof(Ector_Surface_Cache));
+        gl_cache->output = output;
+        gl_cache->suface_hash = eina_hash_string_superfast_new(_ector_surface_cache_free_cb);
+     }
+}
+
+// static void 
+// _ector_surface_cache_dump(void)
+// {
+//    if (gl_cache)
+//      {
+//         eina_hash_free(gl_cache->suface_hash);
+//         free(gl_cache);
+//         gl_cache = NULL;
+//      }
+// }
+
+static void
+eng_ector_surface_cache_set(void *data, const char *key, void *surface)
+{
+   _ector_surface_cache_init(data);
+   eina_hash_add(gl_cache->suface_hash, key, surface);
+}
+
+static void *
+eng_ector_surface_cache_get(void *data, const char *key)
+{
+   _ector_surface_cache_init(data);
+   return eina_hash_find(gl_cache->suface_hash, key);
+}
+
+
 static Evas_Func func, pfunc;
 
 static int
@@ -2701,6 +2746,8 @@ module_open(Evas_Module *em)
    ORD(ector_renderer_draw);
    ORD(ector_end);
    ORD(ector_surface_create);
+   ORD(ector_surface_cache_set);
+   ORD(ector_surface_cache_get);
 
    /* now advertise out own api */
    em->functions = (void *)(&func);
index 3857dd1..3a65998 100644 (file)
@@ -434,11 +434,14 @@ static int _evas_soft_gen_log_dom = -1;
 //#define QCMD evas_thread_cmd_enqueue
 #define QCMD evas_thread_queue_flush
 
+static void _ector_surface_cache_dump(void);
+
 static void
 eng_output_dump(void *data EINA_UNUSED)
 {
    evas_common_image_image_all_unload();
    evas_common_font_font_all_unload();
+   _ector_surface_cache_dump();
 }
 
 static void *
@@ -3889,9 +3892,72 @@ _draw_thread_ector_surface_set(void *data)
 static void *
 eng_ector_surface_create(void *data EINA_UNUSED, void *surface EINA_UNUSED, int width EINA_UNUSED, int height EINA_UNUSED)
 {
-   return NULL;
+   RGBA_Image *im;
+
+   if (!surface)
+     {
+        surface = eng_image_new_from_copied_data(data, width, height, NULL, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
+     }
+   else
+     {
+        int cur_w , cur_h;
+        im = surface;
+        eng_image_size_get(data, im, &cur_w, &cur_h);
+        if (width != cur_w || height != cur_h)
+          {
+             eng_image_free(data, surface);
+             surface =  eng_image_new_from_copied_data(data, width, height, NULL, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
+          }
+      }
+   return surface;
 }
 
+static Ector_Surface_Cache *sw_cache = NULL;
+
+static void
+_ector_surface_cache_free_cb(void *data)
+{
+   eng_image_free(sw_cache->output, data);
+}
+
+static void 
+_ector_surface_cache_init(void *output)
+{
+   if (!sw_cache)
+     {
+        printf("engine cache init\n");
+        sw_cache = calloc(1, sizeof(Ector_Surface_Cache));
+        sw_cache->output = output;
+        sw_cache->suface_hash = eina_hash_string_superfast_new(_ector_surface_cache_free_cb);
+     }
+}
+
+static void 
+_ector_surface_cache_dump(void)
+{
+   if (sw_cache)
+     {
+        eina_hash_free(sw_cache->suface_hash);
+        free(sw_cache);
+        sw_cache = NULL;
+     }
+}
+
+static void
+eng_ector_surface_cache_set(void *data, const char *key, void *surface)
+{
+   _ector_surface_cache_init(data);
+   eina_hash_add(sw_cache->suface_hash, key, surface);
+}
+
+static void *
+eng_ector_surface_cache_get(void *data, const char *key)
+{
+   _ector_surface_cache_init(data);
+   return eina_hash_find(sw_cache->suface_hash, key);
+}
+
+
 static void
 eng_ector_begin(void *data EINA_UNUSED, void *context EINA_UNUSED, Ector_Surface *ector, void *surface, int x, int y, Eina_Bool do_async)
 {
@@ -4156,7 +4222,9 @@ static Evas_Func func =
      eng_ector_begin,
      eng_ector_renderer_draw,
      eng_ector_end,
-        eng_ector_surface_create
+     eng_ector_surface_create,
+     eng_ector_surface_cache_set,
+     eng_ector_surface_cache_get
    /* FUTURE software generic calls go here */
 };