summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHermet Park <hermetpark@gmail.com>2019-06-21 17:32:37 +0900
committerHermet Park <hermetpark@gmail.com>2019-06-21 17:35:48 +0900
commit625e11f584fa00c6a2adc160ed20d96f3763d130 (patch)
tree77ad5b58d58583fdea7e5f9ab76d272fb35bf410
parent23af6ec640c4166aa912f8d6be1e3b78b0780913 (diff)
evas vector: support lottie animation as using json loader.
Summary: This patch extends efl_canvas_vg_object class to implement efl_gfx_frame_controller to suppor any playable animation on it. Plus, vector object takes care of lottie animation by using json loader. it's caching mechanism is changed to cache only static frame, not all frames. vg_cache supports json loader and make it animation request properly. This feature has been stabilized enough, it's using in Samsung Galaxy Watch active product, proved its stability enough. Depends on {D8940} Co-authored-by: JunsuChoi <jsuya.choi@samsung.com> Reviewers: #committers, jsuya Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8941
-rw-r--r--src/lib/evas/Evas_Legacy.h76
-rw-r--r--src/lib/evas/canvas/efl_canvas_vg_container.c8
-rw-r--r--src/lib/evas/canvas/efl_canvas_vg_object.c223
-rw-r--r--src/lib/evas/canvas/efl_canvas_vg_object.eo18
-rw-r--r--src/lib/evas/canvas/evas_vg_private.h9
-rw-r--r--src/lib/evas/include/evas_private.h15
-rw-r--r--src/lib/evas/vg/evas_vg_cache.c125
7 files changed, 423 insertions, 51 deletions
diff --git a/src/lib/evas/Evas_Legacy.h b/src/lib/evas/Evas_Legacy.h
index 3e4ae59c25..ff92ad8bbe 100644
--- a/src/lib/evas/Evas_Legacy.h
+++ b/src/lib/evas/Evas_Legacy.h
@@ -3613,6 +3613,82 @@ EAPI Evas_Object *evas_object_rectangle_add(Evas *e) EINA_WARN_UNUSED_RESULT EIN
3613 */ 3613 */
3614EAPI Evas_Object *evas_object_vg_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; 3614EAPI Evas_Object *evas_object_vg_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
3615 3615
3616/**
3617 * Get the total number of frames of the vector, if it's animated.
3618 *
3619 * @return The number of frames. 0, if it's not animated.
3620 *
3621 * @since 1.23
3622 */
3623EAPI int evas_object_vg_animated_frame_count_get(const Evas_Object *obj) EINA_ARG_NONNULL(1);
3624
3625/**
3626 * Get the duration of a sequence of frames.
3627 *
3628 * This returns total duration in seconds that the specified
3629 * sequence of frames should take.
3630 *
3631 * If @p start_frame is 1 and @p frame_num is 0, this returns the
3632 * duration of frame 1. If @p start_frame is 1 and @p frame_num is 1,
3633 * this returns the total duration of frame 1 + frame 2.
3634 *
3635 * @param[in] start_frame The first frame, ranges from 1 to maximum frame count.
3636 * @param[in] frame_num Number of frames in the sequence, starts from 0.
3637 *
3638 * @return Duration in seconds.
3639 *
3640 * @see evas_object_vg_animated_frame_count_get()
3641 * @since 1.23
3642 */
3643EAPI double evas_object_vg_animated_frame_duration_get(const Evas_Object *obj, int start_frame EINA_UNUSED, int frame_num EINA_UNUSED) EINA_ARG_NONNULL(1);
3644
3645/**
3646 *
3647 * Set the source file from where an vector object must fetch the real
3648 * vector data (it may be one of json, svg, eet files).
3649 *
3650 * If the file supports multiple data stored in it (as Eet files do),
3651 * you can specify the key to be used as the index of the vector in
3652 * this file.
3653 *
3654 * @param[in] file The vector file path.
3655 * @param[in] key The vector key in @p file (if its an Eet one), or @c
3656NULL, otherwise.
3657 *
3658 * @return @c EINA_TRUE if it's succeed to read file, @c EINA_FALSE otherwise.
3659 *
3660 * @since 1.23
3661 */
3662EAPI Eina_Bool evas_object_vg_file_set(Evas_Object *obj, const char *file, const char *key);
3663
3664/**
3665 * Set current frame of animated vector object.
3666 *
3667 * @param[in] frame_index The index of current frame.
3668 *
3669 * @note the @p frame_index must be in range of animation frames. (0 ~ max frame count)
3670 *
3671 * @return @c EINA_TRUE, if the frame index is valid. @c EINA_FALSE, otherwise.
3672 *
3673 * @see evas_object_vg_animated_frame_count_get()
3674 *
3675 * @since 1.23
3676 */
3677EAPI Eina_Bool evas_object_vg_animated_frame_set(Evas_Object *obj, int frame_index) EINA_ARG_NONNULL(1, 2);
3678
3679/**
3680 * Get the current frame number of animated vector object.
3681 *
3682 * @return The frame index.
3683 *
3684 * @see evas_object_vg_animated_frame_set()
3685 * @see evas_object_vg_animated_frame_count_get()
3686 *
3687 * @since 1.23
3688 */
3689EAPI int evas_object_vg_animated_frame_get(const Evas_Object *obj) EINA_ARG_NONNULL(1);
3690
3691
3616#include "canvas/efl_canvas_vg_node_eo.legacy.h" 3692#include "canvas/efl_canvas_vg_node_eo.legacy.h"
3617#include "canvas/efl_canvas_vg_object_eo.legacy.h" 3693#include "canvas/efl_canvas_vg_object_eo.legacy.h"
3618#include "canvas/efl_canvas_vg_container_eo.legacy.h" 3694#include "canvas/efl_canvas_vg_container_eo.legacy.h"
diff --git a/src/lib/evas/canvas/efl_canvas_vg_container.c b/src/lib/evas/canvas/efl_canvas_vg_container.c
index 2c55071a4d..4d11e0b5cb 100644
--- a/src/lib/evas/canvas/efl_canvas_vg_container.c
+++ b/src/lib/evas/canvas/efl_canvas_vg_container.c
@@ -124,7 +124,7 @@ _prepare_mask(Evas_Object_Protected_Data *obj, //vector object
124 if (!pd->mask.buffer) ERR("Mask Buffer is invalid"); 124 if (!pd->mask.buffer) ERR("Mask Buffer is invalid");
125 125
126 //FIXME: This code means that there is another masking container. 126 //FIXME: This code means that there is another masking container.
127 if (pd->mask.option != EFL_CANVAS_VG_NODE_BLEND_TYPE_NONE) 127 if (pd->mask.option >= EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD)
128 { 128 {
129 Efl_Canvas_Vg_Container_Data *src_pd = pd; 129 Efl_Canvas_Vg_Container_Data *src_pd = pd;
130 mask = pd->mask.buffer; 130 mask = pd->mask.buffer;
@@ -178,7 +178,11 @@ _efl_canvas_vg_container_render_pre(Evas_Object_Protected_Data *vg_pd,
178 EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd); 178 EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd);
179 179
180 //Container may have mask source. 180 //Container may have mask source.
181 if (pd->mask_src && !pd->mask.target) 181 //FIXME : _prepare_mask() should only work in cases with matte or main mask.
182 // This condition is valid because the main mask use same type as matte alpha.
183 if (pd->mask_src &&
184 (pd->mask.option == EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA ||
185 pd->mask.option == EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV))
182 { 186 {
183 mask_op = pd->mask.option; 187 mask_op = pd->mask.option;
184 mask = _prepare_mask(vg_pd, pd->mask_src, 188 mask = _prepare_mask(vg_pd, pd->mask_src,
diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.c b/src/lib/evas/canvas/efl_canvas_vg_object.c
index 026640a80a..e8c1524432 100644
--- a/src/lib/evas/canvas/efl_canvas_vg_object.c
+++ b/src/lib/evas/canvas/efl_canvas_vg_object.c
@@ -117,7 +117,7 @@ _efl_canvas_vg_object_root_node_get(const Eo *obj, Efl_Canvas_Vg_Object_Data *pd
117 evas_cache_vg_entry_del(pd->vg_entry); 117 evas_cache_vg_entry_del(pd->vg_entry);
118 pd->vg_entry = vg_entry; 118 pd->vg_entry = vg_entry;
119 } 119 }
120 root = evas_cache_vg_tree_get(pd->vg_entry); 120 root = evas_cache_vg_tree_get(pd->vg_entry, pd->frame_idx);
121 } 121 }
122 else if (pd->user_entry) root = pd->user_entry->root; 122 else if (pd->user_entry) root = pd->user_entry->root;
123 else root = pd->root; 123 else root = pd->root;
@@ -459,7 +459,7 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
459static void * 459static void *
460_render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, 460_render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
461 void *engine, Efl_VG *root, int w, int h, void *buffer, 461 void *engine, Efl_VG *root, int w, int h, void *buffer,
462 Eina_Bool do_async) 462 Eina_Bool do_async, Eina_Bool cacheable)
463{ 463{
464 Ector_Surface *ector; 464 Ector_Surface *ector;
465 RGBA_Draw_Context *context; 465 RGBA_Draw_Context *context;
@@ -502,10 +502,11 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd
502 ENFN->ector_end(engine, buffer, context, ector, do_async); 502 ENFN->ector_end(engine, buffer, context, ector, do_async);
503 evas_common_draw_context_free(context); 503 evas_common_draw_context_free(context);
504 504
505 if (buffer_created) 505 if (buffer_created && cacheable)
506 { 506 {
507 //Use root as a cache key. 507 //Use root as a cache key.
508 ENFN->ector_surface_cache_set(engine, root, buffer); 508 ENFN->ector_surface_cache_set(engine, root, buffer);
509 pd->cached_frame_idx = pd->frame_idx;
509 } 510 }
510 511
511 return buffer; 512 return buffer;
@@ -516,7 +517,7 @@ _render_buffer_to_screen(Evas_Object_Protected_Data *obj,
516 void *engine, void *output, void *context, void *surface, 517 void *engine, void *output, void *context, void *surface,
517 void *buffer, 518 void *buffer,
518 int x, int y, int w, int h, 519 int x, int y, int w, int h,
519 Eina_Bool do_async) 520 Eina_Bool do_async, Eina_Bool cacheable)
520{ 521{
521 Eina_Bool async_unref; 522 Eina_Bool async_unref;
522 523
@@ -532,49 +533,107 @@ _render_buffer_to_screen(Evas_Object_Protected_Data *obj,
532 evas_cache_image_ref((Image_Entry *)buffer); 533 evas_cache_image_ref((Image_Entry *)buffer);
533 evas_unref_queue_image_put(obj->layer->evas, buffer); 534 evas_unref_queue_image_put(obj->layer->evas, buffer);
534 } 535 }
536
537 //TODO: Reuse buffer if size is same?
538 if (!cacheable) ENFN->ector_surface_destroy(engine, buffer);
535} 539}
536 540
537static void 541static void
538_cache_vg_entry_render(Evas_Object_Protected_Data *obj, 542_cache_vg_entry_render(Evas_Object_Protected_Data *obj,
539 Efl_Canvas_Vg_Object_Data *pd, 543 Efl_Canvas_Vg_Object_Data *pd,
540 void *engine, void *output, void *context, void *surface, 544 void *engine, void *output, void *context, void *surface,
541 int x, int y, int w, int h, Eina_Bool do_async) 545 int x, int y, int w, int h, Eina_Bool do_async,
546 Eina_Bool cacheable)
542{ 547{
543 Vg_Cache_Entry *vg_entry = pd->vg_entry; 548 Vg_Cache_Entry *vg_entry = pd->vg_entry;
544 Efl_VG *root; 549 Efl_VG *root;
550 Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio.
551 Eina_Bool drop_cache = EINA_FALSE;
552 void *buffer = NULL;
545 553
546 // if the size changed in between path set and the draw call; 554 // if the size changed in between path set and the draw call;
547
548 if ((vg_entry->w != w) || 555 if ((vg_entry->w != w) ||
549 (vg_entry->h != h)) 556 (vg_entry->h != h))
550 { 557 {
551 vg_entry = evas_cache_vg_entry_resize(vg_entry, w, h); 558 Eina_Size2D size = evas_cache_vg_entry_default_size_get(pd->vg_entry);
552 evas_cache_vg_entry_del(pd->vg_entry); 559
553 pd->vg_entry = vg_entry; 560 //adjust size for aspect ratio.
561 if (size.w > 0 && size.h > 0)
562 {
563 float rw = (float) w / (float) size.w;
564 float rh = (float) h / (float) size.h;
565
566 if (rw < rh)
567 {
568 size.w = w;
569 size.h = (int) ((float) size.h * rw);
570 }
571 else
572 {
573 size.w = (int) ((float) size.w * rh);
574 size.h = h;
575 }
576 }
577 else
578 {
579 size.w = w;
580 size.h = h;
581 }
582
583 //Size is changed, cached data is invalid.
584 if ((size.w != vg_entry->w) || (size.h != vg_entry->h))
585 {
586 drop_cache = EINA_TRUE;
587 vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
588 evas_cache_vg_entry_del(pd->vg_entry);
589 pd->vg_entry = vg_entry;
590 }
591
592 //update for adjusted pos and size.
593 offset.x = w - size.w;
594 if (offset.x > 0) offset.x /= 2;
595 offset.y = h - size.h;
596 if (offset.y > 0) offset.y /= 2;
597 w = size.w;
598 h = size.h;
599
554 } 600 }
555 root = evas_cache_vg_tree_get(vg_entry); 601 root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx);
556 if (!root) return; 602 if (!root) return;
557 603
558 void *buffer = ENFN->ector_surface_cache_get(engine, root); 604 if (cacheable)
605 {
606 //if the size doesn't match, drop previous cache surface.
607 if (drop_cache)
608 ENFN->ector_surface_cache_drop(engine, (void *) root);
609 //Cache Hit!
610 else if (pd->frame_idx == pd->cached_frame_idx)
611 buffer = ENFN->ector_surface_cache_get(engine, (void *) root);
612 //Drop invalid one.
613 else
614 ENFN->ector_surface_cache_drop(engine, (void *) root);
615 }
559 616
560 if (!buffer) 617 if (!buffer)
561 buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL, do_async); 618 buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL,
619 do_async, cacheable);
562 else 620 else
563 //cache reference was increased when we get the cache. 621 //cache reference was increased when we get the cache.
564 ENFN->ector_surface_cache_drop(engine, root); 622 ENFN->ector_surface_cache_drop(engine, (void *) root);
565 623
566 _render_buffer_to_screen(obj, 624 _render_buffer_to_screen(obj,
567 engine, output, context, surface, 625 engine, output, context, surface,
568 buffer, 626 buffer,
569 x, y, w, h, 627 x + offset.x, y + offset.y, w, h,
570 do_async); 628 do_async, cacheable);
571} 629}
572 630
573static void 631static void
574_user_vg_entry_render(Evas_Object_Protected_Data *obj, 632_user_vg_entry_render(Evas_Object_Protected_Data *obj,
575 Efl_Canvas_Vg_Object_Data *pd, 633 Efl_Canvas_Vg_Object_Data *pd,
576 void *engine, void *output, void *context, void *surface, 634 void *engine, void *output, void *context, void *surface,
577 int x, int y, int w, int h, Eina_Bool do_async) 635 int x, int y, int w, int h, Eina_Bool do_async,
636 Eina_Bool cacheable)
578{ 637{
579 Vg_User_Entry *user_entry = pd->user_entry; 638 Vg_User_Entry *user_entry = pd->user_entry;
580 639
@@ -588,13 +647,16 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
588 } 647 }
589 648
590 //if the buffer is not created yet 649 //if the buffer is not created yet
591 void *buffer = ENFN->ector_surface_cache_get(engine, user_entry->root); 650 void *buffer = NULL;
651
652 if (cacheable)
653 buffer = ENFN->ector_surface_cache_get(engine, user_entry->root);
592 654
593 if (!buffer) 655 if (!buffer)
594 { 656 {
595 // render to the buffer 657 // render to the buffer
596 buffer = _render_to_buffer(obj, pd, engine, user_entry->root, 658 buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
597 w, h, buffer, do_async); 659 w, h, buffer, do_async, cacheable);
598 } 660 }
599 else 661 else
600 { 662 {
@@ -602,9 +664,8 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
602 if (pd->changed) 664 if (pd->changed)
603 buffer = _render_to_buffer(obj, pd, engine, 665 buffer = _render_to_buffer(obj, pd, engine,
604 user_entry->root, 666 user_entry->root,
605 w, h, 667 w, h, buffer,
606 buffer, 668 do_async, EINA_FALSE);
607 do_async);
608 //cache reference was increased when we get the cache. 669 //cache reference was increased when we get the cache.
609 ENFN->ector_surface_cache_drop(engine, user_entry->root); 670 ENFN->ector_surface_cache_drop(engine, user_entry->root);
610 } 671 }
@@ -613,7 +674,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
613 engine, output, context, surface, 674 engine, output, context, surface,
614 buffer, 675 buffer,
615 x, y, w, h, 676 x, y, w, h,
616 do_async); 677 do_async, cacheable);
617} 678}
618 679
619static void 680static void
@@ -635,19 +696,30 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
635 ENFN->context_anti_alias_set(engine, context, obj->cur->anti_alias); 696 ENFN->context_anti_alias_set(engine, context, obj->cur->anti_alias);
636 ENFN->context_render_op_set(engine, context, obj->cur->render_op); 697 ENFN->context_render_op_set(engine, context, obj->cur->render_op);
637 698
699 //Cache surface?
700 Eina_Bool cacheable = EINA_FALSE;
701
702 /* Try caching buffer only for first and last frames
703 because it's an overhead task if it caches all frame images.
704 We assume the first and last frame images are the most resusable
705 in generic scenarios. */
706 if (pd->frame_idx == 0 ||
707 (pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)))
708 cacheable = EINA_TRUE;
709
638 if (pd->vg_entry) 710 if (pd->vg_entry)
639 { 711 {
640 _cache_vg_entry_render(obj, pd, 712 _cache_vg_entry_render(obj, pd,
641 engine, output, context, surface, 713 engine, output, context, surface,
642 obj->cur->geometry.x + x, obj->cur->geometry.y + y, 714 obj->cur->geometry.x + x, obj->cur->geometry.y + y,
643 obj->cur->geometry.w, obj->cur->geometry.h, do_async); 715 obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
644 } 716 }
645 if (pd->user_entry) 717 if (pd->user_entry)
646 { 718 {
647 _user_vg_entry_render(obj, pd, 719 _user_vg_entry_render(obj, pd,
648 engine, output, context, surface, 720 engine, output, context, surface,
649 obj->cur->geometry.x + x, obj->cur->geometry.y + y, 721 obj->cur->geometry.x + x, obj->cur->geometry.y + y,
650 obj->cur->geometry.w, obj->cur->geometry.h, do_async); 722 obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
651 } 723 }
652 pd->changed = EINA_FALSE; 724 pd->changed = EINA_FALSE;
653} 725}
@@ -804,6 +876,79 @@ _efl_canvas_vg_object_was_opaque(Evas_Object *eo_obj EINA_UNUSED,
804 return 0; 876 return 0;
805} 877}
806 878
879/* animated feature */
880EOLIAN static Eina_Bool
881_efl_canvas_vg_object_efl_gfx_frame_controller_animated_get(const Eo *eo_obj EINA_UNUSED,
882 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED EINA_UNUSED)
883{
884 //TODO:
885 return EINA_TRUE;
886}
887
888EOLIAN static int
889_efl_canvas_vg_object_efl_gfx_frame_controller_frame_count_get(const Eo *eo_obj EINA_UNUSED,
890 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
891{
892 if (!pd->vg_entry) return 0;
893 return evas_cache_vg_anim_frame_count_get(pd->vg_entry);
894}
895
896EOLIAN static Efl_Gfx_Frame_Controller_Loop_Hint
897_efl_canvas_vg_object_efl_gfx_frame_controller_loop_type_get(const Eo *eo_obj EINA_UNUSED,
898 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
899{
900 //TODO:
901 return EFL_GFX_FRAME_CONTROLLER_LOOP_HINT_NONE;
902}
903
904EOLIAN static int
905_efl_canvas_vg_object_efl_gfx_frame_controller_loop_count_get(const Eo *eo_obj EINA_UNUSED,
906 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
907{
908 //TODO:
909 return 0;
910}
911
912EOLIAN static double
913_efl_canvas_vg_object_efl_gfx_frame_controller_frame_duration_get(const Eo *eo_obj EINA_UNUSED,
914 Efl_Canvas_Vg_Object_Data *pd,
915 int start_frame EINA_UNUSED,
916 int frame_num EINA_UNUSED)
917{
918 if (!pd->vg_entry) return 0;
919 return evas_cache_vg_anim_duration_get(pd->vg_entry);
920}
921
922EOLIAN static Eina_Bool
923_efl_canvas_vg_object_efl_gfx_frame_controller_frame_set(Eo *eo_obj,
924 Efl_Canvas_Vg_Object_Data *pd,
925 int frame_index)
926{
927 //TODO: Validate frame_index range
928 if (pd->frame_idx == frame_index) return EINA_TRUE;
929
930 //Image is changed, drop previous cached image.
931 pd->frame_idx = frame_index;
932 pd->changed = EINA_TRUE;
933 evas_object_change(eo_obj, efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS));
934
935 return EINA_TRUE;
936}
937
938EOLIAN static int
939_efl_canvas_vg_object_efl_gfx_frame_controller_frame_get(const Eo *eo_obj EINA_UNUSED,
940 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
941{
942 return pd->frame_idx;
943}
944
945EOLIAN static Eina_Size2D
946_efl_canvas_vg_object_default_size_get(const Eo *eo_obj EINA_UNUSED,
947 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
948{
949 return evas_cache_vg_entry_default_size_get(pd->vg_entry);
950}
951
807/* the actual api call to add a vector graphic object */ 952/* the actual api call to add a vector graphic object */
808EAPI Evas_Object * 953EAPI Evas_Object *
809evas_object_vg_add(Evas *e) 954evas_object_vg_add(Evas *e)
@@ -814,5 +959,35 @@ evas_object_vg_add(Evas *e)
814 return efl_add(MY_CLASS, e, efl_canvas_object_legacy_ctor(efl_added)); 959 return efl_add(MY_CLASS, e, efl_canvas_object_legacy_ctor(efl_added));
815} 960}
816 961
962EAPI int
963evas_object_vg_animated_frame_get(const Evas_Object *obj)
964{
965 return efl_gfx_frame_controller_frame_get(obj);
966}
967
968EAPI double
969evas_object_vg_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num)
970{
971 return efl_gfx_frame_controller_frame_duration_get(obj, start_frame, frame_num);
972}
973
974EAPI int
975evas_object_vg_animated_frame_count_get(const Evas_Object *obj)
976{
977 return efl_gfx_frame_controller_frame_count_get(obj);
978}
979
980EAPI Eina_Bool
981evas_object_vg_animated_frame_set(Evas_Object *obj, int frame_index)
982{
983 return efl_gfx_frame_controller_frame_set(obj, frame_index);
984}
985
986EAPI Eina_Bool
987evas_object_vg_file_set(Evas_Object *obj, const char *file, const char *key)
988{
989 return efl_file_simple_load(obj, file, key);
990}
991
817#include "efl_canvas_vg_object.eo.c" 992#include "efl_canvas_vg_object.eo.c"
818#include "efl_canvas_vg_object_eo.legacy.c" 993#include "efl_canvas_vg_object_eo.legacy.c"
diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.eo b/src/lib/evas/canvas/efl_canvas_vg_object.eo
index 53bc6de0ea..12411eab37 100644
--- a/src/lib/evas/canvas/efl_canvas_vg_object.eo
+++ b/src/lib/evas/canvas/efl_canvas_vg_object.eo
@@ -21,7 +21,8 @@ enum @beta Efl.Canvas.Vg.Fill_Mode
21 dimension of the viewport.]] 21 dimension of the viewport.]]
22} 22}
23 23
24class @beta Efl.Canvas.Vg.Object extends Efl.Canvas.Object implements Efl.File, Efl.File_Save 24class @beta Efl.Canvas.Vg.Object extends Efl.Canvas.Object implements Efl.File, Efl.File_Save,
25 Efl.Gfx.Frame_Controller
25{ 26{
26 [[Efl vector graphics class]] 27 [[Efl vector graphics class]]
27 methods { 28 methods {
@@ -67,6 +68,15 @@ class @beta Efl.Canvas.Vg.Object extends Efl.Canvas.Object implements Efl.File,
67 root: Efl.Canvas.Vg.Node; [[Root node of the VG canvas.]] 68 root: Efl.Canvas.Vg.Node; [[Root node of the VG canvas.]]
68 } 69 }
69 } 70 }
71 @property default_size {
72 get {
73 [[Get the default vector size that specified from vector resource.
74 @since 1.22]]
75 }
76 values {
77 size: Eina.Size2D;
78 }
79 }
70 } 80 }
71 implements { 81 implements {
72 Efl.Object.constructor; 82 Efl.Object.constructor;
@@ -76,5 +86,11 @@ class @beta Efl.Canvas.Vg.Object extends Efl.Canvas.Object implements Efl.File,
76 Efl.File.unload; 86 Efl.File.unload;
77 Efl.File.file { set; } 87 Efl.File.file { set; }
78 Efl.File_Save.save; 88 Efl.File_Save.save;
89 Efl.Gfx.Frame_Controller.animated { get; }
90 Efl.Gfx.Frame_Controller.frame { get; set; }
91 Efl.Gfx.Frame_Controller.frame_count { get; }
92 Efl.Gfx.Frame_Controller.loop_type { get; }
93 Efl.Gfx.Frame_Controller.loop_count { get; }
94 Efl.Gfx.Frame_Controller.frame_duration { get; }
79 } 95 }
80} 96}
diff --git a/src/lib/evas/canvas/evas_vg_private.h b/src/lib/evas/canvas/evas_vg_private.h
index 73ff63e7d8..0fad40d15c 100644
--- a/src/lib/evas/canvas/evas_vg_private.h
+++ b/src/lib/evas/canvas/evas_vg_private.h
@@ -23,7 +23,7 @@ typedef struct _Vg_Cache_Entry
23 Eina_Stringshare *key; 23 Eina_Stringshare *key;
24 int w; 24 int w;
25 int h; 25 int h;
26 Efl_VG *root; 26 Efl_VG *root[3]; //0: default, 1: start frame, 2: end frame
27 int ref; 27 int ref;
28 Vg_File_Data *vfd; 28 Vg_File_Data *vfd;
29} Vg_Cache_Entry; 29} Vg_Cache_Entry;
@@ -48,6 +48,8 @@ struct _Efl_Canvas_Vg_Object_Data
48 Eina_Array cleanup; 48 Eina_Array cleanup;
49 double align_x, align_y; 49 double align_x, align_y;
50 Efl_Canvas_Vg_Fill_Mode fill_mode; 50 Efl_Canvas_Vg_Fill_Mode fill_mode;
51 int frame_idx;
52 int cached_frame_idx;
51 53
52 Eina_Bool changed : 1; 54 Eina_Bool changed : 1;
53}; 55};
@@ -123,11 +125,14 @@ void evas_cache_vg_init(void);
123void evas_cache_vg_shutdown(void); 125void evas_cache_vg_shutdown(void);
124Vg_Cache_Entry* evas_cache_vg_entry_resize(Vg_Cache_Entry *entry, int w, int h); 126Vg_Cache_Entry* evas_cache_vg_entry_resize(Vg_Cache_Entry *entry, int w, int h);
125Vg_Cache_Entry* evas_cache_vg_entry_create(const Eina_File *file, const char *key, int w, int h); 127Vg_Cache_Entry* evas_cache_vg_entry_create(const Eina_File *file, const char *key, int w, int h);
126Efl_VG* evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry); 128Efl_VG* evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num);
127void evas_cache_vg_entry_del(Vg_Cache_Entry *vg_entry); 129void evas_cache_vg_entry_del(Vg_Cache_Entry *vg_entry);
128Vg_File_Data * evas_cache_vg_file_open(const Eina_File *file, const char *key); 130Vg_File_Data * evas_cache_vg_file_open(const Eina_File *file, const char *key);
129Eina_Bool evas_cache_vg_file_save(Efl_VG *root, int w, int h, const char *file, const char *key, const Efl_File_Save_Info *info); 131Eina_Bool evas_cache_vg_file_save(Efl_VG *root, int w, int h, const char *file, const char *key, const Efl_File_Save_Info *info);
130Eina_Bool evas_cache_vg_entry_file_save(Vg_Cache_Entry *vg_entry, const char *file, const char *key, const Efl_File_Save_Info *info); 132Eina_Bool evas_cache_vg_entry_file_save(Vg_Cache_Entry *vg_entry, const char *file, const char *key, const Efl_File_Save_Info *info);
133double evas_cache_vg_anim_duration_get(const Vg_Cache_Entry *vg_entry);
134unsigned int evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry *vg_entry);
135Eina_Size2D evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry);
131void efl_canvas_vg_node_vg_obj_set(Efl_VG *node, Efl_VG *vg_obj, Efl_Canvas_Vg_Object_Data *vd); 136void efl_canvas_vg_node_vg_obj_set(Efl_VG *node, Efl_VG *vg_obj, Efl_Canvas_Vg_Object_Data *vd);
132void efl_canvas_vg_node_change(Efl_VG *node); 137void efl_canvas_vg_node_change(Efl_VG *node);
133void efl_canvas_vg_container_vg_obj_update(Efl_VG *obj, Efl_Canvas_Vg_Node_Data *nd); 138void efl_canvas_vg_container_vg_obj_update(Efl_VG *obj, Efl_Canvas_Vg_Node_Data *nd);
diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h
index 7d6d1c452f..d6b53bc210 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -139,6 +139,7 @@ typedef struct _Evas_Canvas3D_Header_Eet Evas_Canvas3D_Header_Eet;
139typedef struct _Evas_Canvas3D_File_Eet Evas_Canvas3D_File_Eet; 139typedef struct _Evas_Canvas3D_File_Eet Evas_Canvas3D_File_Eet;
140 140
141typedef struct _Vg_File_Data Vg_File_Data; 141typedef struct _Vg_File_Data Vg_File_Data;
142typedef struct _Vg_File_Anim_Data Vg_File_Anim_Data;
142 143
143struct _Evas_Canvas3D_Vec2_Eet 144struct _Evas_Canvas3D_Vec2_Eet
144{ 145{
@@ -1510,13 +1511,25 @@ struct _Evas_Image_Save_Func
1510 int (*image_save) (RGBA_Image *im, const char *file, const char *key, int quality, int compress, const char *encoding); 1511 int (*image_save) (RGBA_Image *im, const char *file, const char *key, int quality, int compress, const char *encoding);
1511}; 1512};
1512 1513
1514struct _Vg_File_Anim_Data
1515{
1516 unsigned int frame_num; //current frame number
1517 unsigned int frame_cnt; //total frame count
1518 float duration; //animation duration
1519};
1520
1513struct _Vg_File_Data 1521struct _Vg_File_Data
1514{ 1522{
1515 Efl_VG *root; 1523 Efl_VG *root;
1516 Evas_Vg_Load_Func *loader; 1524 Evas_Vg_Load_Func *loader;
1517 Eina_Rectangle view_box; 1525 Eina_Rectangle view_box;
1526 Vg_File_Anim_Data *anim_data; //only when animation supported.
1518 int ref; 1527 int ref;
1528 int w, h; //default size
1529
1530 void *loader_data; //loader specific local data
1519 1531
1532 Eina_Bool no_share : 1; //Shareable VFD through multiple file open requests.
1520 Eina_Bool static_viewbox: 1; 1533 Eina_Bool static_viewbox: 1;
1521 Eina_Bool preserve_aspect : 1; //Used in SVG 1534 Eina_Bool preserve_aspect : 1; //Used in SVG
1522}; 1535};
diff --git a/src/lib/evas/vg/evas_vg_cache.c b/src/lib/evas/vg/evas_vg_cache.c
index 534dca2748..dd85349ee9 100644
--- a/src/lib/evas/vg/evas_vg_cache.c
+++ b/src/lib/evas/vg/evas_vg_cache.c
@@ -35,7 +35,7 @@ static const struct ext_loader_s loaders[] =
35 35
36static const char *loaders_name[] = 36static const char *loaders_name[] =
37{ /* in order of most likely needed */ 37{ /* in order of most likely needed */
38 "eet", "svg" 38 "eet", "json", "svg"
39}; 39};
40 40
41static const struct ext_saver_s savers[] = 41static const struct ext_saver_s savers[] =
@@ -153,19 +153,26 @@ _evas_cache_vg_entry_free_cb(void *data)
153 153
154 if (vg_entry->vfd->ref <= 0) 154 if (vg_entry->vfd->ref <= 0)
155 { 155 {
156 Eina_Strbuf *hash_key = eina_strbuf_new(); 156 if (vg_entry->vfd->no_share)
157 eina_strbuf_append_printf(hash_key, "%s/%s", 157 vg_entry->vfd->loader->file_close(vg_entry->vfd);
158 eina_file_filename_get(vg_entry->file), 158 else
159 vg_entry->key); 159 {
160 if (!eina_hash_del(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key), vg_entry->vfd)) 160 Eina_Strbuf *hash_key = eina_strbuf_new();
161 ERR("Failed to delete vfd = (%p) from hash", vg_entry->vfd); 161 eina_strbuf_append_printf(hash_key, "%s/%s",
162 eina_strbuf_free(hash_key); 162 eina_file_filename_get(vg_entry->file),
163 vg_entry->key);
164 if (!eina_hash_del(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key), vg_entry->vfd))
165 ERR("Failed to delete vfd = (%p) from hash", vg_entry->vfd);
166 eina_strbuf_free(hash_key);
167 }
163 } 168 }
164 } 169 }
165 170
166 eina_stringshare_del(vg_entry->key); 171 eina_stringshare_del(vg_entry->key);
167 free(vg_entry->hash_key); 172 free(vg_entry->hash_key);
168 efl_unref(vg_entry->root); 173 efl_unref(vg_entry->root[0]);
174 efl_unref(vg_entry->root[1]);
175 efl_unref(vg_entry->root[2]);
169 free(vg_entry); 176 free(vg_entry);
170} 177}
171 178
@@ -195,9 +202,37 @@ _vg_file_save(Vg_File_Data *vfd, const char *file, const char *key, const Efl_Fi
195} 202}
196 203
197static Efl_VG* 204static Efl_VG*
198_cached_root_get(Vg_Cache_Entry *vg_entry) 205_cached_root_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num)
199{ 206{
200 return vg_entry->root; 207 Vg_File_Data *vfd = vg_entry->vfd;
208
209 //Case 1: Animatable
210 if (vfd->anim_data)
211 {
212 //Start frame
213 if (vg_entry->root[1] && frame_num == 0)
214 {
215 return vg_entry->root[1];
216 }
217 //End frame
218 else if (vg_entry->root[2] && (frame_num == (vfd->anim_data->frame_cnt - 1)))
219 {
220 return vg_entry->root[2];
221 }
222 //Current frame
223 else if (vg_entry->root[0] && (frame_num == (vfd->anim_data->frame_num)))
224 {
225 return vg_entry->root[0];
226 }
227 }
228 //Case 2: Static
229 else
230 {
231 if (vg_entry->root[0])
232 return vg_entry->root[0];
233 }
234
235 return NULL;
201} 236}
202 237
203static void 238static void
@@ -214,12 +249,34 @@ _caching_root_update(Vg_Cache_Entry *vg_entry)
214 /* TODO: Yet trivial but still we may have a better solution to 249 /* TODO: Yet trivial but still we may have a better solution to
215 avoid this unnecessary copy. If the ector surface key is not 250 avoid this unnecessary copy. If the ector surface key is not
216 to this root pointer. */ 251 to this root pointer. */
217 vg_entry->root = efl_duplicate(vfd->root); 252 vg_entry->root[0] = efl_duplicate(vfd->root);
218 } 253 }
219 else if (vg_entry->root != vfd->root) 254 else if (vg_entry->root[0] != vfd->root)
220 { 255 {
221 if (vg_entry->root) efl_unref(vg_entry->root); 256 if (vg_entry->root[0]) efl_unref(vg_entry->root[0]);
222 vg_entry->root = efl_ref(vfd->root); 257 vg_entry->root[0] = efl_ref(vfd->root);
258 }
259
260 //Animatable?
261 if (!vfd->anim_data) return;
262
263 //Start frame
264 if (vfd->anim_data->frame_num == 0)
265 {
266 if (vg_entry->root[1] != vfd->root)
267 {
268 if (vg_entry->root[1]) efl_unref(vg_entry->root[1]);
269 vg_entry->root[1] = efl_ref(vfd->root);
270 }
271 }
272 //End frame
273 else if (vfd->anim_data->frame_num == (vfd->anim_data->frame_cnt - 1))
274 {
275 if (vg_entry->root[2] != vfd->root)
276 {
277 if (vg_entry->root[2]) efl_unref(vg_entry->root[2]);
278 vg_entry->root[2] = efl_ref(vfd->root);
279 }
223 } 280 }
224} 281}
225 282
@@ -294,11 +351,12 @@ evas_cache_vg_file_open(const Eina_File *file, const char *key)
294 hash_key = eina_strbuf_new(); 351 hash_key = eina_strbuf_new();
295 eina_strbuf_append_printf(hash_key, "%s/%s", eina_file_filename_get(file), key); 352 eina_strbuf_append_printf(hash_key, "%s/%s", eina_file_filename_get(file), key);
296 vfd = eina_hash_find(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key)); 353 vfd = eina_hash_find(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key));
297 if (!vfd) 354 if (!vfd || vfd->no_share)
298 { 355 {
299 vfd = _vg_load_from_file(file, key); 356 vfd = _vg_load_from_file(file, key);
300 //File exists. 357 //File exists.
301 if (vfd) eina_hash_add(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key), vfd); 358 if (vfd && !vfd->no_share)
359 eina_hash_add(vg_cache->vfd_hash, eina_strbuf_string_get(hash_key), vfd);
302 } 360 }
303 eina_strbuf_free(hash_key); 361 eina_strbuf_free(hash_key);
304 return vfd; 362 return vfd;
@@ -356,8 +414,24 @@ evas_cache_vg_entry_create(const Eina_File *file,
356 return vg_entry; 414 return vg_entry;
357} 415}
358 416
417double
418evas_cache_vg_anim_duration_get(const Vg_Cache_Entry* vg_entry)
419{
420 if (!vg_entry->vfd->anim_data) return 0;
421 return vg_entry->vfd->anim_data->duration;
422}
423
424unsigned int
425evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry* vg_entry)
426{
427 if (!vg_entry) return 0;
428 Vg_File_Data *vfd = vg_entry->vfd;
429 if (!vfd || !vfd->anim_data) return 0;
430 return vfd->anim_data->frame_cnt;
431}
432
359Efl_VG* 433Efl_VG*
360evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry) 434evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num)
361{ 435{
362 if (!vg_entry) return NULL; 436 if (!vg_entry) return NULL;
363 if ((vg_entry->w < 1) || (vg_entry->h < 1)) return NULL; 437 if ((vg_entry->w < 1) || (vg_entry->h < 1)) return NULL;
@@ -365,7 +439,7 @@ evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry)
365 Vg_File_Data *vfd = vg_entry->vfd; 439 Vg_File_Data *vfd = vg_entry->vfd;
366 if (!vfd) return NULL; 440 if (!vfd) return NULL;
367 441
368 Efl_VG *root = _cached_root_get(vg_entry); 442 Efl_VG *root = _cached_root_get(vg_entry, frame_num);
369 if (root) return root; 443 if (root) return root;
370 444
371 if (!vfd->static_viewbox) 445 if (!vfd->static_viewbox)
@@ -374,13 +448,15 @@ evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry)
374 vfd->view_box.h = vg_entry->h; 448 vfd->view_box.h = vg_entry->h;
375 } 449 }
376 450
451 if (vfd->anim_data) vfd->anim_data->frame_num = frame_num;
452
377 if (!vfd->loader->file_data(vfd)) return NULL; 453 if (!vfd->loader->file_data(vfd)) return NULL;
378 454
379 _caching_root_update(vg_entry); 455 _caching_root_update(vg_entry);
380 456
381 _local_transform(vg_entry->root, vg_entry->w, vg_entry->h, vfd); 457 _local_transform(vg_entry->root[0], vg_entry->w, vg_entry->h, vfd);
382 458
383 return vg_entry->root; 459 return vg_entry->root[0];
384} 460}
385 461
386void 462void
@@ -393,6 +469,13 @@ evas_cache_vg_entry_del(Vg_Cache_Entry *vg_entry)
393 ERR("Failed to delete vg_entry = (%p) from hash", vg_entry); 469 ERR("Failed to delete vg_entry = (%p) from hash", vg_entry);
394} 470}
395 471
472Eina_Size2D
473evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry)
474{
475 if (!vg_entry) return EINA_SIZE2D(0, 0);
476 return EINA_SIZE2D(vg_entry->vfd->w, vg_entry->vfd->h);
477}
478
396Eina_Bool 479Eina_Bool
397evas_cache_vg_entry_file_save(Vg_Cache_Entry *vg_entry, const char *file, const char *key, const Efl_File_Save_Info *info) 480evas_cache_vg_entry_file_save(Vg_Cache_Entry *vg_entry, const char *file, const char *key, const Efl_File_Save_Info *info)
398{ 481{