1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 
4 #include "evas_vg_private.h"
5 
6 #define MY_CLASS EFL_CANVAS_VG_OBJECT_CLASS
7 
8 /* private magic number for vector objects */
9 static const char o_type[] = "vectors";
10 
11 const char *o_vg_type = o_type;
12 
13 
14 static void _efl_canvas_vg_object_render(Evas_Object *eo_obj,
15                                          Evas_Object_Protected_Data *obj,
16                                          void *type_private_data,
17                                          void *engine, void *output, void *context, void *surface,
18                                          int x, int y, Eina_Bool do_async);
19 static void _efl_canvas_vg_object_render_pre(Evas_Object *eo_obj,
20                                              Evas_Object_Protected_Data *obj,
21                                              void *type_private_data);
22 static void _efl_canvas_vg_object_render_post(Evas_Object *eo_obj,
23                                               Evas_Object_Protected_Data *obj,
24                                               void *type_private_data);
25 static int _efl_canvas_vg_object_is_opaque(Evas_Object *eo_obj,
26                                            Evas_Object_Protected_Data *obj,
27                                            void *type_private_data);
28 static int _efl_canvas_vg_object_was_opaque(Evas_Object *eo_obj,
29                                             Evas_Object_Protected_Data *obj,
30                                             void *type_private_data);
31 
32 static const Evas_Object_Func object_func =
33 {
34    /* methods (compulsory) */
35    NULL,
36    _efl_canvas_vg_object_render,
37    _efl_canvas_vg_object_render_pre,
38    _efl_canvas_vg_object_render_post,
39    NULL,
40    /* these are optional. NULL = nothing */
41    NULL,
42    NULL,
43    _efl_canvas_vg_object_is_opaque,
44    _efl_canvas_vg_object_was_opaque,
45    NULL,
46    NULL,
47    NULL,
48    NULL,
49    NULL,
50    NULL,
51    NULL // render_prepare
52 };
53 
54 static void
_update_vgtree_viewport(Eo * obj,Efl_Canvas_Vg_Object_Data * pd)55 _update_vgtree_viewport(Eo *obj, Efl_Canvas_Vg_Object_Data *pd)
56 {
57    double vb_w, vb_h, vp_w, vp_h, scale_w, scale_h, scale;
58    Eina_Size2D sz = efl_gfx_entity_size_get(obj);
59    Eina_Matrix3 m;
60 
61    eina_matrix3_identity(&m);
62 
63    vb_w = pd->viewbox.w;
64    vb_h = pd->viewbox.h;
65    vp_w = sz.w;
66    vp_h = sz.h;
67 
68    scale_w = vp_w / vb_w;
69    scale_h = vp_h / vb_h;
70 
71    if (pd->fill_mode == EFL_CANVAS_VG_FILL_MODE_STRETCH)
72      { // Fill the viewport and ignore the aspect ratio
73         eina_matrix3_scale(&m, scale_w, scale_h);
74         eina_matrix3_translate(&m, -pd->viewbox.x, -pd->viewbox.y);
75      }
76    else
77      {
78         if (pd->fill_mode == EFL_CANVAS_VG_FILL_MODE_MEET)
79           scale = scale_w < scale_h ? scale_w : scale_h;
80         else // slice
81           scale = scale_w > scale_h ? scale_w : scale_h;
82         eina_matrix3_translate(&m, (vp_w - vb_w * scale) * pd->align_x, (vp_h - vb_h * scale) * pd->align_y);
83         eina_matrix3_scale(&m, scale, scale);
84         eina_matrix3_translate(&m, -pd->viewbox.x, -pd->viewbox.y);
85      }
86 
87    efl_canvas_vg_node_transformation_set(pd->root, &m);
88 
89    pd->changed = EINA_TRUE;
90    evas_object_change(obj, efl_data_scope_get(obj, EFL_CANVAS_OBJECT_CLASS));
91 }
92 
93 static void
_evas_vg_resize(void * data,const Efl_Event * ev)94 _evas_vg_resize(void *data, const Efl_Event *ev)
95 {
96    Efl_Canvas_Vg_Object_Data *pd = data;
97 
98    if (eina_rectangle_is_empty(&pd->viewbox.rect))
99      return;
100    _update_vgtree_viewport(ev->object, pd);
101 }
102 
103 EOLIAN static Efl_VG *
_efl_canvas_vg_object_root_node_get(const Eo * obj,Efl_Canvas_Vg_Object_Data * pd)104 _efl_canvas_vg_object_root_node_get(const Eo *obj, Efl_Canvas_Vg_Object_Data *pd)
105 {
106    Efl_VG *root;
107 
108    if (pd->vg_entry)
109      {
110         Evas_Coord w, h;
111         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
112 
113         //Update vg data with current size.
114         if ((pd->vg_entry->w != w) || (pd->vg_entry->h != h))
115           {
116              Vg_Cache_Entry *vg_entry = evas_cache_vg_entry_resize(pd->vg_entry, w, h);
117              evas_cache_vg_entry_del(pd->vg_entry);
118              pd->vg_entry = vg_entry;
119           }
120         root = evas_cache_vg_tree_get(pd->vg_entry, pd->frame_idx);
121      }
122    else if (pd->user_entry) root = pd->user_entry->root;
123    else root = pd->root;
124 
125    return root;
126 }
127 
128 EOLIAN static void
_efl_canvas_vg_object_root_node_set(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd,Efl_VG * root_node)129 _efl_canvas_vg_object_root_node_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, Efl_VG *root_node)
130 {
131    // if the same root is already set
132    if (pd->user_entry && pd->user_entry->root == root_node)
133      return;
134 
135    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
136 
137    // check if a file has been already set
138    if (pd->vg_entry)
139      {
140         evas_cache_vg_entry_del(pd->vg_entry);
141         pd->vg_entry = NULL;
142      }
143 
144    // detach/free the old root_node
145    if (pd->user_entry && pd->user_entry->root)
146      {
147         // drop any surface cache attached to it.
148         ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root);
149         efl_canvas_vg_node_vg_obj_set(pd->user_entry->root, NULL, NULL);
150         efl_replace(&pd->user_entry->root, NULL);
151      }
152 
153    if (root_node)
154      {
155         if (!pd->user_entry)
156           {
157              pd->user_entry = calloc(1, sizeof(Vg_User_Entry));
158              if (!pd->user_entry)
159                {
160                   ERR("Failed to alloc user entry data while setting root node");
161                   return;
162                }
163           }
164         else pd->user_entry->w = pd->user_entry->h = 0;
165 
166         efl_replace(&pd->user_entry->root, root_node);
167         efl_canvas_vg_node_vg_obj_set(root_node, eo_obj, pd);
168      }
169    else if (pd->user_entry)
170      {
171         free(pd->user_entry);
172         pd->user_entry = NULL;
173      }
174 
175    // force a redraw
176    pd->changed = EINA_TRUE;
177    evas_object_change(eo_obj, obj);
178 }
179 
180 EOLIAN static void
_efl_canvas_vg_object_fill_mode_set(Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd,Efl_Canvas_Vg_Fill_Mode fill_mode)181 _efl_canvas_vg_object_fill_mode_set(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd, Efl_Canvas_Vg_Fill_Mode fill_mode)
182 {
183    pd->fill_mode = fill_mode;
184 }
185 
186 EOLIAN static Efl_Canvas_Vg_Fill_Mode
_efl_canvas_vg_object_fill_mode_get(const Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd)187 _efl_canvas_vg_object_fill_mode_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd)
188 {
189    return pd->fill_mode;
190 }
191 
192 EOLIAN static void
_efl_canvas_vg_object_viewbox_set(Eo * obj,Efl_Canvas_Vg_Object_Data * pd,Eina_Rect viewbox)193 _efl_canvas_vg_object_viewbox_set(Eo *obj, Efl_Canvas_Vg_Object_Data *pd, Eina_Rect viewbox)
194 {
195    // viewbox should be a valid rectangle
196    if (eina_rectangle_is_empty(&viewbox.rect))
197      {
198         // reset the old viewbox if any
199         if (!eina_rectangle_is_empty(&pd->viewbox.rect))
200           {
201              Eina_Matrix3 m;
202 
203              pd->viewbox = EINA_RECT_EMPTY();
204              eina_matrix3_identity(&m);
205              efl_canvas_vg_node_transformation_set(pd->root, &m);
206              // unregister the resize callback
207              efl_event_callback_del(obj, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _evas_vg_resize, pd);
208           }
209         return;
210      }
211    // register for resize callback if not done yet
212    if (eina_rectangle_is_empty(&pd->viewbox.rect))
213      efl_event_callback_add(obj, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _evas_vg_resize, pd);
214 
215    pd->viewbox = viewbox;
216    _update_vgtree_viewport(obj, pd);
217 }
218 
219 EOLIAN static Eina_Rect
_efl_canvas_vg_object_viewbox_get(const Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd)220 _efl_canvas_vg_object_viewbox_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd)
221 {
222    return pd->viewbox;
223 }
224 
225 EOLIAN static void
_efl_canvas_vg_object_viewbox_align_set(Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd,double align_x,double align_y)226 _efl_canvas_vg_object_viewbox_align_set(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd, double align_x, double align_y)
227 {
228    align_x = align_x < 0 ? 0 : align_x;
229    align_x = align_x > 1 ? 1 : align_x;
230 
231    align_y = align_y < 0 ? 0 : align_y;
232    align_y = align_y > 1 ? 1 : align_y;
233 
234    pd->align_x = align_x;
235    pd->align_y = align_y;
236 }
237 
238 EOLIAN static void
_efl_canvas_vg_object_viewbox_align_get(const Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd,double * align_x,double * align_y)239 _efl_canvas_vg_object_viewbox_align_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Object_Data *pd, double *align_x, double *align_y)
240 {
241    if (align_x) *align_x = pd->align_x;
242    if (align_y) *align_y = pd->align_y;
243 }
244 
245 EOLIAN static Eina_Error
_efl_canvas_vg_object_efl_file_file_set(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd EINA_UNUSED,const char * file)246 _efl_canvas_vg_object_efl_file_file_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED, const char *file)
247 {
248    /* Careful: delete previous vg entry.
249       When a new efl file is set, ex-file will be invalid.
250       Since vg cache hashes all file entries,
251       we must remove it from vg cache before we lost file handle. */
252    if (efl_file_loaded_get(eo_obj))
253      {
254         const char *pname = efl_file_get(eo_obj);
255         int pl = pname ? strlen(pname) : 0;
256         int cl = file ? strlen(file) : 0;
257 
258         if ((pl != cl) || (pname && file && strcmp(pname, file)))
259           {
260              Evas_Object_Protected_Data *obj;
261              obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
262              evas_cache_vg_entry_del(pd->vg_entry);
263              evas_object_change(eo_obj, obj);
264              pd->vg_entry = NULL;
265              evas_object_change(eo_obj, obj);
266              pd->changed = EINA_TRUE;
267           }
268      }
269 
270    Eina_Error err;
271    err = efl_file_set(efl_super(eo_obj, MY_CLASS), file);
272 
273    if (err) return err;
274 
275    return 0;
276 }
277 
278 EOLIAN static Eina_Error
_efl_canvas_vg_object_efl_file_load(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd)279 _efl_canvas_vg_object_efl_file_load(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
280 {
281    Eina_Error err;
282    if (efl_file_loaded_get(eo_obj)) return 0;
283 
284    err = efl_file_load(efl_super(eo_obj, MY_CLASS));
285    if (err) return err;
286 
287    const Eina_File *file = efl_file_mmap_get(eo_obj);
288    const char *key = efl_file_key_get(eo_obj);
289    Evas_Object_Protected_Data *obj;
290 
291    obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
292    pd->vg_entry = evas_cache_vg_entry_create(evas_object_evas_get(eo_obj),
293                                              file, key,
294                                              obj->cur->geometry.w,
295                                              obj->cur->geometry.h, NULL);
296 
297    // NOTE: Update object's viewbox. In this case, there is no need to update
298    //       the root of tree. That's why We don't use viewbox_set.
299    if (pd->vg_entry && pd->vg_entry->vfd)
300      pd->viewbox.rect = pd->vg_entry->vfd->view_box;
301 
302    evas_object_change(eo_obj, obj);
303    pd->changed = EINA_TRUE;
304 
305    return 0;
306 }
307 
308 EOLIAN static void
_efl_canvas_vg_object_efl_file_unload(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd)309 _efl_canvas_vg_object_efl_file_unload(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
310 {
311    if (!efl_file_loaded_get(eo_obj)) return;
312 
313    Evas_Object_Protected_Data *obj;
314    obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
315    evas_cache_vg_entry_del(pd->vg_entry);
316    evas_object_change(eo_obj, obj);
317    pd->vg_entry = NULL;
318 }
319 
320 EOLIAN static Eina_Bool
_efl_canvas_vg_object_efl_file_save_save(const Eo * obj,Efl_Canvas_Vg_Object_Data * pd,const char * file,const char * key,const Efl_File_Save_Info * info)321 _efl_canvas_vg_object_efl_file_save_save(const Eo *obj, Efl_Canvas_Vg_Object_Data *pd, const char *file, const char *key, const Efl_File_Save_Info *info)
322 {
323    if (pd->vg_entry)
324      return evas_cache_vg_entry_file_save(pd->vg_entry, file, key, info);
325 
326    Evas_Coord w, h;
327    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
328    return evas_cache_vg_file_save(pd->root, w, h, file, key, info);
329 }
330 
331 static void
_cleanup_reference(void * data,const Efl_Event * event EINA_UNUSED)332 _cleanup_reference(void *data, const Efl_Event *event EINA_UNUSED)
333 {
334    Efl_Canvas_Vg_Object_Data *pd = data;
335    Eo *renderer;
336 
337    /* unref all renderer and may also destroy them async */
338    while ((renderer = eina_array_pop(&pd->cleanup)))
339      efl_unref(renderer);
340 }
341 
342 EOLIAN static void
_efl_canvas_vg_object_efl_object_invalidate(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd)343 _efl_canvas_vg_object_efl_object_invalidate(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
344 {
345    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
346    Evas *e = evas_object_evas_get(eo_obj);
347 
348    efl_event_callback_del(e, EFL_CANVAS_SCENE_EVENT_RENDER_POST, _cleanup_reference, pd);
349    eina_array_flush(&pd->cleanup);
350 
351    efl_unref(pd->root);
352    pd->root = NULL;
353 
354    if (pd->user_entry)
355      {
356         Vg_User_Entry *user_entry = pd->user_entry;
357         ENFN->ector_surface_cache_drop(ENC, user_entry->root);
358         if (pd->user_entry->root) efl_unref(pd->user_entry->root);
359         free(pd->user_entry);
360      }
361    pd->user_entry = NULL;
362 
363    //Drop cache buffers
364    if (pd->vg_entry)
365      {
366         if (pd->ckeys[0])
367           ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->ckeys[0]);
368         if (pd->ckeys[1])
369           ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->ckeys[1]);
370      }
371    evas_cache_vg_entry_del(pd->vg_entry);
372 
373    efl_invalidate(efl_super(eo_obj, MY_CLASS));
374 }
375 
376 EOLIAN static Eo *
_efl_canvas_vg_object_efl_object_constructor(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd)377 _efl_canvas_vg_object_efl_object_constructor(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
378 {
379    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
380 
381    eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
382 
383    /* set up methods (compulsory) */
384    obj->func = &object_func;
385    obj->private_data = efl_data_ref(eo_obj, MY_CLASS);
386    obj->type = o_type;
387 
388    /* default root node */
389    pd->obj = obj;
390    pd->root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
391 
392    pd->sync_render = EINA_FALSE;
393 
394    eina_array_step_set(&pd->cleanup, sizeof(pd->cleanup), 8);
395 
396    return eo_obj;
397 }
398 
399 static Efl_Object *
_efl_canvas_vg_object_efl_object_finalize(Eo * obj,Efl_Canvas_Vg_Object_Data * pd)400 _efl_canvas_vg_object_efl_object_finalize(Eo *obj, Efl_Canvas_Vg_Object_Data *pd)
401 {
402    Evas *e = evas_object_evas_get(obj);
403 
404    /* Container must have a set parent after construction.
405       efl_add_ref() with a parent won't work this case
406       because container needs some jobs in overriding parent_set()
407       after proper intialization. */
408    efl_parent_set(pd->root, obj);
409 
410    // TODO: If we start to have to many Evas_Object_VG per canvas, it may be nice
411    // to actually have one event per canvas and one array per canvas to.
412    efl_event_callback_add(e, EFL_CANVAS_SCENE_EVENT_RENDER_POST, _cleanup_reference, pd);
413 
414    return obj;
415 }
416 
417 static void
_evas_vg_render(Evas_Object_Protected_Data * obj,Efl_Canvas_Vg_Object_Data * pd,void * engine,void * output,void * context,Efl_VG * node,Eina_Array * clips,int w,int h,Ector_Surface * ector,Eina_Bool do_async)418 _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
419                 void *engine, void *output, void *context, Efl_VG *node,
420                 Eina_Array *clips, int w, int h, Ector_Surface *ector, Eina_Bool do_async)
421 {
422    if (!efl_gfx_entity_visible_get(node)) return;
423 
424    if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS))
425      {
426         Efl_VG *child;
427         Eina_List *l;
428         Efl_Canvas_Vg_Container_Data *cd = efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
429 
430         if (cd->comp.src) return;   //Don't draw composite target itself.
431 
432         int alpha = 255;
433         efl_gfx_color_get(node, NULL, NULL, NULL, &alpha);
434 
435         if (alpha < 255)
436           {
437              //Replace with a new size.
438              if (cd->blend.buffer)
439                {
440                   int w2, h2;
441                   ector_buffer_size_get(cd->blend.buffer, &w2, &h2);
442                   if (w2 != w || h2 != h)
443                     efl_canvas_vg_container_blend_buffer_clear(node, cd);
444                }
445 
446              if (!cd->blend.buffer)
447                {
448                   cd->blend.buffer = ENFN->ector_buffer_new(ENC, obj->layer->evas->evas,
449                                                             w, h,
450                                                             EFL_GFX_COLORSPACE_ARGB8888,
451                                                             ECTOR_BUFFER_FLAG_DRAWABLE |
452                                                             ECTOR_BUFFER_FLAG_CPU_READABLE |
453                                                             ECTOR_BUFFER_FLAG_CPU_WRITABLE);
454                   cd->blend.pixels = ector_buffer_map(cd->blend.buffer, &cd->blend.length,
455                                                       (ECTOR_BUFFER_FLAG_DRAWABLE |
456                                                        ECTOR_BUFFER_FLAG_CPU_READABLE |
457                                                        ECTOR_BUFFER_FLAG_CPU_WRITABLE),
458                                                       0, 0, w, h,
459                                                       EFL_GFX_COLORSPACE_ARGB8888,
460                                                       &cd->blend.stride);
461                   if (!cd->blend.pixels) ERR("Failed to map VG blend bufffer");
462                }
463              else
464                {
465                   if (cd->blend.pixels)
466                     memset(cd->blend.pixels, 0, cd->blend.length);
467                }
468 
469              //For recovery context
470              //FIXME: It may occur async issue?
471              int px, py, pw, ph, pstride;
472              void *ppixels = NULL;
473              ector_buffer_size_get(ector, &pw, &ph);
474              ector_buffer_pixels_get(ector, &ppixels, &pw, &ph, &pstride);
475              Efl_Gfx_Colorspace pcspace = ector_buffer_cspace_get(ector);
476              ector_surface_reference_point_get(ector, &px, &py);
477 
478              // Buffer change
479              ector_buffer_pixels_set(ector, cd->blend.pixels,
480                                      w, h, cd->blend.stride,
481                                      EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
482              ector_surface_reference_point_set(ector, 0,0);
483 
484              // Draw child node to changed buffer
485              EINA_LIST_FOREACH(cd->children, l, child)
486                 _evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async);
487 
488              // Recover original surface
489              ector_buffer_pixels_set(ector, ppixels, pw, ph, pstride, pcspace, EINA_TRUE);
490              ector_surface_reference_point_set(ector, px, py);
491 
492              // Draw buffer to original surface.(Ector_Surface)
493              ector_surface_draw_image(ector, cd->blend.buffer, 0, 0, alpha);
494 
495           }
496         else
497           {
498              efl_canvas_vg_container_blend_buffer_clear(node, cd);
499 
500              EINA_LIST_FOREACH(cd->children, l, child)
501                 _evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async);
502           }
503      }
504    else
505      {
506         Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(node, EFL_CANVAS_VG_NODE_CLASS);
507         ENFN->ector_renderer_draw(engine, output, context, nd->renderer, clips, do_async);
508         if (do_async) eina_array_push(&pd->cleanup, efl_ref(nd->renderer));
509      }
510 }
511 
512 //renders a vg_tree to an offscreen buffer and push it to the cache.
513 static void *
_render_to_buffer(Evas_Object_Protected_Data * obj,Efl_Canvas_Vg_Object_Data * pd,void * engine,Efl_VG * root,int x,int y,int w,int h,void * buffer,void * ckey,Eina_Bool do_async)514 _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
515                   void *engine, Efl_VG *root, int x, int y, int w, int h, void *buffer, void *ckey,
516                   Eina_Bool do_async)
517 {
518    Ector_Surface *ector;
519    RGBA_Draw_Context *context;
520    int error = 0;
521    Eina_Bool buffer_created = EINA_FALSE;
522 
523    ector = evas_ector_get(obj->layer->evas);
524    if (!ector) return NULL;
525 
526    //create a buffer
527    if (!buffer)
528      {
529         buffer = ENFN->ector_surface_create(engine, w, h, &error);
530         if (error) return NULL;
531         buffer_created = EINA_TRUE;
532      }
533 
534    //initialize buffer
535    context = evas_common_draw_context_new();
536    evas_common_draw_context_set_render_op(context, _EVAS_RENDER_COPY);
537    evas_common_draw_context_set_color(context, 255, 255, 255, 255);
538 
539    //ector begin - end for drawing composite images.
540    _evas_vg_render_pre(obj, root, engine, buffer, context, ector, NULL, 255, NULL, 0);
541 
542    if (pd->sync_render) do_async = EINA_FALSE;
543 
544    //Actual content drawing
545    if (!ENFN->ector_begin(engine, buffer, context, ector, x, y, do_async))
546      {
547         ERR("Failed ector begin!");
548         return NULL;
549      }
550 
551    //draw on buffer
552    _evas_vg_render(obj, pd,
553                    engine, buffer,
554                    context, root,
555                    NULL,
556                    w, h, ector,
557                    do_async);
558 
559    ENFN->image_dirty_region(engine, buffer, 0, 0, w, h);
560    ENFN->ector_end(engine, buffer, context, ector, do_async);
561    evas_common_draw_context_free(context);
562 
563    if (buffer_created && ckey)
564      {
565         //Drop ex invalid cache buffers.
566         if (pd->frame_idx == 0 && ckey != pd->ckeys[0])
567           {
568              if (pd->ckeys[0])
569                ENFN->ector_surface_cache_drop(engine, pd->ckeys[0]);
570              pd->ckeys[0] = ckey;
571           }
572         else if (pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)
573                  && ckey != pd->ckeys[1])
574           {
575              if (pd->ckeys[1])
576                ENFN->ector_surface_cache_drop(engine, pd->ckeys[1]);
577              pd->ckeys[1] = ckey;
578           }
579         ENFN->ector_surface_cache_set(engine, ckey, buffer);
580      }
581 
582    return buffer;
583 }
584 
585 static void
_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 cacheable)586 _render_buffer_to_screen(Evas_Object_Protected_Data *obj,
587                          void *engine, void *output, void *context, void *surface,
588                          void *buffer,
589                          int x, int y, int w, int h,
590                          Eina_Bool do_async, Eina_Bool cacheable)
591 {
592    if (!buffer) return;
593 
594    Eina_Bool async_unref;
595 
596    //Draw the buffer as image to canvas
597    async_unref = ENFN->image_draw(engine, output, context, surface,
598                                                            buffer,
599                                                            0, 0, w, h,
600                                                            x, y, w, h,
601                                                            EINA_TRUE, do_async);
602    if (do_async && async_unref)
603      {
604         //Free buffer after drawing.
605         evas_cache_image_ref((Image_Entry *)buffer);
606         evas_unref_queue_image_put(obj->layer->evas, buffer);
607      }
608 
609    //TODO: Reuse buffer if size is same?
610    if (!cacheable) ENFN->ector_surface_destroy(engine, buffer);
611 }
612 
613 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,Eina_Bool cacheable)614 _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
615                        Efl_Canvas_Vg_Object_Data *pd,
616                        void *engine, void *output, void *context, void *surface,
617                        int x, int y, int w, int h, Eina_Bool do_async,
618                        Eina_Bool cacheable)
619 {
620    Vg_Cache_Entry *vg_entry = pd->vg_entry;
621    Efl_VG *root;
622    Eina_Position2D offset = {0, 0};  //Offset after keeping aspect ratio.
623    void *buffer = NULL;
624    void *key = NULL;
625 
626    evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers"));
627 
628    // if the size changed in between path set and the draw call;
629    if ((vg_entry->w != w) ||
630        (vg_entry->h != h))
631      {
632         Eina_Size2D size = evas_cache_vg_entry_default_size_get(pd->vg_entry);
633 
634         //adjust size for aspect ratio.
635         if (size.w > 0 && size.h > 0)
636           {
637              float rw = (float) w / (float) size.w;
638              float rh = (float) h / (float) size.h;
639 
640              if (rw < rh)
641                {
642                   size.w = w;
643                   size.h = (int) ((float) size.h * rw);
644                }
645              else
646                {
647                   size.w = (int) ((float) size.w * rh);
648                   size.h = h;
649                }
650           }
651         else
652           {
653               size.w = w;
654               size.h = h;
655           }
656 
657         //Size is changed, cached data is invalid.
658         if ((size.w != vg_entry->w) || (size.h != vg_entry->h))
659           {
660 //Not necessary, but this might be helpful for precise caching.
661 #if 0
662              if (cacheable)
663                {
664                   //if the size doesn't match, drop previous cache surface.
665                   key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, 0);
666                   if (key) ENFN->ector_surface_cache_drop(engine, key);
667 
668                   //Animatable... Try to drop the last frame image.
669                   int last_frame = (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1);
670                   if (last_frame > 0)
671                     {
672                        key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, last_frame);
673                        if (key) ENFN->ector_surface_cache_drop(engine, key);
674                     }
675                }
676 #endif
677              vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
678              evas_cache_vg_entry_del(pd->vg_entry);
679              pd->vg_entry = vg_entry;
680           }
681 
682         //update for adjusted pos and size.
683         offset.x = w - size.w;
684         if (offset.x > 0) offset.x /= 2;
685         offset.y = h - size.h;
686         if (offset.y > 0) offset.y /= 2;
687         w = size.w;
688         h = size.h;
689      }
690    root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx);
691    if (!root) return;
692 
693    if (cacheable)
694      {
695         key = evas_cache_vg_surface_key_get(root, w, h, pd->frame_idx);
696         if (key) buffer = ENFN->ector_surface_cache_get(engine, key);
697      }
698 
699    if (!buffer)
700      {
701         buffer = _render_to_buffer(obj, pd, engine, root, 0, 0, w, h, NULL, key, do_async);
702      }
703    else
704      {
705         //cache reference was increased when we get the cache.
706         if (key) ENFN->ector_surface_cache_drop(engine, key);
707      }
708 
709    _render_buffer_to_screen(obj,
710                             engine, output, context, surface,
711                             buffer,
712                             x + offset.x, y + offset.y, w, h,
713                             do_async, cacheable);
714 }
715 
716 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)717 _user_vg_entry_render(Evas_Object_Protected_Data *obj,
718                       Efl_Canvas_Vg_Object_Data *pd,
719                       void *engine, void *output, void *context, void *surface,
720                       int x, int y, int w, int h, Eina_Bool do_async)
721 {
722    Vg_User_Entry *user_entry = pd->user_entry;
723    Eina_Rect render_rect = EINA_RECT(x, y, w, h);
724 
725    // Get changed boundary and fit the size.
726    if (pd->changed)
727      efl_gfx_path_bounds_get(user_entry->root, &user_entry->path_bounds);
728 
729    if (user_entry->path_bounds.w != 0 && user_entry->path_bounds.h != 0)
730      {
731         EINA_RECTANGLE_SET(&render_rect, user_entry->path_bounds.x,
732                            user_entry->path_bounds.y,
733                            user_entry->path_bounds.w,
734                            user_entry->path_bounds.h);
735      }
736 
737    if (pd->viewbox.w != 0 && pd->viewbox.h !=0)
738      {
739         double sx = 0, sy= 0;
740         sx = (double)w / (double)pd->viewbox.w;
741         sy = (double)h / (double)pd->viewbox.h;
742         render_rect.x = (render_rect.x - pd->viewbox.x) * sx;
743         render_rect.y = (render_rect.y - pd->viewbox.y) * sy;
744         render_rect.w *= sx;
745         render_rect.h *= sy;
746      }
747 
748    //if the size doesn't match, drop previous cache surface.
749    if ((user_entry->w != render_rect.w ) ||
750        (user_entry->h != render_rect.h))
751      {
752         ENFN->ector_surface_cache_drop(engine, user_entry->root);
753         user_entry->w = render_rect.w;
754         user_entry->h = render_rect.h;
755      }
756 
757    //if the buffer is not created yet
758    void *buffer = NULL;
759 
760    buffer = ENFN->ector_surface_cache_get(engine, user_entry->root);
761 
762    if (!buffer)
763      {
764         // render to the buffer
765         buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
766                                    render_rect.x, render_rect.y, render_rect.w, render_rect.h, buffer, user_entry->root, do_async);
767      }
768    else
769      {
770         // render to the buffer
771         if (pd->changed)
772           buffer = _render_to_buffer(obj, pd, engine,
773                                      user_entry->root,
774                                      render_rect.x, render_rect.y, render_rect.w, render_rect.h, buffer, NULL,
775                                      do_async);
776         //cache reference was increased when we get the cache.
777         ENFN->ector_surface_cache_drop(engine, user_entry->root);
778      }
779 
780    _render_buffer_to_screen(obj,
781                             engine, output, context, surface,
782                             buffer,
783                             x + render_rect.x,
784                             y + render_rect.y,
785                             render_rect.w, render_rect.h,
786                             do_async, EINA_TRUE);
787 }
788 
789 static void
_efl_canvas_vg_object_render(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data,void * engine,void * output,void * context,void * surface,int x,int y,Eina_Bool do_async)790 _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
791                              Evas_Object_Protected_Data *obj,
792                              void *type_private_data,
793                              void *engine, void *output, void *context, void *surface,
794                              int x, int y, Eina_Bool do_async)
795 {
796    Efl_Canvas_Vg_Object_Data *pd = type_private_data;
797 
798    /* render object to surface with context, and offxet by x,y */
799    ENFN->context_color_set(engine, context, 255, 255, 255, 255);
800    ENFN->context_multiplier_set(engine, context,
801                                 obj->cur->cache.clip.r,
802                                 obj->cur->cache.clip.g,
803                                 obj->cur->cache.clip.b,
804                                 obj->cur->cache.clip.a);
805    ENFN->context_anti_alias_set(engine, context, obj->cur->anti_alias);
806    ENFN->context_render_op_set(engine, context, obj->cur->render_op);
807 
808    //Cache surface?
809    Eina_Bool cacheable = EINA_FALSE;
810 
811    /* Try caching buffer only for first and last frames
812       because it's an overhead task if it caches all frame images.
813       We assume the first and last frame images are the most resusable
814       in generic scenarios. */
815    if (pd->frame_idx == 0 ||
816        (pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)))
817      cacheable = EINA_TRUE;
818 
819    if (pd->vg_entry)
820      {
821         _cache_vg_entry_render(obj, pd,
822                                engine, output, context, surface,
823                                obj->cur->geometry.x + x, obj->cur->geometry.y + y,
824                                obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
825      }
826    if (pd->user_entry)
827      {
828         _user_vg_entry_render(obj, pd,
829                               engine, output, context, surface,
830                               obj->cur->geometry.x + x, obj->cur->geometry.y + y,
831                               obj->cur->geometry.w, obj->cur->geometry.h, do_async);
832      }
833    pd->changed = EINA_FALSE;
834 }
835 
836 static void
_efl_canvas_vg_object_render_pre(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data)837 _efl_canvas_vg_object_render_pre(Evas_Object *eo_obj,
838                                  Evas_Object_Protected_Data *obj,
839                                  void *type_private_data)
840 {
841    Efl_Canvas_Vg_Object_Data *pd = type_private_data;
842    int is_v, was_v;
843 
844    if (obj->pre_render_done) return;
845    obj->pre_render_done = EINA_TRUE;
846 
847    /* pre-render phase. this does anything an object needs to do just before */
848    /* rendering. this could mean loading the image data, retrieving it from */
849    /* elsewhere, decoding video etc. */
850    /* then when this is done the object needs to figure if it changed and */
851    /* if so what and where and add the appropriate redraw rectangles */
852    /* if someone is clipping this obj - go calculate the clipper */
853    if (obj->cur->clipper)
854      {
855         if (obj->cur->cache.clip.dirty)
856           evas_object_clip_recalc(obj->cur->clipper);
857         obj->cur->clipper->func->render_pre(obj->cur->clipper->object,
858                                             obj->cur->clipper,
859                                             obj->cur->clipper->private_data);
860      }
861 
862    /* now figure what changed and add draw rects */
863    /* if it just became visible or invisible */
864    is_v = evas_object_is_visible(obj);
865    was_v = evas_object_was_visible(obj);
866    if (!(is_v | was_v)) goto done;
867 
868    if (pd->changed)
869      {
870         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj);
871         goto done;
872      }
873 
874    if (is_v != was_v)
875      {
876         evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, eo_obj, is_v, was_v);
877         goto done;
878      }
879    if (obj->changed_map || obj->changed_src_visible)
880      {
881         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj);
882         goto done;
883      }
884    /* it's not visible - we accounted for it appearing or not so just abort */
885    if (!is_v) goto done;
886    /* clipper changed this is in addition to anything else for obj */
887    evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, eo_obj);
888    /* if we restacked (layer or just within a layer) and don't clip anyone */
889    if ((obj->restack) && (!obj->clip.clipees))
890      {
891         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj);
892         goto done;
893      }
894    /* if it changed render op */
895    if (obj->cur->render_op != obj->prev->render_op)
896      {
897         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj);
898         goto done;
899      }
900    /* if it changed color */
901    if ((obj->cur->color.r != obj->prev->color.r) ||
902        (obj->cur->color.g != obj->prev->color.g) ||
903        (obj->cur->color.b != obj->prev->color.b) ||
904        (obj->cur->color.a != obj->prev->color.a) ||
905        (obj->cur->cache.clip.r != obj->prev->cache.clip.r) ||
906        (obj->cur->cache.clip.g != obj->prev->cache.clip.g) ||
907        (obj->cur->cache.clip.b != obj->prev->cache.clip.b) ||
908        (obj->cur->cache.clip.a != obj->prev->cache.clip.a))
909      {
910         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj);
911         goto done;
912      }
913    /* if it changed geometry - and obviously not visibility or color */
914    /* calculate differences since we have a constant color fill */
915    /* we really only need to update the differences */
916    if ((obj->cur->geometry.x != obj->prev->geometry.x) ||
917        (obj->cur->geometry.y != obj->prev->geometry.y) ||
918        (obj->cur->geometry.w != obj->prev->geometry.w) ||
919        (obj->cur->geometry.h != obj->prev->geometry.h))
920      {
921         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj);
922         goto done;
923      }
924    /* it obviously didn't change - add a NO obscure - this "unupdates"  this */
925    /* area so if there were updates for it they get wiped. don't do it if we */
926    /* arent fully opaque and we are visible */
927    if (evas_object_is_visible(obj) &&
928        evas_object_is_opaque(obj) &&
929        (!obj->clip.clipees))
930      {
931         Evas_Coord x, y, w, h;
932 
933         x = obj->cur->cache.clip.x;
934         y = obj->cur->cache.clip.y;
935         w = obj->cur->cache.clip.w;
936         h = obj->cur->cache.clip.h;
937         if (obj->cur->clipper)
938           {
939              RECTS_CLIP_TO_RECT(x, y, w, h,
940                                 obj->cur->clipper->cur->cache.clip.x,
941                                 obj->cur->clipper->cur->cache.clip.y,
942                                 obj->cur->clipper->cur->cache.clip.w,
943                                 obj->cur->clipper->cur->cache.clip.h);
944           }
945         evas_render_update_del(obj->layer->evas,
946                                x + obj->layer->evas->framespace.x,
947                                y + obj->layer->evas->framespace.y,
948                                w, h);
949      }
950 
951 done:
952    evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, eo_obj, is_v, was_v);
953 }
954 
955 static void
_efl_canvas_vg_object_render_post(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data EINA_UNUSED)956 _efl_canvas_vg_object_render_post(Evas_Object *eo_obj EINA_UNUSED,
957                                   Evas_Object_Protected_Data *obj,
958                                   void *type_private_data EINA_UNUSED)
959 {
960    /* this moves the current data to the previous state parts of the object */
961    /* in whatever way is safest for the object. also if we don't need object */
962    /* data anymore we can free it if the object deems this is a good idea */
963    /* remove those pesky changes */
964    evas_object_clip_changes_clean(obj);
965    /* move cur to prev safely for object data */
966    evas_object_cur_prev(obj);
967 }
968 
969 static int
_efl_canvas_vg_object_is_opaque(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj EINA_UNUSED,void * type_private_data EINA_UNUSED)970 _efl_canvas_vg_object_is_opaque(Evas_Object *eo_obj EINA_UNUSED,
971                                 Evas_Object_Protected_Data *obj EINA_UNUSED,
972                                 void *type_private_data EINA_UNUSED)
973 {
974    return 0;
975 }
976 
977 static int
_efl_canvas_vg_object_was_opaque(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj EINA_UNUSED,void * type_private_data EINA_UNUSED)978 _efl_canvas_vg_object_was_opaque(Evas_Object *eo_obj EINA_UNUSED,
979                                  Evas_Object_Protected_Data *obj EINA_UNUSED,
980                                  void *type_private_data EINA_UNUSED)
981 {
982    return 0;
983 }
984 
985 /* animated feature */
986 EOLIAN static Eina_Bool
_efl_canvas_vg_object_efl_gfx_frame_controller_animated_get(const Eo * eo_obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd EINA_UNUSED EINA_UNUSED)987 _efl_canvas_vg_object_efl_gfx_frame_controller_animated_get(const Eo *eo_obj EINA_UNUSED,
988                                                                       Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED EINA_UNUSED)
989 {
990    //TODO:
991    return EINA_TRUE;
992 }
993 
994 EOLIAN static int
_efl_canvas_vg_object_efl_gfx_frame_controller_frame_count_get(const Eo * eo_obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd EINA_UNUSED)995 _efl_canvas_vg_object_efl_gfx_frame_controller_frame_count_get(const Eo *eo_obj EINA_UNUSED,
996                                                                                   Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
997 {
998    if (!pd->vg_entry) return 0;
999    return evas_cache_vg_anim_frame_count_get(pd->vg_entry);
1000 }
1001 
1002 EOLIAN static Efl_Gfx_Frame_Controller_Loop_Hint
_efl_canvas_vg_object_efl_gfx_frame_controller_loop_type_get(const Eo * eo_obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd EINA_UNUSED)1003 _efl_canvas_vg_object_efl_gfx_frame_controller_loop_type_get(const Eo *eo_obj EINA_UNUSED,
1004                                                                                 Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
1005 {
1006    //TODO:
1007    return EFL_GFX_FRAME_CONTROLLER_LOOP_HINT_NONE;
1008 }
1009 
1010 EOLIAN static int
_efl_canvas_vg_object_efl_gfx_frame_controller_loop_count_get(const Eo * eo_obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd EINA_UNUSED)1011 _efl_canvas_vg_object_efl_gfx_frame_controller_loop_count_get(const Eo *eo_obj EINA_UNUSED,
1012                                                                                  Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
1013 {
1014    //TODO:
1015    return 0;
1016 }
1017 
1018 EOLIAN static double
_efl_canvas_vg_object_efl_gfx_frame_controller_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)1019 _efl_canvas_vg_object_efl_gfx_frame_controller_frame_duration_get(const Eo *eo_obj EINA_UNUSED,
1020                                                                                      Efl_Canvas_Vg_Object_Data *pd,
1021                                                                                      int start_frame EINA_UNUSED,
1022                                                                                      int frame_num EINA_UNUSED)
1023 {
1024    if (!pd->vg_entry) return 0;
1025    return evas_cache_vg_anim_duration_get(pd->vg_entry);
1026 }
1027 
_efl_canvas_vg_object_efl_gfx_frame_controller_sector_set(Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd,const char * name,int startframe,int endframe)1028 Eina_Bool _efl_canvas_vg_object_efl_gfx_frame_controller_sector_set(Eo *obj EINA_UNUSED,
1029                                                                     Efl_Canvas_Vg_Object_Data *pd,
1030                                                                     const char *name,
1031                                                                     int startframe,
1032                                                                     int endframe)
1033 {
1034    if (!pd->vg_entry) return EINA_FALSE;
1035    if (!evas_cache_vg_anim_sector_set(pd->vg_entry, name, startframe, endframe))
1036      return EINA_FALSE;
1037    return EINA_TRUE;
1038 }
1039 
_efl_canvas_vg_object_efl_gfx_frame_controller_sector_get(const Eo * obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd,const char * name,int * startframe,int * endframe)1040 Eina_Bool _efl_canvas_vg_object_efl_gfx_frame_controller_sector_get(const Eo *obj EINA_UNUSED,
1041                                                                     Efl_Canvas_Vg_Object_Data *pd,
1042                                                                     const char *name,
1043                                                                     int *startframe,
1044                                                                     int *endframe)
1045 {
1046    if (!pd->vg_entry) return EINA_FALSE;
1047    if (!evas_cache_vg_anim_sector_get(pd->vg_entry, name, startframe, endframe))
1048      return EINA_FALSE;
1049    return EINA_TRUE;
1050 }
1051 
1052 EOLIAN static Eina_Bool
_efl_canvas_vg_object_efl_gfx_frame_controller_frame_set(Eo * eo_obj,Efl_Canvas_Vg_Object_Data * pd,int frame_index)1053 _efl_canvas_vg_object_efl_gfx_frame_controller_frame_set(Eo *eo_obj,
1054                                                          Efl_Canvas_Vg_Object_Data *pd,
1055                                                          int frame_index)
1056 {
1057    //TODO: Validate frame_index range
1058    if (pd->frame_idx == frame_index) return EINA_TRUE;
1059 
1060    //Image is changed, drop previous cached image.
1061    pd->frame_idx = frame_index;
1062    pd->changed = EINA_TRUE;
1063    evas_object_change(eo_obj, efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS));
1064 
1065    return EINA_TRUE;
1066 }
1067 
1068 EOLIAN static int
_efl_canvas_vg_object_efl_gfx_frame_controller_frame_get(const Eo * eo_obj EINA_UNUSED,Efl_Canvas_Vg_Object_Data * pd EINA_UNUSED)1069 _efl_canvas_vg_object_efl_gfx_frame_controller_frame_get(const Eo *eo_obj EINA_UNUSED,
1070                                                                             Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
1071 {
1072    return pd->frame_idx;
1073 }
1074 
1075 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)1076 _efl_canvas_vg_object_default_size_get(const Eo *eo_obj EINA_UNUSED,
1077                                        Efl_Canvas_Vg_Object_Data *pd EINA_UNUSED)
1078 {
1079    return evas_cache_vg_entry_default_size_get(pd->vg_entry);
1080 }
1081 
1082 /* the actual api call to add a vector graphic object */
1083 EAPI Eo *
evas_object_vg_add(Evas * e)1084 evas_object_vg_add(Evas *e)
1085 {
1086    e = evas_find(e);
1087    EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(e, EVAS_CANVAS_CLASS), NULL);
1088    // TODO: Ask backend to return the main Ector_Surface
1089    return efl_add(MY_CLASS, e, efl_canvas_object_legacy_ctor(efl_added));
1090 }
1091 
1092 EAPI int
evas_object_vg_animated_frame_get(const Evas_Object * obj)1093 evas_object_vg_animated_frame_get(const Evas_Object *obj)
1094 {
1095    return efl_gfx_frame_controller_frame_get(obj);
1096 }
1097 
1098 EAPI double
evas_object_vg_animated_frame_duration_get(const Evas_Object * obj,int start_frame,int frame_num)1099 evas_object_vg_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num)
1100 {
1101    return efl_gfx_frame_controller_frame_duration_get(obj, start_frame, frame_num);
1102 }
1103 
1104 EAPI int
evas_object_vg_animated_frame_count_get(const Evas_Object * obj)1105 evas_object_vg_animated_frame_count_get(const Evas_Object *obj)
1106 {
1107    return efl_gfx_frame_controller_frame_count_get(obj);
1108 }
1109 
1110 EAPI Eina_Bool
evas_object_vg_animated_frame_set(Evas_Object * obj,int frame_index)1111 evas_object_vg_animated_frame_set(Evas_Object *obj, int frame_index)
1112 {
1113    return efl_gfx_frame_controller_frame_set(obj, frame_index);
1114 }
1115 
1116 EAPI Eina_Bool
evas_object_vg_file_set(Evas_Object * obj,const char * file,const char * key)1117 evas_object_vg_file_set(Evas_Object *obj, const char *file, const char *key)
1118 {
1119    return efl_file_simple_load(obj, file, key);
1120 }
1121 
1122 static inline Efl_Canvas_Vg_Fill_Mode
_evas_object_vg_fill_mode_to_efl_ui_canvas_object_vg_fill_mode(Evas_Object_Vg_Fill_Mode mode)1123 _evas_object_vg_fill_mode_to_efl_ui_canvas_object_vg_fill_mode(Evas_Object_Vg_Fill_Mode mode)
1124 {
1125    switch (mode)
1126      {
1127 #define CONVERT_MODE(MODE) case EVAS_OBJECT_VG_FILL_MODE_##MODE: return EFL_CANVAS_VG_FILL_MODE_##MODE
1128        CONVERT_MODE(NONE);
1129        CONVERT_MODE(STRETCH);
1130        CONVERT_MODE(MEET);
1131        CONVERT_MODE(SLICE);
1132        default: break;
1133      }
1134 #undef CONVERT_MODE
1135    return EFL_CANVAS_VG_FILL_MODE_NONE;
1136 }
1137 
1138 static inline Evas_Object_Vg_Fill_Mode
_efl_ui_canvas_object_vg_fill_mode_to_evas_object_vg_fill_mode(Efl_Canvas_Vg_Fill_Mode mode)1139 _efl_ui_canvas_object_vg_fill_mode_to_evas_object_vg_fill_mode(Efl_Canvas_Vg_Fill_Mode mode)
1140 {
1141    switch (mode)
1142      {
1143 #define CONVERT_MODE(MODE) case EFL_CANVAS_VG_FILL_MODE_##MODE: return EVAS_OBJECT_VG_FILL_MODE_##MODE
1144        CONVERT_MODE(NONE);
1145        CONVERT_MODE(STRETCH);
1146        CONVERT_MODE(MEET);
1147        CONVERT_MODE(SLICE);
1148        default: break;
1149      }
1150 #undef CONVERT_MODE
1151    return EVAS_OBJECT_VG_FILL_MODE_NONE;
1152 }
1153 
1154 EAPI void
evas_object_vg_fill_mode_set(Evas_Object * obj,Evas_Object_Vg_Fill_Mode fill_mode)1155 evas_object_vg_fill_mode_set(Evas_Object *obj, Evas_Object_Vg_Fill_Mode fill_mode)
1156 {
1157    efl_canvas_vg_object_fill_mode_set(obj, _evas_object_vg_fill_mode_to_efl_ui_canvas_object_vg_fill_mode(fill_mode));
1158 }
1159 
1160 EAPI Evas_Object_Vg_Fill_Mode
evas_object_vg_fill_mode_get(const Evas_Object * obj)1161 evas_object_vg_fill_mode_get(const Evas_Object *obj)
1162 {
1163    return _efl_ui_canvas_object_vg_fill_mode_to_evas_object_vg_fill_mode(efl_canvas_vg_object_fill_mode_get(obj));
1164 }
1165 
1166 #include "efl_canvas_vg_object.eo.c"
1167 #include "efl_canvas_vg_object_eo.legacy.c"
1168