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