// detach/free the old root_node
if (pd->user_entry && pd->user_entry->root)
{
-#ifndef HAVE_THORVG
- // drop any surface cache attached to it.
- ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root);
-#endif
efl_canvas_vg_node_vg_obj_set(pd->user_entry->root, NULL, NULL);
efl_replace(&pd->user_entry->root, NULL);
}
if (pd->user_entry)
{
-#ifndef HAVE_THORVG
- ENFN->ector_surface_cache_drop(ENC, pd->user_entry->root);
-#endif
if (pd->user_entry->root) efl_unref(pd->user_entry->root);
free(pd->user_entry);
}
pd->user_entry = NULL;
- //Drop cache buffers
- if (pd->vg_entry)
- {
-#ifndef HAVE_THORVG
- if (pd->ckeys[0])
- ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->ckeys[0]);
- if (pd->ckeys[1])
- ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->ckeys[1]);
-#endif
- }
evas_cache_vg_entry_del(pd->vg_entry);
-#ifdef HAVE_THORVG
if (pd->tvg_buffer)
{
free(pd->tvg_buffer);
tvg_canvas_clear(pd->tvg_canvas, false);
tvg_canvas_destroy(pd->tvg_canvas);
}
-#endif
+
efl_invalidate(efl_super(eo_obj, MY_CLASS));
}
pd->root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
pd->sync_render = EINA_FALSE;
-#ifdef HAVE_THORVG
pd->tvg_canvas = tvg_swcanvas_create();
pd->tvg_canvas_size.w = 0;
pd->tvg_canvas_size.h = 0;
-#endif
eina_array_step_set(&pd->cleanup, sizeof(pd->cleanup), 8);
return eo_obj;
return obj;
}
-#ifdef HAVE_THORVG
static void
_render_to_tvg_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
Efl_VG *root, int w EINA_UNUSED, int h EINA_UNUSED)
if (!buffer)
return;
-
+
image = ENFN->image_new_from_copied_data(engine, w, h, buffer, 255, EVAS_COLORSPACE_ARGB8888);
async_unref = ENFN->image_draw(engine, output, context, surface,
ENFN->image_free(engine, image);
}
-#else
-
-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)
-{
- if (!efl_gfx_entity_visible_get(node)) return;
-
- if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS))
- {
- Efl_VG *child;
- Eina_List *l;
- Efl_Canvas_Vg_Container_Data *cd = efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
-
- if (cd->comp.src) return; //Don't draw composite target itself.
-
- int alpha = 255;
- efl_gfx_color_get(node, NULL, NULL, NULL, &alpha);
-
- if (alpha < 255)
- {
- //Replace with a new size.
- if (cd->blend.buffer)
- {
- int w2, h2;
- ector_buffer_size_get(cd->blend.buffer, &w2, &h2);
- }
-
- if (!cd->blend.buffer)
- {
- cd->blend.buffer = ENFN->ector_buffer_new(ENC, obj->layer->evas->evas,
- w, h,
- EFL_GFX_COLORSPACE_ARGB8888,
- ECTOR_BUFFER_FLAG_DRAWABLE |
- ECTOR_BUFFER_FLAG_CPU_READABLE |
- ECTOR_BUFFER_FLAG_CPU_WRITABLE);
- cd->blend.pixels = ector_buffer_map(cd->blend.buffer, &cd->blend.length,
- (ECTOR_BUFFER_FLAG_DRAWABLE |
- ECTOR_BUFFER_FLAG_CPU_READABLE |
- ECTOR_BUFFER_FLAG_CPU_WRITABLE),
- 0, 0, w, h,
- EFL_GFX_COLORSPACE_ARGB8888,
- &cd->blend.stride);
- if (!cd->blend.pixels) ERR("Failed to map VG blend bufffer");
- }
- else
- {
- if (cd->blend.pixels)
- memset(cd->blend.pixels, 0, cd->blend.length);
- }
-
- //For recovery context
- //FIXME: It may occur async issue?
- int px, py, pw, ph, pstride;
- void *ppixels = NULL;
- ector_buffer_size_get(ector, &pw, &ph);
- ector_buffer_pixels_get(ector, &ppixels, &pw, &ph, &pstride);
- Efl_Gfx_Colorspace pcspace = ector_buffer_cspace_get(ector);
- ector_surface_reference_point_get(ector, &px, &py);
-
- // Buffer change
- ector_buffer_pixels_set(ector, cd->blend.pixels,
- w, h, cd->blend.stride,
- EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
- ector_surface_reference_point_set(ector, 0,0);
-
- // Draw child node to changed buffer
- EINA_LIST_FOREACH(cd->children, l, child)
- _evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async);
-
- // Recover original surface
- ector_buffer_pixels_set(ector, ppixels, pw, ph, pstride, pcspace, EINA_TRUE);
- ector_surface_reference_point_set(ector, px, py);
-
- // Draw buffer to original surface.(Ector_Surface)
- ector_surface_draw_image(ector, cd->blend.buffer, 0, 0, alpha);
-
- }
- else
- {
- EINA_LIST_FOREACH(cd->children, l, child)
- _evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async);
- }
- }
- else
- {
- Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(node, EFL_CANVAS_VG_NODE_CLASS);
- ENFN->ector_renderer_draw(engine, output, context, nd->renderer, clips, do_async);
- if (do_async) eina_array_push(&pd->cleanup, efl_ref(nd->renderer));
- }
-}
-
-//renders a vg_tree to an offscreen buffer and push it to the cache.
-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)
-{
- Ector_Surface *ector;
- RGBA_Draw_Context *context;
- int error = 0;
- Eina_Bool buffer_created = EINA_FALSE;
-
- ector = evas_ector_get(obj->layer->evas);
- if (!ector) return NULL;
-
- //create a buffer
- if (!buffer)
- {
- buffer = ENFN->ector_surface_create(engine, w, h, &error);
- if (error) return NULL;
- buffer_created = EINA_TRUE;
- }
-
- //initialize buffer
- context = evas_common_draw_context_new();
- evas_common_draw_context_set_render_op(context, _EVAS_RENDER_COPY);
- evas_common_draw_context_set_color(context, 255, 255, 255, 255);
-
- //ector begin - end for drawing composite images.
- _evas_vg_render_pre(obj, root, engine, buffer, context, ector, NULL, 255, NULL, 0);
-
- if (pd->sync_render) do_async = EINA_FALSE;
-
- //Actual content drawing
- if (!ENFN->ector_begin(engine, buffer, context, ector, x, y, do_async))
- {
- ERR("Failed ector begin!");
- return NULL;
- }
-
- //draw on buffer
- _evas_vg_render(obj, pd,
- engine, buffer,
- context, root,
- NULL,
- w, h, ector,
- do_async);
-
- ENFN->image_dirty_region(engine, buffer, 0, 0, w, h);
- ENFN->ector_end(engine, buffer, context, ector, do_async);
- evas_common_draw_context_free(context);
-
- if (buffer_created && ckey)
- {
- //Drop ex invalid cache buffers.
- if (pd->frame_idx == 0 && ckey != pd->ckeys[0])
- {
- if (pd->ckeys[0])
- ENFN->ector_surface_cache_drop(engine, pd->ckeys[0]);
- pd->ckeys[0] = ckey;
- }
- else if (pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)
- && ckey != pd->ckeys[1])
- {
- if (pd->ckeys[1])
- ENFN->ector_surface_cache_drop(engine, pd->ckeys[1]);
- pd->ckeys[1] = ckey;
- }
- ENFN->ector_surface_cache_set(engine, ckey, buffer);
- }
-
- return buffer;
-}
-
-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)
-{
- if (!buffer) return;
-
- Eina_Bool async_unref;
-
- //Draw the buffer as image to canvas
- async_unref = ENFN->image_draw(engine, output, context, surface,
- buffer,
- 0, 0, w, h,
- x, y, w, h,
- EINA_TRUE, do_async);
- if (do_async && async_unref)
- {
- //Free buffer after drawing.
- evas_cache_image_ref((Image_Entry *)buffer);
- evas_unref_queue_image_put(obj->layer->evas, buffer);
- }
-
- //TODO: Reuse buffer if size is same?
- if (!cacheable) ENFN->ector_surface_destroy(engine, buffer);
-}
-
-static void
-_cache_vg_entry_render(Evas_Object_Protected_Data *obj,
- Efl_Canvas_Vg_Object_Data *pd,
- void *engine, void *output, void *context, void *surface,
- int x, int y, int w, int h, Eina_Bool do_async,
- Eina_Bool cacheable)
-{
- Vg_Cache_Entry *vg_entry = pd->vg_entry;
- Efl_VG *root;
- Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio.
- void *buffer = NULL;
- void *key = NULL;
-
- evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers"));
-
- // if the size changed in between path set and the draw call;
- if ((vg_entry->w != w) ||
- (vg_entry->h != h))
- {
- Eina_Size2D size = evas_cache_vg_entry_default_size_get(pd->vg_entry);
-
- //adjust size for aspect ratio.
- if (size.w > 0 && size.h > 0)
- {
- float rw = (float) w / (float) size.w;
- float rh = (float) h / (float) size.h;
-
- if (rw < rh)
- {
- size.w = w;
- size.h = (int) ((float) size.h * rw);
- }
- else
- {
- size.w = (int) ((float) size.w * rh);
- size.h = h;
- }
- }
- else
- {
- size.w = w;
- size.h = h;
- }
-
- //Size is changed, cached data is invalid.
- if ((size.w != vg_entry->w) || (size.h != vg_entry->h))
- {
-//Not necessary, but this might be helpful for precise caching.
-#if 0
- if (cacheable)
- {
- //if the size doesn't match, drop previous cache surface.
- key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, 0);
- if (key) ENFN->ector_surface_cache_drop(engine, key);
-
- //Animatable... Try to drop the last frame image.
- int last_frame = (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1);
- if (last_frame > 0)
- {
- key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, last_frame);
- if (key) ENFN->ector_surface_cache_drop(engine, key);
- }
- }
-#endif
- vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
- evas_cache_vg_entry_del(pd->vg_entry);
- pd->vg_entry = vg_entry;
- }
-
- //update for adjusted pos and size.
- offset.x = w - size.w;
- if (offset.x > 0) offset.x /= 2;
- offset.y = h - size.h;
- if (offset.y > 0) offset.y /= 2;
- w = size.w;
- h = size.h;
- }
- root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx);
- if (!root) return;
-
- if (cacheable)
- {
- key = evas_cache_vg_surface_key_get(root, w, h, pd->frame_idx);
- if (key) buffer = ENFN->ector_surface_cache_get(engine, key);
- }
-
- if (!buffer)
- {
- buffer = _render_to_buffer(obj, pd, engine, root, 0, 0, w, h, NULL, key, do_async);
- }
- else
- {
- //cache reference was increased when we get the cache.
- if (key) ENFN->ector_surface_cache_drop(engine, key);
- }
-
- _render_buffer_to_screen(obj,
- engine, output, context, surface,
- buffer,
- x + offset.x, y + offset.y, w, h,
- do_async, cacheable);
-}
-
-static void
-_user_vg_entry_render(Evas_Object_Protected_Data *obj,
- Efl_Canvas_Vg_Object_Data *pd,
- void *engine, void *output, void *context, void *surface,
- int x, int y, int w, int h, Eina_Bool do_async)
-{
- Vg_User_Entry *user_entry = pd->user_entry;
- Eina_Rect render_rect = EINA_RECT(x, y, w, h);
-
- // Get changed boundary and fit the size.
- if (pd->changed)
- efl_gfx_path_bounds_get(user_entry->root, &user_entry->path_bounds);
-
- if (user_entry->path_bounds.w != 0 && user_entry->path_bounds.h != 0)
- {
- EINA_RECTANGLE_SET(&render_rect, user_entry->path_bounds.x,
- user_entry->path_bounds.y,
- user_entry->path_bounds.w,
- user_entry->path_bounds.h);
- }
- // If size of the drawing area is 0, no render.
- else return;
-
- if (pd->viewbox.w != 0 && pd->viewbox.h !=0)
- {
- double sx = 0, sy= 0;
- sx = (double)w / (double)pd->viewbox.w;
- sy = (double)h / (double)pd->viewbox.h;
- render_rect.x = (render_rect.x - pd->viewbox.x) * sx;
- render_rect.y = (render_rect.y - pd->viewbox.y) * sy;
- render_rect.w *= sx;
- render_rect.h *= sy;
- }
-
- //if the size doesn't match, drop previous cache surface.
- if ((user_entry->w != render_rect.w ) ||
- (user_entry->h != render_rect.h))
- {
- ENFN->ector_surface_cache_drop(engine, user_entry->root);
- user_entry->w = render_rect.w;
- user_entry->h = render_rect.h;
- }
-
- //if the buffer is not created yet
- void *buffer = NULL;
-
- buffer = ENFN->ector_surface_cache_get(engine, user_entry->root);
-
- if (!buffer)
- {
- // render to the buffer
- buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
- render_rect.x, render_rect.y, render_rect.w, render_rect.h, buffer, user_entry->root, do_async);
- }
- else
- {
- // render to the buffer
- if (pd->changed)
- buffer = _render_to_buffer(obj, pd, engine,
- user_entry->root,
- render_rect.x, render_rect.y, render_rect.w, render_rect.h, buffer, NULL,
- do_async);
- //cache reference was increased when we get the cache.
- ENFN->ector_surface_cache_drop(engine, user_entry->root);
- }
-
- _render_buffer_to_screen(obj,
- engine, output, context, surface,
- buffer,
- x + render_rect.x,
- y + render_rect.y,
- render_rect.w, render_rect.h,
- do_async, EINA_TRUE);
-}
-
-#endif
-
static void
_efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
ENFN->context_anti_alias_set(engine, context, obj->cur->anti_alias);
ENFN->context_render_op_set(engine, context, obj->cur->render_op);
-#ifdef HAVE_THORVG
Eina_Size2D size;
size.w = obj->cur->geometry.w;
_render_tvg_buffer_to_screen(obj, pd, engine, output, context, surface,
pd->tvg_buffer, obj->cur->geometry.x + x,
obj->cur->geometry.y + y, size.w, size.h, do_async);
-#else
- //Cache surface?
- Eina_Bool cacheable = EINA_FALSE;
-
- /* Try caching buffer only for first and last frames
- because it's an overhead task if it caches all frame images.
- We assume the first and last frame images are the most resusable
- in generic scenarios. */
- if (pd->frame_idx == 0 ||
- (pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)))
- cacheable = EINA_TRUE;
-
- if (pd->vg_entry)
- {
- _cache_vg_entry_render(obj, pd,
- engine, output, context, surface,
- obj->cur->geometry.x + x, obj->cur->geometry.y + y,
- obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable);
- }
-
- if (pd->user_entry)
- {
- _user_vg_entry_render(obj, pd,
- engine, output, context, surface,
- obj->cur->geometry.x + x, obj->cur->geometry.y + y,
- obj->cur->geometry.w, obj->cur->geometry.h, do_async);
- }
-#endif
pd->changed = EINA_FALSE;
}