evas json: introduce lottie animation in efl.
lottie animation is a new format of animation data
that works based on vector graphics and key frames.
lottie-player is a standalone library that manipulate
lottie animation scenes. Since lottie animation file format
is json, evas json loader is added here and it parses json data
using lottie player and construct vector nodes graphs
by accessing lottie-player interfaces.
Since evas vector is designed for static image,
here changes vg object interfaces to newly afford animation controller
by expanding Gfx.Image.Animation_Controller and expand vg cache routines
for caching first and last frame images which is mostly used repeatedly
in common scenarios.
@feature
Change-Id: Ia94b00c0f834c524c7f3242f95687b487d7b37e7
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'],
+ 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']
)
evas_cache_vg_entry_del(pd->vg_entry);
pd->vg_entry = vg_entry;
}
- root = evas_cache_vg_tree_get(pd->vg_entry, pd->frame_index);
+ root = evas_cache_vg_tree_get(pd->vg_entry, pd->frame_idx);
}
else if (pd->user_entry) root = pd->user_entry->root;
else root = pd->root;
ENFN->ector_end(engine, buffer, context, ector, do_async);
evas_common_draw_context_free(context);
- //caching buffer only for first and last frames.
if (buffer_created && cacheable)
- ENFN->ector_surface_cache_set(engine, ((void *) key) + pd->frame_index, buffer);
+ {
+ ENFN->ector_surface_cache_set(engine, key, buffer);
+ pd->cached_frame_idx = pd->frame_idx;
+ }
return buffer;
}
w = size.w;
h = size.h;
}
- root = evas_cache_vg_tree_get(vg_entry, pd->frame_index);
+ root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx);
if (!root) return;
- void *buffer = ENFN->ector_surface_cache_get(engine, ((void *) root) + pd->frame_index);
+ void *buffer = NULL;
+
+ if (pd->frame_idx == pd->cached_frame_idx)
+ buffer = ENFN->ector_surface_cache_get(engine, (void *) root);
if (!buffer)
buffer = _render_to_buffer(obj, pd, engine, root, w, h, root, NULL,
do_async, cacheable);
else
//cache reference was increased when we get the cache.
- ENFN->ector_surface_cache_drop(engine, ((void *) root) + pd->frame_index);
+ ENFN->ector_surface_cache_drop(engine, (void *) root);
_render_buffer_to_screen(obj,
engine, output, context, surface,
//Cache surface?
Eina_Bool cacheable = EINA_FALSE;
- if (pd->frame_index == 0 ||
- (pd->frame_index == (int) evas_cache_vg_anim_frame_count_get(pd->vg_entry)))
+ /* Try caching buffer only for first and last frames
+ because it's an overhead task if it caches all frame images.
+ We assume the first and last frame images are the most resusable
+ in generic scenarios. */
+ if (pd->frame_idx == 0 ||
+ (pd->frame_idx == (int) evas_cache_vg_anim_frame_count_get(pd->vg_entry)))
cacheable = EINA_TRUE;
if (pd->vg_entry)
int frame_index)
{
//TODO: Validate frame_index range
- if (pd->frame_index == frame_index) return EINA_TRUE;
+ if (pd->frame_idx == frame_index) return EINA_TRUE;
//Image is changed, drop previous cached image.
- pd->frame_index = frame_index;
+ pd->frame_idx = frame_index;
pd->changed = EINA_TRUE;
evas_object_change(eo_obj, efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS));
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_frame_get(const Eo *eo_obj EINA_UNUSED,
Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
{
- return pd->frame_index;
+ return pd->frame_idx;
}
EOLIAN static Eina_Size2D
Eina_Array cleanup;
double align_x, align_y;
Efl_Canvas_Vg_Fill_Mode fill_mode;
- int frame_index;
+ int frame_idx;
Eina_File *file;
Eina_Stringshare *key;
+ int cached_frame_idx;
Eina_Bool changed : 1;
};
png = dependency('libpng')
tiff = dependency('libtiff-4')
giflib = cc.find_library('gif')
-
+json = dependency('lottie-player', required: get_option('evas-loaders-disabler').contains('json') == false)
webp = dependency('libwebp', required: get_option('evas-loaders-disabler').contains('webp') == false)
subdir('image_loaders')
-evas_vg_loaders_file = ['eet', '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')
+evas_vg_loaders_file = [
+ ['eet', [eet]],
+ ['json', [json]],
+ ['svg', []],
+]
+
+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
'vg_common.h',
])
+json = dependency('lottie-player', required: get_option('evas-loaders-disabler').contains('json') == false)
+
+if (json.found())
+ 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(
include_directories: vg_common_inc_dir,
sources: vg_common_src,
)
+
+
/******************************************************************************************
* Lottie Compatible feature implementation
******************************************************************************************/
-#ifdef BUILD_VG_LOADER_JSON
-# include <lottieanimation_capi.h>
-#endif
-
Eina_Bool vg_common_json_create_vg_node(Vg_File_Data *vfd);
#endif //EVAS_VG_COMMON_H_
#ifdef BUILD_VG_LOADER_JSON
+#include <lottieanimation_capi.h>
+
static char*
_get_key_val(void *key)
{
{
if (!parent) return;
-#if TREE_VERIFY
- Eina_Bool verified = EINA_TRUE;
- Eina_Iterator *itr = efl_canvas_vg_container_children_get(parent);
- if (itr)
- {
- Efl_Canvas_Vg_Shape *child;
- int i = 0;
- EINA_ITERATOR_FOREACH(itr, child)
- {
- if (!efl_isa(child, EFL_CANVAS_VG_SHAPE_CLASS)) continue;
-
- LOTNode *node = layer->mNodeList.ptr[i];
- if (efl_key_data_get(parent, _get_key_val(node)) != child)
- {
- verified = EINA_FALSE;
- }
- i++;
- efl_gfx_entity_visible_set(child, EINA_FALSE);
- }
- eina_iterator_free(itr);
- }
- if (!verified) ERR("Shape: Failed to verify!");
-#endif
-
for (unsigned int i = 0; i < layer->mNodeList.size; i++)
{
LOTNode *node = layer->mNodeList.ptr[i];
}
efl_gfx_entity_visible_set(root, EINA_TRUE);
-#if TREE_VERIFY
- Eina_Bool verified = EINA_TRUE;
- Eina_Iterator *itr = efl_canvas_vg_container_children_get(root);
- if (itr)
- {
- Efl_Canvas_Vg_Node *child;
- int i = 0;
- EINA_ITERATOR_FOREACH(itr, child)
- {
- if (!efl_isa(child, EFL_CANVAS_VG_CONTAINER_CLASS)) continue;
- LOTLayerNode *clayer = layer->mLayerList.ptr[i];
- if (efl_key_data_get(root, _get_key_val(clayer)) != child)
- {
- verified = EINA_FALSE;
- }
-
- i++;
- }
- eina_iterator_free(itr);
- }
- if (!verified) ERR("Layer: Failed to verify!");
-#endif
Efl_Canvas_Vg_Container *ptree = NULL;
//Note: We assume that if matte is valid, next layer must be a matte source.
efl_key_data_set(root, _get_key_val((void *) tree), tree);
vfd->root = root;
}
- else
- {
-#if TREE_VERIFY
- if (efl_key_data_get(root, _get_key_val((void *) tree)) != tree)
- {
- ERR("Root: Failed to verify!");
- }
-#endif
- }
+
_update_vg_tree(root, tree, 1);
#else
return EINA_FALSE;