diff --git a/meson_options.txt b/meson_options.txt index 79081a71bc..9dac48279d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -201,8 +201,8 @@ option('evas-modules', option('evas-loaders-disabler', type : 'array', description : 'add names here to disable the loaders', - choices : ['gst', 'pdf', 'ps', 'raw', 'svg', 'xcf', 'bmp', 'dds', 'eet', 'generic', 'gif', 'ico', 'jp2k', 'jpeg', 'pmaps', 'png', 'psd', 'tga', 'tgv', 'tiff', 'wbmp', 'webp', 'xpm'], - value : ['webp'] + choices : ['gst', 'pdf', 'ps', 'raw', 'svg', 'xcf', 'bmp', 'dds', 'eet', 'generic', 'gif', 'ico', 'jp2k', 'jpeg', 'pmaps', 'png', 'psd', 'tga', 'tgv', 'tiff', 'wbmp', 'webp', 'xpm', 'json'], + value : ['webp', 'json'] ) option('ecore-imf-loaders-disabler', diff --git a/src/lib/evas/file/evas_module.c b/src/lib/evas/file/evas_module.c index 63129bc286..b467ebcdbf 100644 --- a/src/lib/evas/file/evas_module.c +++ b/src/lib/evas/file/evas_module.c @@ -185,6 +185,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(engine, wayland_egl); #if !EVAS_MODULE_NO_VG_LOADERS EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, eet); EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, svg); +EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, json); #endif #if !EVAS_MODULE_NO_IMAGE_LOADERS @@ -274,6 +275,9 @@ static const struct { #ifdef EVAS_STATIC_BUILD_VG_EET EVAS_EINA_STATIC_MODULE_USE(vg_loader, eet), #endif +#ifdef EVAS_STATIC_BUILD_VG_JSON + EVAS_EINA_STATIC_MODULE_USE(vg_loader, json), +#endif #endif #if !EVAS_MODULE_NO_IMAGE_LOADERS #ifdef EVAS_STATIC_BUILD_BMP diff --git a/src/modules/evas/meson.build b/src/modules/evas/meson.build index a79dc6800b..c49a24c3ea 100644 --- a/src/modules/evas/meson.build +++ b/src/modules/evas/meson.build @@ -2,7 +2,7 @@ png = dependency('libpng') tiff = dependency('libtiff-4') giflib = cc.find_library('gif') - +json = dependency('rlottie', required: get_option('evas-loaders-disabler').contains('json') == false) webp = dependency('libwebp', required: get_option('evas-loaders-disabler').contains('webp') == false) #there are a few modules that should NEVER be build as a module but rather be build as static lib and linked in later diff --git a/src/modules/evas/vg_loaders/json/evas_vg_load_json.c b/src/modules/evas/vg_loaders/json/evas_vg_load_json.c new file mode 100644 index 0000000000..6dabff71a6 --- /dev/null +++ b/src/modules/evas/vg_loaders/json/evas_vg_load_json.c @@ -0,0 +1,139 @@ +#include +#include "vg_common.h" + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_evas_vg_loader_json_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_evas_vg_loader_json_log_dom, __VA_ARGS__) + +static int _evas_vg_loader_json_log_dom = -1; + +static Eina_Bool +evas_vg_load_file_close_json(Vg_File_Data *vfd) +{ + if (!vfd) return EINA_FALSE; + + Lottie_Animation *lot_anim = (Lottie_Animation *) vfd->loader_data; + lottie_animation_destroy(lot_anim); + if (vfd->anim_data) free(vfd->anim_data); + if (vfd->root) efl_unref(vfd->root); + free(vfd); + + return EINA_TRUE; +} + +static Eina_Bool +evas_vg_load_file_data_json(Vg_File_Data *vfd) +{ + return vg_common_json_create_vg_node(vfd); +} + +static Vg_File_Data* +evas_vg_load_file_open_json(Eina_File *file, + const char *key, + int *error EINA_UNUSED) +{ + Vg_File_Data *vfd = calloc(1, sizeof(Vg_File_Data)); + if (!vfd) return NULL; + + Lottie_Animation *lot_anim = NULL; + + const char *data = (const char*) eina_file_map_all(file, EINA_FILE_SEQUENTIAL); + if (!data) goto err; + //@TODO pass corrct external_resource path. + lot_anim = lottie_animation_from_data(data, key ? key:eina_file_filename_get(file), " "); + eina_file_map_free(file, (void *) data); + + if (!lot_anim) + { + ERR("Failed lottie_animation_from_file"); + goto err; + } + + unsigned int frame_cnt = lottie_animation_get_totalframe(lot_anim); + + //Support animation + if (frame_cnt > 1) + { + vfd->anim_data = calloc(1, sizeof(Vg_File_Anim_Data)); + if (!vfd->anim_data) goto err; + vfd->anim_data->duration = lottie_animation_get_duration(lot_anim); + vfd->anim_data->frame_cnt = frame_cnt; + } + + //default size + size_t w, h; + lottie_animation_get_size(lot_anim, &w, &h); + vfd->w = (int) w; + vfd->h = (int) h; + + vfd->loader_data = (void *) lot_anim; + vfd->no_share = EINA_TRUE; + + return vfd; + +err: + if (vfd) + { + if (vfd->anim_data) free(vfd->anim_data); + free(vfd); + } + if (lot_anim) lottie_animation_destroy(lot_anim); + + return NULL; +} + +static Evas_Vg_Load_Func evas_vg_load_json_func = +{ + evas_vg_load_file_open_json, + evas_vg_load_file_close_json, + evas_vg_load_file_data_json +}; + +static int +module_open(Evas_Module *em) +{ + if (!em) return 0; + em->functions = (void *)(&evas_vg_load_json_func); + _evas_vg_loader_json_log_dom = eina_log_domain_register + ("vg-load-json", EVAS_DEFAULT_LOG_COLOR); + if (_evas_vg_loader_json_log_dom < 0) + { + EINA_LOG_ERR("Can not create a module log domain."); + return 0; + } + return 1; +} + +static void +module_close(Evas_Module *em EINA_UNUSED) +{ + if (_evas_vg_loader_json_log_dom >= 0) + { + eina_log_domain_unregister(_evas_vg_loader_json_log_dom); + _evas_vg_loader_json_log_dom = -1; + } +} + +static Evas_Module_Api evas_modapi = +{ + EVAS_MODULE_API_VERSION, + "json", + "none", + { + module_open, + module_close + } +}; + +EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_VG_LOADER, vg_loader, json); + +#ifndef EVAS_STATIC_BUILD_VG_JSON +EVAS_EINA_MODULE_DEFINE(vg_loader, json); +#endif + diff --git a/src/modules/evas/vg_loaders/meson.build b/src/modules/evas/vg_loaders/meson.build index 584501a825..5ffe8f0ffe 100644 --- a/src/modules/evas/vg_loaders/meson.build +++ b/src/modules/evas/vg_loaders/meson.build @@ -1,13 +1,26 @@ -evas_vg_loaders_file = ['eet', 'svg'] +evas_vg_loaders_file = [ + ['eet', [eet]], + ['json', [json]], + ['svg', []], +] -foreach loader : evas_vg_loaders_file - file = join_paths(loader, 'evas_vg_load_'+loader+'.c') - static_library('vg_loader_'+loader, file, - include_directories : config_dir, - dependencies : evas_pre - ) - evas_static_list += [declare_dependency( - sources: file, - )] - config_h.set('EVAS_STATIC_BUILD_VG_'+loader.to_upper(), '1') +foreach loader_inst : evas_vg_loaders_file + loader = loader_inst[0] + loader_deps = loader_inst[1] + + if (get_option('evas-loaders-disabler').contains(loader) == false) + file = join_paths(loader, 'evas_vg_load_'+loader+'.c') + + static_library('vg_loader_'+loader, file, + include_directories : config_dir, + dependencies : [evas_pre] + loader_deps + ) + + evas_static_list += [declare_dependency( + sources: file, + dependencies: loader_deps, + )] + + config_h.set('EVAS_STATIC_BUILD_VG_'+loader.to_upper(), '1') + endif endforeach diff --git a/src/static_libs/vg_common/meson.build b/src/static_libs/vg_common/meson.build index 648fcd5570..9dfb47f897 100644 --- a/src/static_libs/vg_common/meson.build +++ b/src/static_libs/vg_common/meson.build @@ -5,6 +5,11 @@ vg_common_src = files([ 'vg_common.h', ]) +if get_option('evas-loaders-disabler').contains('json') == false + config_h.set('BUILD_VG_LOADER_JSON', '1') + vg_common_src += files('vg_common_json.c') +endif + vg_common_inc_dir = include_directories('.') vg_common = declare_dependency( diff --git a/src/static_libs/vg_common/vg_common.h b/src/static_libs/vg_common/vg_common.h index 3484a7174f..fc8d566144 100644 --- a/src/static_libs/vg_common/vg_common.h +++ b/src/static_libs/vg_common/vg_common.h @@ -319,4 +319,10 @@ Vg_File_Data * vg_common_svg_create_vg_node(Svg_Node *node); Svg_Node *vg_common_svg_create_svg_node(Vg_File_Data *node); void vg_common_svg_node_free(Svg_Node *node); + +/****************************************************************************************** + * Lottie Compatible feature implementation + ******************************************************************************************/ +Eina_Bool vg_common_json_create_vg_node(Vg_File_Data *vfd); + #endif //EVAS_VG_COMMON_H_ diff --git a/src/static_libs/vg_common/vg_common_json.c b/src/static_libs/vg_common/vg_common_json.c new file mode 100644 index 0000000000..c97bfeaa08 --- /dev/null +++ b/src/static_libs/vg_common/vg_common_json.c @@ -0,0 +1,438 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "vg_common.h" +#include + +#ifdef BUILD_VG_LOADER_JSON + +#include + +//FIXME: This enum add temporarily to help understanding of additional code +//related to masking in prepare_mask. +//This needs to be formally declared through the eo class. +typedef enum _EFL_CANVAS_VG_NODE_BLEND_TYPE +{ + EFL_CANVAS_VG_NODE_BLEND_TYPE_NONE = 0, + EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA, + EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV, + EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD, + EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT, + EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT, + EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE +}EFL_CANVAS_VG_NODE_BLEND_TYPE; +// + +static char* +_get_key_val(void *key) +{ + static char buf[30]; + snprintf(buf, sizeof(buf), "%ld", (size_t) key); + return buf; +} + +static void +_construct_drawable_nodes(Efl_Canvas_Vg_Container *parent, const LOTLayerNode *layer, int depth EINA_UNUSED) +{ + if (!parent) return; + + for (unsigned int i = 0; i < layer->mNodeList.size; i++) + { + LOTNode *node = layer->mNodeList.ptr[i]; + if (!node) continue; + + const float *data = node->mPath.ptPtr; + if (!data) continue; + + char *key = _get_key_val(node); + Efl_Canvas_Vg_Shape *shape = efl_key_data_get(parent, key); + if (!shape) + { + shape = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent); + efl_key_data_set(parent, key, shape); + } + else + efl_gfx_path_reset(shape); + + efl_gfx_entity_visible_set(shape, EINA_TRUE); +#if DEBUG + for (int i = 0; i < depth; i++) printf(" "); + printf("%s (%p)\n", efl_class_name_get(efl_class_get(shape)), shape); +#endif + //0: Path + efl_gfx_path_reserve(shape, node->mPath.elmCount, node->mPath.ptCount); + + for (int i = 0; i < node->mPath.elmCount; i++) + { + switch (node->mPath.elmPtr[i]) + { + case 0: + efl_gfx_path_append_move_to(shape, data[0], data[1]); + data += 2; + break; + case 1: + efl_gfx_path_append_line_to(shape, data[0], data[1]); + data += 2; + break; + case 2: + efl_gfx_path_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]); + data += 6; + break; + case 3: + efl_gfx_path_append_close(shape); + break; + default: + ERR("No reserved path type = %d", node->mPath.elmPtr[i]); + } + } + + //1: Stroke + if (node->mStroke.enable) + { + //Stroke Width + efl_gfx_shape_stroke_width_set(shape, node->mStroke.width); + + //Stroke Cap + Efl_Gfx_Cap cap; + switch (node->mStroke.cap) + { + case CapFlat: cap = EFL_GFX_CAP_BUTT; break; + case CapSquare: cap = EFL_GFX_CAP_SQUARE; break; + case CapRound: cap = EFL_GFX_CAP_ROUND; break; + default: cap = EFL_GFX_CAP_BUTT; break; + } + efl_gfx_shape_stroke_cap_set(shape, cap); + + //Stroke Join + Efl_Gfx_Join join; + switch (node->mStroke.join) + { + case JoinMiter: join = EFL_GFX_JOIN_MITER; break; + case JoinBevel: join = EFL_GFX_JOIN_BEVEL; break; + case JoinRound: join = EFL_GFX_JOIN_ROUND; break; + default: join = EFL_GFX_JOIN_MITER; break; + } + efl_gfx_shape_stroke_join_set(shape, join); + + //Stroke Dash + if (node->mStroke.dashArraySize > 0) + { + int size = (node->mStroke.dashArraySize / 2); + Efl_Gfx_Dash *dash = malloc(sizeof(Efl_Gfx_Dash) * size); + if (dash) + { + for (int i = 0; i <= size; i+=2) + { + dash[i].length = node->mStroke.dashArray[i]; + dash[i].gap = node->mStroke.dashArray[i + 1]; + } + efl_gfx_shape_stroke_dash_set(shape, dash, size); + free(dash); + } + } + } + + //2: Fill Method + switch (node->mBrushType) + { + case BrushSolid: + { + float pa = ((float)node->mColor.a) / 255; + int r = (int)(((float) node->mColor.r) * pa); + int g = (int)(((float) node->mColor.g) * pa); + int b = (int)(((float) node->mColor.b) * pa); + int a = node->mColor.a; + + if (node->mStroke.enable) + efl_gfx_shape_stroke_color_set(shape, r, g, b, a); + else + efl_gfx_color_set(shape, r, g, b, a); + } + break; + case BrushGradient: + { + Efl_Canvas_Vg_Gradient* grad = NULL; + + if (node->mGradient.type == GradientLinear) + { + grad = efl_add(EFL_CANVAS_VG_GRADIENT_LINEAR_CLASS, parent); + efl_gfx_gradient_linear_start_set(grad, node->mGradient.start.x, node->mGradient.start.y); + efl_gfx_gradient_linear_end_set(grad, node->mGradient.end.x, node->mGradient.end.y); + } + else if (node->mGradient.type == GradientRadial) + { + grad = efl_add(EFL_CANVAS_VG_GRADIENT_RADIAL_CLASS, parent); + efl_gfx_gradient_radial_center_set(grad, node->mGradient.center.x, node->mGradient.center.y); + efl_gfx_gradient_radial_focal_set(grad, node->mGradient.focal.x, node->mGradient.focal.y); + efl_gfx_gradient_radial_radius_set(grad, node->mGradient.cradius); + } + else + ERR("No reserved gradient type = %d", node->mGradient.type); + + if (grad) + { + //Gradient Stop + Efl_Gfx_Gradient_Stop* stops = malloc(sizeof(Efl_Gfx_Gradient_Stop) * node->mGradient.stopCount); + if (stops) + { + for (unsigned int i = 0; i < node->mGradient.stopCount; i++) + { + stops[i].offset = node->mGradient.stopPtr[i].pos; + float pa = ((float)node->mGradient.stopPtr[i].a) / 255; + stops[i].r = (int)(((float)node->mGradient.stopPtr[i].r) * pa); + stops[i].g = (int)(((float)node->mGradient.stopPtr[i].g) * pa); + stops[i].b = (int)(((float)node->mGradient.stopPtr[i].b) * pa); + stops[i].a = node->mGradient.stopPtr[i].a; + } + efl_gfx_gradient_stop_set(grad, stops, node->mGradient.stopCount); + free(stops); + } + if (node->mStroke.enable) + efl_canvas_vg_shape_stroke_fill_set(shape, grad); + else + efl_canvas_vg_shape_fill_set(shape, grad); + } + } + break; + default: + ERR("No reserved brush type = %d", node->mBrushType); + } + + //3: Fill Rule + if (node->mFillRule == FillEvenOdd) + efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_ODD_EVEN); + else if (node->mFillRule == FillWinding) + efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_WINDING); + } +} + +static void +_construct_mask_nodes(Efl_Canvas_Vg_Container *parent, LOTMask *mask, int depth EINA_UNUSED) +{ + const float *data = mask->mPath.ptPtr; + if (!data) return; + + char *key = _get_key_val(mask); + Efl_Canvas_Vg_Shape *shape = efl_key_data_get(parent, key); + if (!shape) + { + shape = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent); + efl_key_data_set(parent, key, shape); + } + else + efl_gfx_path_reset(shape); + + efl_gfx_entity_visible_set(shape, EINA_TRUE); + + efl_gfx_path_reserve(shape, mask->mPath.elmCount, mask->mPath.ptCount); + + for (int i = 0; i < mask->mPath.elmCount; i++) + { + switch (mask->mPath.elmPtr[i]) + { + case 0: + efl_gfx_path_append_move_to(shape, data[0], data[1]); + data += 2; + break; + case 1: + efl_gfx_path_append_line_to(shape, data[0], data[1]); + data += 2; + break; + case 2: + efl_gfx_path_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]); + data += 6; + break; + case 3: + efl_gfx_path_append_close(shape); + break; + default: + ERR("No reserved path type = %d", mask->mPath.elmPtr[i]); + break; + } + } + //White color and alpha setting + float pa = ((float)mask->mAlpha) / 255; + int r = (int) (255.0f * pa); + int g = (int) (255.0f * pa); + int b = (int) (255.0f * pa); + int a = mask->mAlpha; + efl_gfx_color_set(shape, r, g, b, a); +} + +static void +_construct_masks(Efl_Canvas_Vg_Container *mtarget, LOTMask *masks, unsigned int mask_cnt, int depth) +{ + char *key = NULL; + + Efl_Canvas_Vg_Container *msource = NULL; + + key = _get_key_val(mtarget); + msource = efl_key_data_get(mtarget, key); + if (!msource) + { + msource = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, mtarget); + efl_key_data_set(mtarget, key, msource); + } + + //FIXME : EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA option is temporary + //Currently matte alpha implemtnes is same the mask intersect impletment. + //It has been implemented as a multiplication calculation. + efl_canvas_vg_node_mask_set(mtarget, msource, EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA); + + mtarget = msource; + + //Make mask layers + for (unsigned int i = 0; i < mask_cnt; i++) + { + LOTMask *mask = &masks[i];; + key = _get_key_val(mask); + msource = efl_key_data_get(mtarget, key); + + if (!msource) + { + msource = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, mtarget); + efl_key_data_set(mtarget, key, msource); + } + _construct_mask_nodes(msource, mask, depth + 1); + + EFL_CANVAS_VG_NODE_BLEND_TYPE mask_mode; + switch (mask->mMode) + { + case MaskSubstract: + mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT; + break; + case MaskIntersect: + mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT; + break; + case MaskDifference: + mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE; + break; + case MaskAdd: + default: + mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD; + break; + } + efl_canvas_vg_node_mask_set(mtarget, msource, mask_mode); + mtarget = msource; + } +} + +static void +_update_vg_tree(Efl_Canvas_Vg_Container *root, const LOTLayerNode *layer, int depth EINA_UNUSED) +{ + if (!layer->mVisible) + { + efl_gfx_entity_visible_set(root, EINA_FALSE); + return; + } + efl_gfx_entity_visible_set(root, EINA_TRUE); + + Efl_Canvas_Vg_Container *ptree = NULL; + + //Note: We assume that if matte is valid, next layer must be a matte source. + int matte_mode = 0; + Efl_Canvas_Vg_Container *mtarget = NULL; + LOTLayerNode *mlayer = NULL; + + //Is this layer a container layer? + for (unsigned int i = 0; i < layer->mLayerList.size; i++) + { + LOTLayerNode *clayer = layer->mLayerList.ptr[i]; + + //Source Layer + char *key = _get_key_val(clayer); + Efl_Canvas_Vg_Container *ctree = efl_key_data_get(root, key); + if (!ctree) + { + ctree = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, root); + efl_key_data_set(root, key, ctree); + } +#if DEBUG + for (int i = 0; i < depth; i++) printf(" "); + printf("%s (%p) matte:%d => %p\n", efl_class_name_get(efl_class_get(ctree)), ctree, matte_mode, ptree); +#endif + _update_vg_tree(ctree, clayer, depth+1); + + if (matte_mode != 0) + { + efl_canvas_vg_node_mask_set(ptree, ctree, matte_mode); + mtarget = ctree; + } + matte_mode = (int) clayer->mMatte; + + if (clayer->mMaskList.size > 0) + { + mlayer = clayer; + if (!mtarget) mtarget = ctree; + } + + ptree = ctree; + + //Remap Matte Mode + switch (matte_mode) + { + case MatteNone: + matte_mode = 0; + break; + case MatteAlpha: + matte_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA; + break; + case MatteAlphaInv: + matte_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV; + break; + case MatteLuma: + matte_mode = 0; + ERR("TODO: MatteLuma"); + break; + case MatteLumaInv: + matte_mode = 0; + ERR("TODO: MatteLumaInv"); + break; + default: + matte_mode = 0; + break; + } + } + + //Construct drawable nodes. + if (layer->mNodeList.size > 0) + _construct_drawable_nodes(root, layer, depth); + + //Construct node that have mask. + if (mlayer) + _construct_masks(mtarget, mlayer->mMaskList.ptr, mlayer->mMaskList.size, depth); +} +#endif + +Eina_Bool +vg_common_json_create_vg_node(Vg_File_Data *vfd) +{ +#ifdef BUILD_VG_LOADER_JSON + Lottie_Animation *lot_anim = (Lottie_Animation *) vfd->loader_data; + if (!lot_anim) return EINA_FALSE; + + unsigned int frame_num = (vfd->anim_data) ? vfd->anim_data->frame_num : 0; + const LOTLayerNode *tree = + lottie_animation_render_tree(lot_anim, frame_num, + vfd->view_box.w, vfd->view_box.h); +#if DEBUG + printf("%s (%p)\n", efl_class_name_get(efl_class_get(vfd->root)), vfd->root); +#endif + + //Root node + Efl_Canvas_Vg_Container *root = vfd->root; + if (!root) + { + root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL); + if (!root) return EINA_FALSE; + efl_key_data_set(root, _get_key_val((void *) tree), tree); + vfd->root = root; + } + + _update_vg_tree(root, tree, 1); +#else + return EINA_FALSE; +#endif + return EINA_TRUE; +}