forked from enlightenment/efl
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
This commit is contained in:
parent
865c60373a
commit
5b0c43cbbc
|
@ -2585,7 +2585,7 @@ esac
|
|||
|
||||
ARG_ENABLE_EVAS_VG_LOADER(SVG, static)
|
||||
ARG_ENABLE_EVAS_VG_LOADER(EET, static)
|
||||
|
||||
ARG_ENABLE_EVAS_VG_LOADER(JSON, auto)
|
||||
|
||||
ARG_ENABLE_EVAS_IMAGE_LOADER(BMP, static)
|
||||
ARG_ENABLE_EVAS_IMAGE_LOADER(Eet, static)
|
||||
|
@ -2876,6 +2876,7 @@ AM_CONDITIONAL([BUILD_ENGINE_WAYLAND_COMMON], [test "x${have_evas_engine_wayland
|
|||
|
||||
EVAS_CHECK_VG_LOADER([SVG], [${want_evas_vg_loader_svg}])
|
||||
EVAS_CHECK_VG_LOADER([EET], [${want_evas_vg_loader_eet}])
|
||||
EVAS_CHECK_VG_LOADER([JSON], [${want_evas_vg_loader_json}])
|
||||
|
||||
## Image Loaders
|
||||
|
||||
|
|
|
@ -58,6 +58,37 @@ AS_IF([test "x${have_dep}" = "xyes"], [$3], [$4])
|
|||
|
||||
])
|
||||
|
||||
dnl use: EVAS_CHECK_VG_LOADER_DEP_JSON(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
|
||||
AC_DEFUN([EVAS_CHECK_VG_LOADER_DEP_JSON],
|
||||
[
|
||||
|
||||
have_dep="no"
|
||||
evas_vg_loader_[]$1[]_cflags=""
|
||||
evas_vg_loader_[]$1[]_libs=""
|
||||
|
||||
AC_CHECK_HEADER([lottieanimation_capi.h], [have_dep="yes"])
|
||||
|
||||
if test "x${have_dep}" = "xyes" ; then
|
||||
AC_CHECK_LIB([lottie-player],
|
||||
[lottie_animation_from_file],
|
||||
[
|
||||
evas_vg_loader_[]$1[]_libs="-llottie-player"
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$2" = "xstatic" && test "x${have_dep}" = "xyes" ; then
|
||||
requirements_libs_evas="${evas_vg_loader_[]$1[]_libs} ${requirements_libs_evas}"
|
||||
fi
|
||||
|
||||
AC_SUBST([evas_vg_loader_$1_cflags])
|
||||
AC_SUBST([evas_vg_loader_$1_libs])
|
||||
|
||||
AS_IF([test "x${have_dep}" = "xyes"], [$3], [$4])
|
||||
|
||||
])
|
||||
|
||||
dnl use: ARG_ENABLE_EVAS_IMAGE_LOADER(loader, default_value)
|
||||
|
||||
AC_DEFUN([ARG_ENABLE_EVAS_IMAGE_LOADER],
|
||||
|
@ -657,11 +688,12 @@ if test "x${have_loader}" = "xyes" ; then
|
|||
want_static_loader="yes"
|
||||
else
|
||||
have_evas_vg_loader_[]DOWN="yes"
|
||||
want_static_loader="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x${have_loader}" = "xyes" ; then
|
||||
AC_DEFINE(BUILD_VG_LOADER_[]UP, [1], [UP Image Loader Support])
|
||||
AC_DEFINE(BUILD_VG_LOADER_[]UP, [1], [UP VG Loader Support])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_VG_LOADER_[]UP, [test "x${have_loader}" = "xyes"])
|
||||
|
|
|
@ -201,7 +201,7 @@ 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'],
|
||||
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']
|
||||
)
|
||||
|
||||
|
|
|
@ -1558,6 +1558,36 @@ modules_evas_vg_savers_eet_module_la_LIBTOOLFLAGS = --tag=disable-static
|
|||
endif
|
||||
endif
|
||||
|
||||
if BUILD_VG_LOADER_JSON
|
||||
if EVAS_STATIC_BUILD_VG_JSON
|
||||
lib_evas_libevas_la_SOURCES += modules/evas/vg_loaders/json/evas_vg_load_json.c \
|
||||
static_libs/vg_common/vg_common_json.c \
|
||||
static_libs/vg_common/vg_common.h
|
||||
lib_evas_libevas_la_CPPFLAGS += -I$(top_srcdir)/src/static_libs/vg_common \
|
||||
@evas_vg_loader_json_cflags@
|
||||
lib_evas_libevas_la_LIBADD += @evas_vg_loader_json_libs@
|
||||
else
|
||||
vgloaderjsonpkgdir = $(libdir)/evas/modules/vg_loaders/json/$(MODULE_ARCH)
|
||||
vgloaderjsonpkg_LTLIBRARIES = modules/evas/vg_loaders/json/module.la
|
||||
|
||||
# Workaround for broken parallel install support in automake (relink issue)
|
||||
# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328
|
||||
install_vgloaderjsonpkgLTLIBRARIES = install-vgloaderjsonpkgLTLIBRARIES
|
||||
$(install_vgloaderjsonpkgLTLIBRARIES): install-libLTLIBRARIES
|
||||
|
||||
modules_evas_vg_loaders_json_module_la_SOURCES = modules/evas/vg_loaders/json/evas_vg_load_json.c
|
||||
modules_evas_vg_loaders_json_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||
-I$(top_srcdir)/src/lib/evas/include \
|
||||
@EVAS_CFLAGS@ \
|
||||
@evas_vg_loader_json_cflags@
|
||||
modules_evas_vg_loaders_json_module_la_LIBADD = \
|
||||
@USE_EVAS_LIBS@ \
|
||||
@evas_vg_loader_json_libs@
|
||||
modules_evas_vg_loaders_json_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@
|
||||
modules_evas_vg_loaders_json_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
|
||||
modules_evas_vg_loaders_json_module_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_LOADER_BMP
|
||||
if EVAS_STATIC_BUILD_BMP
|
||||
|
|
|
@ -117,7 +117,7 @@ _efl_canvas_vg_object_root_node_get(const Eo *obj, Efl_Canvas_Vg_Object_Data *pd
|
|||
evas_cache_vg_entry_del(pd->vg_entry);
|
||||
pd->vg_entry = vg_entry;
|
||||
}
|
||||
root = evas_cache_vg_tree_get(pd->vg_entry);
|
||||
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;
|
||||
|
@ -244,22 +244,21 @@ _efl_canvas_vg_object_viewbox_align_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg
|
|||
if (align_y) *align_y = pd->align_y;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_canvas_vg_object_efl_file_file_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, const char *file, const char *key)
|
||||
static Eina_Bool
|
||||
_vg_file_mmap_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, const Eina_File *file, const char *key, Eina_Bool mmap)
|
||||
{
|
||||
Vg_Cache_Entry *old_entry;
|
||||
Evas_Object_Protected_Data *obj;
|
||||
|
||||
if (!file) return EINA_FALSE;
|
||||
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
|
||||
|
||||
old_entry = pd->vg_entry;
|
||||
|
||||
Evas_Object_Protected_Data *obj;
|
||||
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
|
||||
|
||||
if (file)
|
||||
pd->vg_entry = evas_cache_vg_entry_create(file, key,
|
||||
obj->cur->geometry.w,
|
||||
obj->cur->geometry.h);
|
||||
obj->cur->geometry.h,
|
||||
mmap);
|
||||
else
|
||||
pd->vg_entry = NULL;
|
||||
|
||||
|
@ -270,7 +269,9 @@ _efl_canvas_vg_object_efl_file_file_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *p
|
|||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_canvas_vg_object_efl_file_file_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd, const char **file, const char **key)
|
||||
_efl_canvas_vg_object_efl_file_mmap_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd,
|
||||
const Eina_File **file, const char **key)
|
||||
{
|
||||
if (file) *file = NULL;
|
||||
if (key) *key = NULL;
|
||||
|
@ -282,6 +283,106 @@ _efl_canvas_vg_object_efl_file_file_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg
|
|||
}
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_canvas_vg_object_efl_file_mmap_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, const Eina_File *file, const char *key)
|
||||
{
|
||||
Eina_File *pf = pd->file;
|
||||
Eina_Bool ret;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
Evas_Object_Protected_Data *obj;
|
||||
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
|
||||
evas_cache_vg_entry_del(pd->vg_entry);
|
||||
evas_object_change(eo_obj, obj);
|
||||
eina_stringshare_del(pd->key);
|
||||
pd->vg_entry = NULL;
|
||||
pd->file = NULL;
|
||||
pd->key = NULL;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
if (pd->file == file)
|
||||
{
|
||||
if (!pd->key && !key) return EINA_FALSE;
|
||||
else if (pd->key && key)
|
||||
{
|
||||
if (!strcmp(pd->key, key)) return EINA_FALSE;
|
||||
}
|
||||
pf = NULL;
|
||||
}
|
||||
if (pd->file != file)
|
||||
pd->file = eina_file_dup(file);
|
||||
ret = _vg_file_mmap_set(eo_obj, pd, file, key, EINA_TRUE);
|
||||
|
||||
//Close previous file after deleting ex-cache entry.
|
||||
if (pf) eina_file_close(pf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_canvas_vg_object_efl_file_file_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, const char *file, const char *key)
|
||||
{
|
||||
Eina_File *pf = pd->file;
|
||||
Eina_Bool ret;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
Evas_Object_Protected_Data *obj;
|
||||
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
|
||||
evas_cache_vg_entry_del(pd->vg_entry);
|
||||
evas_object_change(eo_obj, obj);
|
||||
eina_stringshare_del(pd->key);
|
||||
pd->vg_entry = NULL;
|
||||
pd->file = NULL;
|
||||
pd->key = NULL;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
if (!pd->file)
|
||||
{
|
||||
pd->file = eina_file_open(file, EINA_FALSE);
|
||||
if (!pd->file) return EINA_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *filename = eina_file_filename_get(pd->file);
|
||||
if (filename)
|
||||
{
|
||||
if (strcmp(filename, file))
|
||||
pd->file = eina_file_open(file, EINA_FALSE);
|
||||
else
|
||||
{
|
||||
if (!pd->key && !key) return EINA_FALSE;
|
||||
else if (pd->key && key)
|
||||
{
|
||||
if (!strcmp(pd->key, key)) return EINA_FALSE;
|
||||
}
|
||||
pf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = _vg_file_mmap_set(eo_obj, pd, pd->file, key, EINA_FALSE);
|
||||
|
||||
//Close previous file after deleting ex-cache entry.
|
||||
if (pf) eina_file_close(pf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_canvas_vg_object_efl_file_file_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd, const char **file, const char **key)
|
||||
{
|
||||
if (file) *file = NULL;
|
||||
if (key) *key = NULL;
|
||||
|
||||
if (pd->vg_entry)
|
||||
{
|
||||
if (file) *file = eina_file_filename_get(pd->vg_entry->file);
|
||||
if (key) *key = pd->vg_entry->key;
|
||||
}
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_canvas_vg_object_efl_file_save(const Eo *obj, Efl_Canvas_Vg_Object_Data *pd, const char *file, const char *key, const char *flags)
|
||||
{
|
||||
|
@ -319,6 +420,18 @@ _efl_canvas_vg_object_efl_object_destructor(Eo *eo_obj, Efl_Canvas_Vg_Object_Dat
|
|||
pd->user_entry = NULL;
|
||||
evas_cache_vg_entry_del(pd->vg_entry);
|
||||
|
||||
//Close files after deleting entry.
|
||||
if (pd->file)
|
||||
{
|
||||
eina_file_close(pd->file);
|
||||
pd->file = NULL;
|
||||
}
|
||||
if (pd->key)
|
||||
{
|
||||
eina_stringshare_del(pd->key);
|
||||
pd->key = NULL;
|
||||
}
|
||||
|
||||
efl_destructor(efl_super(eo_obj, MY_CLASS));
|
||||
}
|
||||
|
||||
|
@ -425,7 +538,7 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
|
|||
static void *
|
||||
_render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
|
||||
void *engine, Efl_VG *root, int w, int h, void *key,
|
||||
void *buffer, Eina_Bool do_async)
|
||||
void *buffer, Eina_Bool do_async, Eina_Bool cacheable)
|
||||
{
|
||||
Ector_Surface *ector;
|
||||
RGBA_Draw_Context *context;
|
||||
|
@ -463,8 +576,11 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd
|
|||
ENFN->ector_end(engine, buffer, context, ector, do_async);
|
||||
evas_common_draw_context_free(context);
|
||||
|
||||
if (buffer_created)
|
||||
ENFN->ector_surface_cache_set(engine, key, buffer);
|
||||
if (buffer_created && cacheable)
|
||||
{
|
||||
ENFN->ector_surface_cache_set(engine, key, buffer);
|
||||
pd->cached_frame_idx = pd->frame_idx;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -474,7 +590,7 @@ _render_buffer_to_screen(Evas_Object_Protected_Data *obj,
|
|||
void *engine, void *output, void *context, void *surface,
|
||||
void *buffer,
|
||||
int x, int y, int w, int h,
|
||||
Eina_Bool do_async)
|
||||
Eina_Bool do_async, Eina_Bool cacheable)
|
||||
{
|
||||
Eina_Bool async_unref;
|
||||
|
||||
|
@ -490,50 +606,90 @@ _render_buffer_to_screen(Evas_Object_Protected_Data *obj,
|
|||
evas_cache_image_ref((Image_Entry *)buffer);
|
||||
evas_unref_queue_image_put(obj->layer->evas, buffer);
|
||||
}
|
||||
|
||||
//TODO: Reuse buffer if size is same?
|
||||
if (!cacheable) ENFN->ector_surface_destroy(engine, buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
_cache_vg_entry_render(Evas_Object_Protected_Data *obj,
|
||||
Efl_Canvas_Vg_Object_Data *pd,
|
||||
void *engine, void *output, void *context, void *surface,
|
||||
int x, int y, int w, int h, Eina_Bool do_async)
|
||||
int x, int y, int w, int h, Eina_Bool do_async,
|
||||
Eina_Bool cacheable)
|
||||
{
|
||||
Vg_Cache_Entry *vg_entry = pd->vg_entry;
|
||||
Efl_VG *root;
|
||||
Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio.
|
||||
|
||||
// if the size changed in between path set and the draw call;
|
||||
|
||||
if ((vg_entry->w != w) ||
|
||||
(vg_entry->h != h))
|
||||
{
|
||||
vg_entry = evas_cache_vg_entry_resize(vg_entry, w, h);
|
||||
evas_cache_vg_entry_del(pd->vg_entry);
|
||||
pd->vg_entry = vg_entry;
|
||||
}
|
||||
root = evas_cache_vg_tree_get(vg_entry);
|
||||
if (!root) return;
|
||||
Eina_Size2D size = evas_cache_vg_entry_default_size_get(pd->vg_entry);
|
||||
|
||||
void *buffer = ENFN->ector_surface_cache_get(engine, root);
|
||||
//adjust size for aspect ratio.
|
||||
if (size.w > 0 && size.h > 0)
|
||||
{
|
||||
float rw = (float) w / (float) size.w;
|
||||
float rh = (float) h / (float) size.h;
|
||||
|
||||
if (rw < rh)
|
||||
{
|
||||
size.w = w;
|
||||
size.h = (int) ((float) size.h * rw);
|
||||
}
|
||||
else
|
||||
{
|
||||
size.w = (int) ((float) size.w * rh);
|
||||
size.h = h;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size.w = w;
|
||||
size.h = h;
|
||||
}
|
||||
|
||||
vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
|
||||
evas_cache_vg_entry_del(pd->vg_entry);
|
||||
pd->vg_entry = vg_entry;
|
||||
|
||||
//update for adjusted pos and size.
|
||||
offset.x = w - size.w;
|
||||
if (offset.x > 0) offset.x /= 2;
|
||||
offset.y = h - size.h;
|
||||
if (offset.y > 0) offset.y /= 2;
|
||||
w = size.w;
|
||||
h = size.h;
|
||||
}
|
||||
root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx);
|
||||
if (!root) return;
|
||||
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);
|
||||
do_async, cacheable);
|
||||
else
|
||||
//cache reference was increased when we get the cache.
|
||||
ENFN->ector_surface_cache_drop(engine, root);
|
||||
ENFN->ector_surface_cache_drop(engine, (void *) root);
|
||||
|
||||
_render_buffer_to_screen(obj,
|
||||
engine, output, context, surface,
|
||||
buffer,
|
||||
x, y, w, h,
|
||||
do_async);
|
||||
x + offset.x, y + offset.y, w, h,
|
||||
do_async, cacheable);
|
||||
}
|
||||
|
||||
static void
|
||||
_user_vg_entry_render(Evas_Object_Protected_Data *obj,
|
||||
Efl_Canvas_Vg_Object_Data *pd,
|
||||
void *engine, void *output, void *context, void *surface,
|
||||
int x, int y, int w, int h, Eina_Bool do_async)
|
||||
int x, int y, int w, int h, Eina_Bool do_async,
|
||||
Eina_Bool cacheable)
|
||||
{
|
||||
Vg_User_Entry *user_entry = pd->user_entry;
|
||||
|
||||
|
@ -554,7 +710,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
|
|||
// render to the buffer
|
||||
buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
|
||||
w, h, user_entry, buffer,
|
||||
do_async);
|
||||
do_async, cacheable);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -565,7 +721,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
|
|||
w, h,
|
||||
user_entry,
|
||||
buffer,
|
||||
do_async);
|
||||
do_async, EINA_FALSE);
|
||||
//cache reference was increased when we get the cache.
|
||||
ENFN->ector_surface_cache_drop(engine, user_entry->root);
|
||||
}
|
||||
|
@ -574,7 +730,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
|
|||
engine, output, context, surface,
|
||||
buffer,
|
||||
x, y, w, h,
|
||||
do_async);
|
||||
do_async, cacheable);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -596,19 +752,30 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
|
|||
ENFN->context_anti_alias_set(engine, context, obj->cur->anti_alias);
|
||||
ENFN->context_render_op_set(engine, context, obj->cur->render_op);
|
||||
|
||||
//Cache surface?
|
||||
Eina_Bool cacheable = EINA_FALSE;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
_cache_vg_entry_render(obj, pd,
|
||||
engine, output, context, surface,
|
||||
obj->cur->geometry.x + x, obj->cur->geometry.y + y,
|
||||
obj->cur->geometry.w, obj->cur->geometry.h, do_async);
|
||||
obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
|
||||
}
|
||||
if (pd->user_entry)
|
||||
{
|
||||
_user_vg_entry_render(obj, pd,
|
||||
engine, output, context, surface,
|
||||
obj->cur->geometry.x + x, obj->cur->geometry.y + y,
|
||||
obj->cur->geometry.w, obj->cur->geometry.h, do_async);
|
||||
obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
|
||||
}
|
||||
pd->changed = EINA_FALSE;
|
||||
}
|
||||
|
@ -764,6 +931,79 @@ _efl_canvas_vg_object_was_opaque(Evas_Object *eo_obj EINA_UNUSED,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* animated feature */
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED EINA_UNUSED)
|
||||
{
|
||||
//TODO:
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EOLIAN static int
|
||||
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_frame_count_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
|
||||
{
|
||||
if (!pd->vg_entry) return 0;
|
||||
return evas_cache_vg_anim_frame_count_get(pd->vg_entry);
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Gfx_Image_Animation_Controller_Loop_Hint
|
||||
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_loop_type_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
|
||||
{
|
||||
//TODO:
|
||||
return EFL_GFX_IMAGE_ANIMATION_CONTROLLER_LOOP_HINT_NONE;
|
||||
}
|
||||
|
||||
EOLIAN static int
|
||||
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_loop_count_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
|
||||
{
|
||||
//TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
EOLIAN static double
|
||||
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_frame_duration_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd,
|
||||
int start_frame EINA_UNUSED,
|
||||
int frame_num EINA_UNUSED)
|
||||
{
|
||||
if (!pd->vg_entry) return 0;
|
||||
return evas_cache_vg_anim_duration_get(pd->vg_entry);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_canvas_vg_object_efl_gfx_image_animation_controller_animated_frame_set(Eo *eo_obj,
|
||||
Efl_Canvas_Vg_Object_Data *pd,
|
||||
int frame_index)
|
||||
{
|
||||
//TODO: Validate frame_index range
|
||||
if (pd->frame_idx == frame_index) return EINA_TRUE;
|
||||
|
||||
//Image is changed, drop previous cached image.
|
||||
pd->frame_idx = frame_index;
|
||||
pd->changed = EINA_TRUE;
|
||||
evas_object_change(eo_obj, efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS));
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EOLIAN static int
|
||||
_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_idx;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Size2D
|
||||
_efl_canvas_vg_object_default_size_get(const Eo *eo_obj EINA_UNUSED,
|
||||
Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
|
||||
{
|
||||
return evas_cache_vg_entry_default_size_get(pd->vg_entry);
|
||||
}
|
||||
|
||||
/* the actual api call to add a vector graphic object */
|
||||
EAPI Evas_Object *
|
||||
evas_object_vg_add(Evas *e)
|
||||
|
@ -774,4 +1014,40 @@ evas_object_vg_add(Evas *e)
|
|||
return efl_add(MY_CLASS, e, efl_canvas_object_legacy_ctor(efl_added));
|
||||
}
|
||||
|
||||
EAPI int
|
||||
evas_object_vg_animated_frame_get(const Evas_Object *obj)
|
||||
{
|
||||
return efl_gfx_image_animated_frame_get(obj);
|
||||
}
|
||||
|
||||
EAPI double
|
||||
evas_object_vg_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num)
|
||||
{
|
||||
return efl_gfx_image_animated_frame_duration_get(obj, start_frame, frame_num);
|
||||
}
|
||||
|
||||
EAPI int
|
||||
evas_object_vg_animated_frame_count_get(const Evas_Object *obj)
|
||||
{
|
||||
return efl_gfx_image_animated_frame_count_get(obj);
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
evas_object_vg_animated_frame_set(Evas_Object *obj, int frame_index)
|
||||
{
|
||||
return efl_gfx_image_animated_frame_set(obj, frame_index);
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
evas_object_vg_mmap_set(Evas_Object *obj, const Eina_File *f, const char *key)
|
||||
{
|
||||
return efl_file_mmap_set(obj, f, key);
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
evas_object_vg_file_set(Evas_Object *obj, const char *file, const char *key)
|
||||
{
|
||||
return efl_file_set(obj, file, key);
|
||||
}
|
||||
|
||||
#include "efl_canvas_vg_object.eo.c"
|
||||
|
|
|
@ -21,7 +21,7 @@ enum Efl.Canvas.Vg.Fill_Mode
|
|||
dimension of the viewport.]]
|
||||
}
|
||||
|
||||
class Efl.Canvas.Vg.Object (Efl.Canvas.Object, Efl.File)
|
||||
class Efl.Canvas.Vg.Object (Efl.Canvas.Object, Efl.File, Efl.Gfx.Image_Animation_Controller)
|
||||
{
|
||||
[[Efl vector graphics class]]
|
||||
legacy_prefix: evas_object_vg;
|
||||
|
@ -68,13 +68,28 @@ class Efl.Canvas.Vg.Object (Efl.Canvas.Object, Efl.File)
|
|||
root: Efl.Canvas.Vg.Node; [[Root node of the VG canvas.]]
|
||||
}
|
||||
}
|
||||
@property default_size {
|
||||
get {
|
||||
[[Get the default vector size that specified from vector resource.
|
||||
@since 1.22]]
|
||||
}
|
||||
values {
|
||||
size: Eina.Size2D;
|
||||
}
|
||||
}
|
||||
}
|
||||
implements {
|
||||
Efl.Object.constructor;
|
||||
Efl.Object.finalize;
|
||||
Efl.Object.destructor;
|
||||
// FIXME: Implement mmap only (also fix cache keys)
|
||||
Efl.File.mmap { get; set; }
|
||||
Efl.File.file { get; set; }
|
||||
Efl.File.save;
|
||||
Efl.Gfx.Image_Animation_Controller.animated { get; }
|
||||
Efl.Gfx.Image_Animation_Controller.animated_frame { get; set; }
|
||||
Efl.Gfx.Image_Animation_Controller.animated_frame_count { get; }
|
||||
Efl.Gfx.Image_Animation_Controller.animated_loop_type { get; }
|
||||
Efl.Gfx.Image_Animation_Controller.animated_loop_count { get; }
|
||||
Efl.Gfx.Image_Animation_Controller.animated_frame_duration { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,15 @@ typedef struct _Vg_Cache
|
|||
typedef struct _Vg_Cache_Entry
|
||||
{
|
||||
char *hash_key;
|
||||
Eina_Stringshare *file;
|
||||
const Eina_File *file;
|
||||
Eina_Stringshare *key;
|
||||
int w;
|
||||
int h;
|
||||
Efl_VG *root;
|
||||
Efl_VG *root[3]; //0: default, 1: start frame, 2: end frame
|
||||
int ref;
|
||||
Vg_File_Data *vfd;
|
||||
|
||||
Eina_Bool mmap : 1;
|
||||
} Vg_Cache_Entry;
|
||||
|
||||
// holds the vg tree info set by the user
|
||||
|
@ -49,6 +50,10 @@ struct _Efl_Canvas_Vg_Object_Data
|
|||
Eina_Array cleanup;
|
||||
double align_x, align_y;
|
||||
Efl_Canvas_Vg_Fill_Mode fill_mode;
|
||||
int frame_idx;
|
||||
Eina_File *file;
|
||||
Eina_Stringshare *key;
|
||||
int cached_frame_idx;
|
||||
|
||||
Eina_Bool changed : 1;
|
||||
};
|
||||
|
@ -119,12 +124,15 @@ struct _Efl_Canvas_Vg_Interpolation
|
|||
void evas_cache_vg_init(void);
|
||||
void evas_cache_vg_shutdown(void);
|
||||
Vg_Cache_Entry* evas_cache_vg_entry_resize(Vg_Cache_Entry *entry, int w, int h);
|
||||
Vg_Cache_Entry* evas_cache_vg_entry_create(const char *file, const char *key, int w, int h);
|
||||
Efl_VG* evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry);
|
||||
Vg_Cache_Entry* evas_cache_vg_entry_create(const Eina_File *file, const char *key, int w, int h, Eina_Bool mmap);
|
||||
Efl_VG* evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num);
|
||||
void evas_cache_vg_entry_del(Vg_Cache_Entry *vg_entry);
|
||||
Vg_File_Data * evas_cache_vg_file_open(const char *file, const char *key);
|
||||
Vg_File_Data * evas_cache_vg_file_open(const Eina_File *file, const char *key, Eina_Bool mmap);
|
||||
Eina_Bool evas_cache_vg_file_save(Efl_VG *root, int w, int h, const char *file, const char *key, const char *flags);
|
||||
Eina_Bool evas_cache_vg_entry_file_save(Vg_Cache_Entry *vg_entry, const char *file, const char *key, const char *flags);
|
||||
double evas_cache_vg_anim_duration_get(const Vg_Cache_Entry *vg_entry);
|
||||
unsigned int evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry *vg_entry);
|
||||
Eina_Size2D evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry);
|
||||
void efl_canvas_vg_node_vg_obj_set(Efl_VG *node, Efl_VG *vg_obj, Efl_Canvas_Vg_Object_Data *vd);
|
||||
void efl_canvas_vg_node_change(Efl_VG *node);
|
||||
void efl_canvas_vg_container_vg_obj_update(Efl_VG *obj, Efl_Canvas_Vg_Node_Data *nd);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -138,6 +138,7 @@ typedef struct _Evas_Canvas3D_Header_Eet Evas_Canvas3D_Header_Eet;
|
|||
typedef struct _Evas_Canvas3D_File_Eet Evas_Canvas3D_File_Eet;
|
||||
|
||||
typedef struct _Vg_File_Data Vg_File_Data;
|
||||
typedef struct _Vg_File_Anim_Data Vg_File_Anim_Data;
|
||||
|
||||
struct _Evas_Canvas3D_Vec2_Eet
|
||||
{
|
||||
|
@ -1505,12 +1506,23 @@ struct _Evas_Image_Save_Func
|
|||
int (*image_save) (RGBA_Image *im, const char *file, const char *key, int quality, int compress, const char *encoding);
|
||||
};
|
||||
|
||||
struct _Vg_File_Anim_Data
|
||||
{
|
||||
unsigned int frame_num; //current frame number
|
||||
unsigned int frame_cnt; //total frame count
|
||||
float duration; //animation duration
|
||||
};
|
||||
|
||||
struct _Vg_File_Data
|
||||
{
|
||||
Efl_VG *root;
|
||||
Evas_Vg_Load_Func *loader;
|
||||
Eina_Rectangle view_box;
|
||||
Eina_Rectangle view_box;
|
||||
Vg_File_Anim_Data *anim_data; //only when animation supported.
|
||||
int ref;
|
||||
int w, h; //default size
|
||||
|
||||
void *loader_data; //loader specific local data
|
||||
|
||||
Eina_Bool static_viewbox: 1;
|
||||
Eina_Bool preserve_aspect : 1; //Used in SVG
|
||||
|
@ -1518,7 +1530,7 @@ struct _Vg_File_Data
|
|||
|
||||
struct _Evas_Vg_Load_Func
|
||||
{
|
||||
Vg_File_Data *(*file_open) (const char *file, const char *key, int *error);
|
||||
Vg_File_Data *(*file_open) (Eina_File *file, const char *key, Eina_Bool mmap, int *error);
|
||||
Eina_Bool (*file_close) (Vg_File_Data *vfd);
|
||||
Eina_Bool (*file_data) (Vg_File_Data *vfd);
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ static const struct ext_loader_s loaders[] =
|
|||
|
||||
static const char *loaders_name[] =
|
||||
{ /* in order of most likely needed */
|
||||
"eet", "svg"
|
||||
"eet", "json", "svg"
|
||||
};
|
||||
|
||||
static const struct ext_saver_s savers[] =
|
||||
|
@ -70,7 +70,7 @@ _find_loader_module(const char *file)
|
|||
}
|
||||
|
||||
static Vg_File_Data *
|
||||
_vg_load_from_file(const char *file, const char *key)
|
||||
_vg_load_from_file(const Eina_File *file, const char *key, Eina_Bool mmap)
|
||||
{
|
||||
Evas_Module *em;
|
||||
Evas_Vg_Load_Func *loader;
|
||||
|
@ -78,11 +78,12 @@ _vg_load_from_file(const char *file, const char *key)
|
|||
Vg_File_Data *vfd;
|
||||
unsigned int i;
|
||||
|
||||
em = _find_loader_module(file);
|
||||
const char *file_name = eina_file_filename_get(file);
|
||||
em = _find_loader_module(file_name);
|
||||
if (em)
|
||||
{
|
||||
loader = em->functions;
|
||||
vfd = loader->file_open(file, key, &error);
|
||||
vfd = loader->file_open((Eina_File *) file, key, mmap, &error);
|
||||
if (vfd)
|
||||
{
|
||||
vfd->loader = loader;
|
||||
|
@ -97,7 +98,8 @@ _vg_load_from_file(const char *file, const char *key)
|
|||
if (em)
|
||||
{
|
||||
loader = em->functions;
|
||||
vfd = loader->file_open(file, key, &error);
|
||||
vfd = loader->file_open((Eina_File *) file, key, mmap, &error);
|
||||
if (vfd)
|
||||
{
|
||||
vfd->loader = loader;
|
||||
return vfd;
|
||||
|
@ -105,7 +107,7 @@ _vg_load_from_file(const char *file, const char *key)
|
|||
}
|
||||
}
|
||||
}
|
||||
WRN("Exhausted all means to load vector file = %s", file);
|
||||
WRN("Exhausted all means to load vector file = %s", file_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -152,7 +154,7 @@ _evas_cache_vg_entry_free_cb(void *data)
|
|||
{
|
||||
Eina_Strbuf *hash_key = eina_strbuf_new();
|
||||
eina_strbuf_append_printf(hash_key, "%s/%s",
|
||||
vg_entry->file,
|
||||
eina_file_filename_get(vg_entry->file),
|
||||
vg_entry->key);
|
||||
if (!eina_hash_del(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key), vg_entry->vfd))
|
||||
ERR("Failed to delete vfd = (%p) from hash", vg_entry->vfd);
|
||||
|
@ -162,7 +164,9 @@ _evas_cache_vg_entry_free_cb(void *data)
|
|||
|
||||
eina_stringshare_del(vg_entry->key);
|
||||
free(vg_entry->hash_key);
|
||||
efl_unref(vg_entry->root);
|
||||
efl_unref(vg_entry->root[0]);
|
||||
efl_unref(vg_entry->root[1]);
|
||||
efl_unref(vg_entry->root[2]);
|
||||
free(vg_entry);
|
||||
}
|
||||
|
||||
|
@ -208,9 +212,37 @@ _vg_file_save(Vg_File_Data *vfd, const char *file, const char *key, const char *
|
|||
}
|
||||
|
||||
static Efl_VG*
|
||||
_cached_root_get(Vg_Cache_Entry *vg_entry)
|
||||
_cached_root_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num)
|
||||
{
|
||||
return vg_entry->root;
|
||||
Vg_File_Data *vfd = vg_entry->vfd;
|
||||
|
||||
//Case 1: Animatable
|
||||
if (vfd->anim_data)
|
||||
{
|
||||
//Start frame
|
||||
if (vg_entry->root[1] && frame_num == 0)
|
||||
{
|
||||
return vg_entry->root[1];
|
||||
}
|
||||
//End frame
|
||||
else if (vg_entry->root[2] && (frame_num == (vfd->anim_data->frame_cnt - 1)))
|
||||
{
|
||||
return vg_entry->root[2];
|
||||
}
|
||||
//Current frame
|
||||
else if (vg_entry->root[0] && (frame_num == (vfd->anim_data->frame_num)))
|
||||
{
|
||||
return vg_entry->root[0];
|
||||
}
|
||||
}
|
||||
//Case 2: Static
|
||||
else
|
||||
{
|
||||
if (vg_entry->root[0])
|
||||
return vg_entry->root[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -227,12 +259,34 @@ _caching_root_update(Vg_Cache_Entry *vg_entry)
|
|||
/* TODO: Yet trivial but still we may have a better solution to
|
||||
avoid this unnecessary copy. If the ector surface key is not
|
||||
to this root pointer. */
|
||||
vg_entry->root = efl_duplicate(vfd->root);
|
||||
vg_entry->root[0] = efl_duplicate(vfd->root);
|
||||
}
|
||||
else if (vg_entry->root != vfd->root)
|
||||
else if (vg_entry->root[0] != vfd->root)
|
||||
{
|
||||
if (vg_entry->root) efl_unref(vg_entry->root);
|
||||
vg_entry->root = efl_ref(vfd->root);
|
||||
if (vg_entry->root[0]) efl_unref(vg_entry->root[0]);
|
||||
vg_entry->root[0] = efl_ref(vfd->root);
|
||||
}
|
||||
|
||||
//Animatable?
|
||||
if (!vfd->anim_data) return;
|
||||
|
||||
//Start frame
|
||||
if (vfd->anim_data->frame_num == 0)
|
||||
{
|
||||
if (vg_entry->root[1] != vfd->root)
|
||||
{
|
||||
if (vg_entry->root[1]) efl_unref(vg_entry->root[1]);
|
||||
vg_entry->root[1] = efl_ref(vfd->root);
|
||||
}
|
||||
}
|
||||
//End frame
|
||||
else if (vfd->anim_data->frame_num == (vfd->anim_data->frame_cnt - 1))
|
||||
{
|
||||
if (vg_entry->root[2] != vfd->root)
|
||||
{
|
||||
if (vg_entry->root[2]) efl_unref(vg_entry->root[2]);
|
||||
vg_entry->root[2] = efl_ref(vfd->root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,17 +353,17 @@ evas_cache_vg_shutdown(void)
|
|||
}
|
||||
|
||||
Vg_File_Data *
|
||||
evas_cache_vg_file_open(const char *file, const char *key)
|
||||
evas_cache_vg_file_open(const Eina_File *file, const char *key, Eina_Bool mmap)
|
||||
{
|
||||
Vg_File_Data *vfd;
|
||||
Eina_Strbuf *hash_key;
|
||||
|
||||
hash_key = eina_strbuf_new();
|
||||
eina_strbuf_append_printf(hash_key, "%s/%s", file, key);
|
||||
eina_strbuf_append_printf(hash_key, "%s/%s", eina_file_filename_get(file), key);
|
||||
vfd = eina_hash_find(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key));
|
||||
if (!vfd)
|
||||
{
|
||||
vfd = _vg_load_from_file(file, key);
|
||||
vfd = _vg_load_from_file(file, key, mmap);
|
||||
//File exists.
|
||||
if (vfd) eina_hash_add(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key), vfd);
|
||||
}
|
||||
|
@ -320,13 +374,14 @@ evas_cache_vg_file_open(const char *file, const char *key)
|
|||
Vg_Cache_Entry*
|
||||
evas_cache_vg_entry_resize(Vg_Cache_Entry *vg_entry, int w, int h)
|
||||
{
|
||||
return evas_cache_vg_entry_create(vg_entry->file, vg_entry->key, w, h);
|
||||
return evas_cache_vg_entry_create(vg_entry->file, vg_entry->key, w, h, vg_entry->mmap);
|
||||
}
|
||||
|
||||
Vg_Cache_Entry*
|
||||
evas_cache_vg_entry_create(const char *file,
|
||||
evas_cache_vg_entry_create(const Eina_File *file,
|
||||
const char *key,
|
||||
int w, int h)
|
||||
int w, int h,
|
||||
Eina_Bool mmap)
|
||||
{
|
||||
Vg_Cache_Entry* vg_entry;
|
||||
Eina_Strbuf *hash_key;
|
||||
|
@ -336,7 +391,7 @@ evas_cache_vg_entry_create(const char *file,
|
|||
//TODO: zero-sized entry is useless. how to skip it?
|
||||
|
||||
hash_key = eina_strbuf_new();
|
||||
eina_strbuf_append_printf(hash_key, "%s/%s/%d/%d", file, key, w, h);
|
||||
eina_strbuf_append_printf(hash_key, "%p/%s/%d/%d", file, key, w, h);
|
||||
vg_entry = eina_hash_find(vg_cache->vg_entry_hash, eina_strbuf_string_get(hash_key));
|
||||
if (!vg_entry)
|
||||
{
|
||||
|
@ -347,17 +402,18 @@ evas_cache_vg_entry_create(const char *file,
|
|||
eina_strbuf_free(hash_key);
|
||||
return NULL;
|
||||
}
|
||||
vg_entry->file = eina_stringshare_add(file);
|
||||
vg_entry->file = file;
|
||||
vg_entry->key = eina_stringshare_add(key);
|
||||
vg_entry->w = w;
|
||||
vg_entry->h = h;
|
||||
vg_entry->hash_key = eina_strbuf_string_steal(hash_key);
|
||||
vg_entry->mmap = mmap;
|
||||
eina_hash_direct_add(vg_cache->vg_entry_hash, vg_entry->hash_key, vg_entry);
|
||||
}
|
||||
eina_strbuf_free(hash_key);
|
||||
vg_entry->ref++;
|
||||
|
||||
vg_entry->vfd = evas_cache_vg_file_open(file, key);
|
||||
vg_entry->vfd = evas_cache_vg_file_open(file, key, mmap);
|
||||
//No File??
|
||||
if (!vg_entry->vfd)
|
||||
{
|
||||
|
@ -369,8 +425,24 @@ evas_cache_vg_entry_create(const char *file,
|
|||
return vg_entry;
|
||||
}
|
||||
|
||||
double
|
||||
evas_cache_vg_anim_duration_get(const Vg_Cache_Entry* vg_entry)
|
||||
{
|
||||
if (!vg_entry->vfd->anim_data) return 0;
|
||||
return vg_entry->vfd->anim_data->duration;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry* vg_entry)
|
||||
{
|
||||
if (!vg_entry) return 0;
|
||||
Vg_File_Data *vfd = vg_entry->vfd;
|
||||
if (!vfd || !vfd->anim_data) return 0;
|
||||
return vfd->anim_data->frame_cnt;
|
||||
}
|
||||
|
||||
Efl_VG*
|
||||
evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry)
|
||||
evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num)
|
||||
{
|
||||
if (!vg_entry) return NULL;
|
||||
if ((vg_entry->w < 1) || (vg_entry->h < 1)) return NULL;
|
||||
|
@ -378,7 +450,7 @@ evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry)
|
|||
Vg_File_Data *vfd = vg_entry->vfd;
|
||||
if (!vfd) return NULL;
|
||||
|
||||
Efl_VG *root = _cached_root_get(vg_entry);
|
||||
Efl_VG *root = _cached_root_get(vg_entry, frame_num);
|
||||
if (root) return root;
|
||||
|
||||
if (!vfd->static_viewbox)
|
||||
|
@ -387,13 +459,15 @@ evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry)
|
|||
vfd->view_box.h = vg_entry->h;
|
||||
}
|
||||
|
||||
if (vfd->anim_data) vfd->anim_data->frame_num = frame_num;
|
||||
|
||||
if (!vfd->loader->file_data(vfd)) return NULL;
|
||||
|
||||
_caching_root_update(vg_entry);
|
||||
|
||||
_local_transform(vg_entry->root, vg_entry->w, vg_entry->h, vfd);
|
||||
_local_transform(vg_entry->root[0], vg_entry->w, vg_entry->h, vfd);
|
||||
|
||||
return vg_entry->root;
|
||||
return vg_entry->root[0];
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -406,12 +480,19 @@ evas_cache_vg_entry_del(Vg_Cache_Entry *vg_entry)
|
|||
ERR("Failed to delete vg_entry = (%p) from hash", vg_entry);
|
||||
}
|
||||
|
||||
Eina_Size2D
|
||||
evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry)
|
||||
{
|
||||
if (!vg_entry) return EINA_SIZE2D(0, 0);
|
||||
return EINA_SIZE2D(vg_entry->vfd->w, vg_entry->vfd->h);
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
evas_cache_vg_entry_file_save(Vg_Cache_Entry *vg_entry, const char *file, const char *key,
|
||||
const char *flags)
|
||||
{
|
||||
Vg_File_Data *vfd =
|
||||
evas_cache_vg_file_open(vg_entry->file, vg_entry->key);
|
||||
evas_cache_vg_file_open(vg_entry->file, vg_entry->key, EINA_FALSE);
|
||||
|
||||
if (!vfd) return EINA_FALSE;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ evas_static_list = []
|
|||
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')
|
||||
|
|
|
@ -13,13 +13,11 @@ static int _evas_vg_loader_eet_log_dom = -1;
|
|||
#define INF(...) EINA_LOG_DOM_INFO(_evas_vg_loader_eet_log_dom, __VA_ARGS__)
|
||||
|
||||
static Vg_File_Data*
|
||||
evas_vg_load_file_open_eet(const char *file, const char *key, int *error EINA_UNUSED)
|
||||
evas_vg_load_file_open_eet(Eina_File *file, const char *key, Eina_Bool mmap EINA_UNUSED, int *error EINA_UNUSED)
|
||||
{
|
||||
Eet_Data_Descriptor *svg_node_eet;
|
||||
Svg_Node *node;
|
||||
Eet_File *ef;
|
||||
|
||||
ef = eet_open(file, EET_FILE_MODE_READ);
|
||||
Eet_File *ef = eet_mmap(file);
|
||||
if (!ef)
|
||||
{
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
#include <lottieanimation_capi.h>
|
||||
#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,
|
||||
Eina_Bool mmap,
|
||||
int *error EINA_UNUSED)
|
||||
{
|
||||
Vg_File_Data *vfd = calloc(1, sizeof(Vg_File_Data));
|
||||
if (!vfd) return NULL;
|
||||
|
||||
Lottie_Animation *lot_anim = NULL;
|
||||
|
||||
if (mmap)
|
||||
{
|
||||
const char *data = (const char*) eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
|
||||
if (!data) goto err;
|
||||
lot_anim = lottie_animation_from_data(data, key ? key:eina_file_filename_get(file));
|
||||
eina_file_map_free(file, (void *) data);
|
||||
}
|
||||
else
|
||||
{
|
||||
lot_anim = lottie_animation_from_file(eina_file_filename_get(file));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -2339,7 +2339,10 @@ evas_vg_load_file_close_svg(Vg_File_Data *vfd)
|
|||
}
|
||||
|
||||
static Vg_File_Data*
|
||||
evas_vg_load_file_open_svg(const char *file, const char *key EINA_UNUSED, int *error EINA_UNUSED)
|
||||
evas_vg_load_file_open_svg(Eina_File *file,
|
||||
const char *key EINA_UNUSED,
|
||||
Eina_Bool mmap EINA_UNUSED,
|
||||
int *error EINA_UNUSED)
|
||||
{
|
||||
Evas_SVG_Loader loader = {
|
||||
NULL, NULL, NULL, NULL, NULL, 0, EINA_FALSE
|
||||
|
@ -2347,18 +2350,10 @@ evas_vg_load_file_open_svg(const char *file, const char *key EINA_UNUSED, int *e
|
|||
const char *content;
|
||||
unsigned int length;
|
||||
Svg_Node *defs;
|
||||
Eina_File *f;
|
||||
|
||||
f = eina_file_open(file, EINA_FALSE);
|
||||
if (!f)
|
||||
{
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
loader.svg_parse = calloc(1, sizeof(Evas_SVG_Parser));
|
||||
length = eina_file_size_get(f);
|
||||
content = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
|
||||
length = eina_file_size_get(file);
|
||||
content = eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
|
||||
if (content)
|
||||
{
|
||||
loader.stack = eina_array_new(8);
|
||||
|
@ -2366,7 +2361,7 @@ evas_vg_load_file_open_svg(const char *file, const char *key EINA_UNUSED, int *e
|
|||
_evas_svg_loader_parser, &loader);
|
||||
|
||||
eina_array_free(loader.stack);
|
||||
eina_file_map_free(f, (void*) content);
|
||||
eina_file_map_free(file, (void*) content);
|
||||
}
|
||||
|
||||
if (loader.doc)
|
||||
|
@ -2383,7 +2378,7 @@ evas_vg_load_file_open_svg(const char *file, const char *key EINA_UNUSED, int *e
|
|||
*error = EVAS_LOAD_ERROR_GENERIC;
|
||||
}
|
||||
free(loader.svg_parse);
|
||||
eina_file_close(f);
|
||||
|
||||
return vg_common_svg_create_vg_node(loader.doc);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,18 @@ vg_common_src = files([
|
|||
'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,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -317,4 +317,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_
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "vg_common.h"
|
||||
#include <Evas.h>
|
||||
|
||||
#ifdef BUILD_VG_LOADER_JSON
|
||||
|
||||
#include <lottieanimation_capi.h>
|
||||
|
||||
static char*
|
||||
_get_key_val(void *key)
|
||||
{
|
||||
static char buf[20];
|
||||
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
|
||||
_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.
|
||||
LOTMatteType matte = MatteNone;
|
||||
|
||||
//Is this layer a container layer?
|
||||
for (unsigned int i = 0; i < layer->mLayerList.size; i++)
|
||||
{
|
||||
LOTLayerNode *clayer = layer->mLayerList.ptr[i];
|
||||
|
||||
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, ptree);
|
||||
#endif
|
||||
_update_vg_tree(ctree, clayer, depth+1);
|
||||
|
||||
//TODO: Only valid for MatteAlphaInverse?
|
||||
//TODO: Set this blending option to efl_canvas_vg_node...
|
||||
if (matte != MatteNone)
|
||||
efl_canvas_vg_node_mask_set(ptree, ctree, matte);
|
||||
|
||||
matte = clayer->mMatte;
|
||||
ptree = ctree;
|
||||
|
||||
//Debug Matte Info
|
||||
switch (matte)
|
||||
{
|
||||
case MatteNone:
|
||||
case MatteAlphaInv:
|
||||
case MatteAlpha:
|
||||
break;
|
||||
case MatteLuma:
|
||||
ERR("TODO: MatteLuma");
|
||||
break;
|
||||
case MatteLumaInv:
|
||||
ERR("TODO: MatteLumaInv");
|
||||
break;
|
||||
default:
|
||||
ERR("No reserved Matte type = %d", matte);
|
||||
}
|
||||
}
|
||||
|
||||
//Construct drawable nodes.
|
||||
if (layer->mNodeList.size > 0)
|
||||
_construct_drawable_nodes(root, layer, 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;
|
||||
}
|
Loading…
Reference in New Issue