efl/src/lib/evas/canvas/evas_object_image.c

3570 lines
127 KiB
C
Raw Normal View History

2018-09-02 23:19:02 -07:00
#include "evas_image_private.h"
#define MY_CLASS EFL_CANVAS_IMAGE_INTERNAL_CLASS
#define MY_CLASS_NAME "Evas_Image"
2002-11-08 00:02:15 -08:00
/* private magic number for image objects */
static const char o_type[] = "image";
const char *o_image_type = o_type;
2002-11-08 00:02:15 -08:00
/* private methods for image objects */
static Evas_Coord evas_object_image_figure_x_fill(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret);
static Evas_Coord evas_object_image_figure_y_fill(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret);
static void evas_object_image_init(Evas_Object *eo_obj);
static void evas_object_image_render(Evas_Object *eo_obj, 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);
static void _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *engine, void *output, void *context, void *surface,
int x, int y, int l, int t, int r, int b, Eina_Bool skip_map, Eina_Bool do_async);
static void evas_object_image_free(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj);
static void evas_object_image_render_pre(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data);
static void evas_object_image_render_post(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data);
static void *evas_object_image_engine_data_get(Evas_Object *eo_obj);
static int evas_object_image_is_opaque(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data);
static int evas_object_image_was_opaque(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data);
static int evas_object_image_is_inside(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data,
Evas_Coord x, Evas_Coord y);
static int evas_object_image_has_opaque_rect(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data);
static int evas_object_image_get_opaque_rect(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data,
Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
static int evas_object_image_can_map(Evas_Object *eo_obj);
static void evas_object_image_render_prepare(Evas_Object *obj, Evas_Object_Protected_Data *pd, Eina_Bool do_async);
static void evas_object_image_filled_resize_listener(void *data, Evas *eo_e, Evas_Object *eo_obj, void *einfo);
static int evas_object_image_is_on_plane(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data);
static int evas_object_image_plane_changed(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data);
static const Evas_Object_Func object_func =
2002-11-08 00:02:15 -08:00
{
/* methods (compulsory) */
NULL,
evas_object_image_render,
evas_object_image_render_pre,
evas_object_image_render_post,
evas_object_image_engine_data_get,
/* these are optional. NULL = nothing */
NULL,
NULL,
evas_object_image_is_opaque,
evas_object_image_was_opaque,
evas_object_image_is_inside,
NULL,
NULL,
evas_object_image_has_opaque_rect,
evas_object_image_get_opaque_rect,
evas_object_image_can_map,
evas_object_image_render_prepare, // render_prepare
evas_object_image_is_on_plane,
evas_object_image_plane_changed
2002-11-08 00:02:15 -08:00
};
static const Evas_Object_Image_Load_Opts default_load_opts = {
0, 0.0, 0, 0, { 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, 0
};
static const Evas_Object_Image_Pixels default_pixels = {
NULL, { NULL, NULL }, NULL, { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, ~0x0
};
static const Evas_Object_Image_State default_state = {
{ 0, 0, 0, 0 }, // fill
{ 0, 0, 0 }, // image
{ 1.0, 0, 0, 0, 0, 1 }, // border
NULL, NULL, NULL, //source, defmap, scene
NULL, //f
NULL, //key
0, //frame
EVAS_COLORSPACE_ARGB8888,
EVAS_IMAGE_ORIENT_NONE,
EINA_TRUE, // smooth
EINA_FALSE, // has_alpha
EINA_FALSE, // opaque_valid
EINA_FALSE // opaque
};
Eina_Cow *evas_object_image_load_opts_cow = NULL;
Eina_Cow *evas_object_image_pixels_cow = NULL;
Eina_Cow *evas_object_image_state_cow = NULL;
static void
evas_object_image_render_prepare(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
{
#if 0
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
// if image data not loaded or in texture then upload
if ((o->cur->f) || (o->written) || (o->cur->frame != 0))
{
if (o->engine_data) ENFN->image_prepare(ENC, o->engine_data);
}
#endif
// XXX: if image is a proxy, PREPEND to prerender list in evas canvas
}
static void *
_evas_object_image_output_find(Evas_Object_Protected_Data *obj)
{
Efl_Canvas_Output *output;
Eina_List *l;
const Eina_Rectangle geometry = {
obj->cur->geometry.x,
obj->cur->geometry.y,
obj->cur->geometry.w,
obj->cur->geometry.h
};
EINA_LIST_FOREACH(obj->layer->evas->outputs, l, output)
{
if (eina_rectangles_intersect(&output->geometry, &geometry))
return output->output;
}
// Always return an output, as evas rely on that even if the object is out of screen.
output = eina_list_data_get(obj->layer->evas->outputs);
return output->output;
}
void
_evas_image_cleanup(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
/* Eina_Cow doesn't know if the resulting memory has changed, better check
before we change it */
if (o->cur->opaque_valid)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->opaque_valid = 0;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
2018-09-02 23:19:02 -07:00
if ((o->preload & EVAS_IMAGE_PRELOADING) && (o->engine_data))
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
}
if (o->cur->source) _evas_image_proxy_unset(eo_obj, obj, o);
if (o->cur->scene) _evas_image_3d_unset(eo_obj, obj, o);
}
static Eina_Bool
_init_cow(void)
{
if (!evas_object_image_load_opts_cow ||
!evas_object_image_pixels_cow ||
!evas_object_image_state_cow)
{
evas_object_image_load_opts_cow = eina_cow_add("Evas_Object_Image load opts",
sizeof (Evas_Object_Image_Load_Opts),
8,
&default_load_opts,
EINA_TRUE);
evas_object_image_pixels_cow = eina_cow_add("Evas_Object_Image pixels",
sizeof (Evas_Object_Image_Pixels),
8,
&default_pixels,
EINA_TRUE);
evas_object_image_state_cow = eina_cow_add("Evas_Object_Image states",
sizeof (Evas_Object_Image_State),
8,
&default_state,
EINA_TRUE);
}
if (!evas_object_image_load_opts_cow ||
!evas_object_image_pixels_cow ||
!evas_object_image_state_cow)
{
ERR("Failed to init cow.");
return EINA_FALSE;
}
return EINA_TRUE;
}
EOLIAN static Eo *
_efl_canvas_image_internal_efl_object_constructor(Eo *eo_obj, Evas_Image_Data *o)
2002-11-08 00:02:15 -08:00
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Colorspace cspace;
2002-11-08 00:02:15 -08:00
eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
evas_object_image_init(eo_obj);
if (!_init_cow())
return NULL;
o->load_opts = eina_cow_alloc(evas_object_image_load_opts_cow);
o->pixels = eina_cow_alloc(evas_object_image_pixels_cow);
o->cur = eina_cow_alloc(evas_object_image_state_cow);
o->prev = eina_cow_alloc(evas_object_image_state_cow);
o->proxy_src_clip = EINA_TRUE;
cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
if (cspace != o->cur->cspace)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->cspace = cspace;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
return eo_obj;
}
EOLIAN static Eo *
_efl_canvas_image_internal_efl_object_finalize(Eo *eo_obj, Evas_Image_Data *o)
{
if (!o->filled_set)
efl_gfx_fill_auto_set(eo_obj, EINA_TRUE);
return efl_finalize(efl_super(eo_obj, MY_CLASS));
}
void
_evas_image_init_set(const Eina_File *f, const char *key,
Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o,
Evas_Image_Load_Opts *lo)
{
if (o->cur->source) _evas_image_proxy_unset(eo_obj, obj, o);
if (o->cur->scene) _evas_image_3d_unset(eo_obj, obj, o);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
Eina_File *tmp = state_write->f;
state_write->f = NULL;
if (f) state_write->f = eina_file_dup(f);
eina_file_close(tmp);
eina_stringshare_replace(&state_write->key, key);
state_write->opaque_valid = 0;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
if (o->prev->f != NULL || o->prev->key != NULL)
{
2013-07-11 00:03:01 -07:00
EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
{
state_write->f = NULL;
state_write->key = NULL;
}
2013-07-11 00:03:01 -07:00
EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
}
2002-11-08 00:02:15 -08:00
if (o->engine_data)
{
2018-09-02 23:19:02 -07:00
if (o->preload & EVAS_IMAGE_PRELOADING)
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
}
ENFN->image_free(ENC, o->engine_data);
}
o->engine_data = NULL;
o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_NONE;
if (!lo) return;
lo->emile.scale_down_by = o->load_opts->scale_down_by;
lo->emile.dpi = o->load_opts->dpi;
lo->emile.w = o->load_opts->w;
lo->emile.h = o->load_opts->h;
lo->emile.region.x = o->load_opts->region.x;
lo->emile.region.y = o->load_opts->region.y;
lo->emile.region.w = o->load_opts->region.w;
lo->emile.region.h = o->load_opts->region.h;
lo->emile.scale_load.src_x = o->load_opts->scale_load.src_x;
lo->emile.scale_load.src_y = o->load_opts->scale_load.src_y;
lo->emile.scale_load.src_w = o->load_opts->scale_load.src_w;
lo->emile.scale_load.src_h = o->load_opts->scale_load.src_h;
lo->emile.scale_load.dst_w = o->load_opts->scale_load.dst_w;
lo->emile.scale_load.dst_h = o->load_opts->scale_load.dst_h;
lo->emile.scale_load.smooth = o->load_opts->scale_load.smooth;
lo->emile.scale_load.scale_hint = o->load_opts->scale_load.scale_hint;
lo->emile.orientation = o->load_opts->orientation;
lo->emile.degree = 0;
lo->skip_head = o->skip_head;
}
void
_evas_image_done_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
Eina_Bool resize_call = EINA_FALSE;
2002-11-08 00:02:15 -08:00
if (o->engine_data)
{
int w, h;
int stride;
Evas_Image_Orient orient;
ENFN->image_size_get(ENC, o->engine_data, &w, &h);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = w * 4;
orient = ENFN->image_orient_get(ENC, o->engine_data);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->has_alpha = ENFN->image_alpha_get(ENC, o->engine_data);
state_write->cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
if ((o->cur->image.w != w) || (o->cur->image.h != h))
resize_call = EINA_TRUE;
state_write->image.w = w;
state_write->image.h = h;
state_write->image.stride = stride;
state_write->orient = orient;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
2002-11-08 00:02:15 -08:00
}
else
{
if (o->load_error == EFL_GFX_IMAGE_LOAD_ERROR_NONE)
o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->has_alpha = EINA_TRUE;
state_write->cspace = EVAS_COLORSPACE_ARGB8888;
if ((state_write->image.w != 0) || (state_write->image.h != 0))
resize_call = EINA_TRUE;
state_write->image.w = 0;
state_write->image.h = 0;
state_write->image.stride = 0;
state_write->orient = EVAS_IMAGE_ORIENT_NONE;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
2002-11-08 00:02:15 -08:00
}
o->file_size.w = 0;
o->file_size.h = 0;
o->written = EINA_FALSE;
o->changed = EINA_TRUE;
if (resize_call) evas_object_inform_call_image_resize(eo_obj);
evas_object_change(eo_obj, obj);
2002-11-08 00:02:15 -08:00
}
void
_evas_image_orientation_set(Eo *eo_obj, Evas_Image_Data *o, Evas_Image_Orient orient)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
int iw, ih;
if (o->cur->orient == orient) return;
2018-09-02 23:19:02 -07:00
if ((o->preload & EVAS_IMAGE_PRELOADING) && (o->engine_data))
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_TRUE);
}
2015-09-20 19:05:58 -07:00
if (o->engine_data)
{
int stride = 0;
o->engine_data = ENFN->image_orient_set(ENC, o->engine_data, orient);
if (o->engine_data)
{
ENFN->image_size_get(ENC, o->engine_data, &iw, &ih);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = iw * 4;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->image.w = iw;
state_write->image.h = ih;
state_write->orient = orient;
state_write->image.stride = stride;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->written = EINA_TRUE;
}
}
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
}
static Evas_Image_Orient
_get_image_orient_from_orient_flip(Efl_Orient orient, Efl_Flip flip)
{
switch (orient)
{
case EFL_ORIENT_0:
if (flip == EFL_FLIP_HORIZONTAL)
return EVAS_IMAGE_FLIP_HORIZONTAL;
else if (flip == EFL_FLIP_VERTICAL)
return EVAS_IMAGE_FLIP_VERTICAL;
else
return EVAS_IMAGE_ORIENT_0;
case EFL_ORIENT_90:
if (flip == EFL_FLIP_HORIZONTAL)
return EVAS_IMAGE_FLIP_TRANSPOSE;
else if (flip == EFL_FLIP_VERTICAL)
return EVAS_IMAGE_FLIP_TRANSVERSE;
else
return EVAS_IMAGE_ORIENT_90;
case EFL_ORIENT_180:
if (flip == EFL_FLIP_HORIZONTAL)
return EVAS_IMAGE_FLIP_VERTICAL;
else if (flip == EFL_FLIP_VERTICAL)
return EVAS_IMAGE_FLIP_HORIZONTAL;
else
return EVAS_IMAGE_ORIENT_180;
case EFL_ORIENT_270:
if (flip == EFL_FLIP_HORIZONTAL)
return EVAS_IMAGE_FLIP_TRANSVERSE;
else if (flip == EFL_FLIP_VERTICAL)
return EVAS_IMAGE_FLIP_TRANSPOSE;
else
return EVAS_IMAGE_ORIENT_270;
default:
return EVAS_IMAGE_ORIENT_NONE;
}
}
EOLIAN static void
_efl_canvas_image_internal_efl_orientation_orientation_set(Eo *obj, Evas_Image_Data *o, Efl_Orient dir)
{
Evas_Image_Orient orient;
o->orient_value = dir;
orient = _get_image_orient_from_orient_flip(dir, o->flip_value);
_evas_image_orientation_set(obj, o, orient);
}
EOLIAN static Efl_Orient
_efl_canvas_image_internal_efl_orientation_orientation_get(const Eo *obj EINA_UNUSED, Evas_Image_Data *o)
{
return o->orient_value;
}
EOLIAN static void
_efl_canvas_image_internal_efl_orientation_flip_set(Eo *obj, Evas_Image_Data *o, Efl_Flip flip)
{
Evas_Image_Orient orient;
o->flip_value = flip;
orient = _get_image_orient_from_orient_flip(o->orient_value, flip);
_evas_image_orientation_set(obj, o, orient);
}
EOLIAN static Efl_Flip
_efl_canvas_image_internal_efl_orientation_flip_get(const Eo *obj EINA_UNUSED, Evas_Image_Data *o)
{
return o->flip_value;
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_object_dbg_info_get(Eo *eo_obj, Evas_Image_Data *o, Efl_Dbg_Info *root)
{
efl_dbg_info_get(efl_super(eo_obj, MY_CLASS), root);
Efl_Dbg_Info *group = EFL_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME);
const char *file, *key;
file = eina_file_filename_get(o->cur->f);
key = o->cur->key;
EFL_DBG_INFO_APPEND(group, "Image File", EINA_VALUE_TYPE_STRING, file);
EFL_DBG_INFO_APPEND(group, "Key", EINA_VALUE_TYPE_STRING, key);
EFL_DBG_INFO_APPEND(group, "Source", EINA_VALUE_TYPE_UINT64,
(uint64_t)(uintptr_t)evas_object_image_source_get(eo_obj));
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_set(Eo *eo_obj, Evas_Image_Data *o, int l, int r, int t, int b)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2002-11-08 00:02:15 -08:00
if (l < 0) l = 0;
if (r < 0) r = 0;
if (t < 0) t = 0;
if (b < 0) b = 0;
if ((o->cur->border.l == l) &&
(o->cur->border.r == r) &&
(o->cur->border.t == t) &&
(o->cur->border.b == b)) return;
evas_object_async_block(obj);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->border.l = l;
state_write->border.r = r;
state_write->border.t = t;
state_write->border.b = b;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, int *l, int *r, int *t, int *b)
{
if (l) *l = o->cur->border.l;
if (r) *r = o->cur->border.r;
if (t) *t = o->cur->border.t;
if (b) *b = o->cur->border.b;
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_center_fill_set(Eo *eo_obj, Evas_Image_Data *o, Efl_Gfx_Border_Fill_Mode _fill)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Border_Fill_Mode fill = (Evas_Border_Fill_Mode)_fill;
if (fill == o->cur->border.fill) return;
evas_object_async_block(obj);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->border.fill = fill;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
}
EOLIAN static Efl_Gfx_Border_Fill_Mode
_efl_canvas_image_internal_efl_gfx_image_border_center_fill_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
return (Efl_Gfx_Border_Fill_Mode)o->cur->border.fill;
}
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_fill_fill_auto_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool setting)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
setting = !!setting;
o->filled_set = 1;
if (o->filled == setting) return;
evas_object_async_block(obj);
o->filled = setting;
if (!o->filled)
evas_object_event_callback_del(eo_obj, EVAS_CALLBACK_RESIZE,
evas_object_image_filled_resize_listener);
else
{
Eina_Size2D sz;
sz = efl_gfx_entity_size_get(eo_obj);
_evas_image_fill_set(eo_obj, o, 0, 0, sz.w, sz.h);
evas_object_event_callback_add(eo_obj, EVAS_CALLBACK_RESIZE,
evas_object_image_filled_resize_listener,
NULL);
}
}
2014-03-12 07:28:40 -07:00
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_gfx_fill_fill_auto_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
2014-03-12 07:28:40 -07:00
return o->filled;
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_scale_set(Eo *eo_obj, Evas_Image_Data *o, double scale)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
if (EINA_DBL_EQ(scale, o->cur->border.scale)) return;
evas_object_async_block(obj);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->border.scale = scale;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
}
2014-03-12 07:28:40 -07:00
EOLIAN static double
_efl_canvas_image_internal_efl_gfx_image_border_scale_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
2014-03-12 07:28:40 -07:00
return o->cur->border.scale;
}
void
_evas_image_fill_set(Eo *eo_obj, Evas_Image_Data *o, int x, int y, int w, int h)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2005-05-21 19:49:50 -07:00
if (w == 0) return;
if (h == 0) return;
if (w < 0) w = -w;
if (h < 0) h = -h;
if ((o->cur->fill.x == x) &&
(o->cur->fill.y == y) &&
(o->cur->fill.w == w) &&
(o->cur->fill.h == h)) return;
evas_object_async_block(obj);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->fill.x = x;
state_write->fill.y = y;
state_write->fill.w = w;
state_write->fill.h = h;
state_write->opaque_valid = 0;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
2002-11-08 00:02:15 -08:00
}
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_fill_fill_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Rect fill)
{
// Should (0,0,0,0) reset the filled flag to true?
o->filled = EINA_FALSE;
o->filled_set = EINA_TRUE;
_evas_image_fill_set(eo_obj, o, fill.x, fill.y, fill.w, fill.h);
}
EOLIAN static Eina_Rect
_efl_canvas_image_internal_efl_gfx_fill_fill_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
2002-11-08 00:02:15 -08:00
{
return (Eina_Rect) o->cur->fill;
2002-11-08 00:02:15 -08:00
}
EOLIAN static Eina_Size2D
_efl_canvas_image_internal_efl_gfx_image_image_size_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
2017-09-18 04:49:56 -07:00
return EINA_SIZE2D(o->file_size.w, o->file_size.h);
}
2017-09-18 04:16:33 -07:00
EOLIAN static Eina_Size2D
_efl_canvas_image_internal_efl_gfx_view_view_size_get(const Eo *eo_obj, Evas_Image_Data *o)
{
int uvw, uvh;
Evas_Object_Protected_Data *source = NULL;
Evas_Object_Protected_Data *obj;
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
if (o->cur->source)
source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
if (o->cur->scene)
{
uvw = obj->data_3d->w;
uvh = obj->data_3d->h;
}
else if (!o->cur->source)
{
uvw = o->cur->image.w;
uvh = o->cur->image.h;
}
else if (source->proxy->surface && !source->proxy->redraw)
{
uvw = source->proxy->w;
uvh = source->proxy->h;
}
else if (source->type == o_type &&
((Evas_Image_Data *)efl_data_scope_get(o->cur->source, MY_CLASS))->engine_data)
{
uvw = source->cur->geometry.w;
uvh = source->cur->geometry.h;
}
else
{
uvw = source->proxy->w;
uvh = source->proxy->h;
}
2017-09-18 04:16:33 -07:00
return EINA_SIZE2D(uvw, uvh);
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_buffer_buffer_update_add(Eo *eo_obj, Evas_Image_Data *o, const Eina_Rect *region)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Eina_Rectangle *r;
Eo *eo_obj2;
Eina_List *l;
int x, y, w, h;
int cnt;
if (region)
{
x = region->x;
y = region->y;
w = region->w;
h = region->h;
}
else
{
x = y = 0;
w = o->cur->image.w;
h = o->cur->image.h;
}
RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, o->cur->image.w, o->cur->image.h);
if ((w <= 0) || (h <= 0)) return;
if (obj->cur->snapshot)
{
obj->snapshot_no_obscure = EINA_TRUE;
evas_object_change(eo_obj, obj);
return;
}
if (!o->written) return;
evas_object_async_block(obj);
cnt = eina_list_count(o->pixels->pixel_updates);
if (cnt == 1) // detect single blob case already there to do a nop
{
if ((r = o->pixels->pixel_updates->data)) // already a single full rect there.
{
if ((r->x == 0) && (r->y == 0) && (r->w == o->cur->image.w) && (r->h == o->cur->image.h))
return;
}
}
if ((cnt >= 512) ||
(((x == 0) && (y == 0) && (w == o->cur->image.w) && (h == o->cur->image.h)))) // too many update rects - just make a single blob update
{
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, r)
eina_rectangle_free(r);
NEW_RECT(r, 0, 0, o->cur->image.w, o->cur->image.h);
if (r) pixi_write->pixel_updates = eina_list_append(pixi_write->pixel_updates, r);
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
else
{
NEW_RECT(r, x, y, w, h);
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
if (r) pixi_write->pixel_updates = eina_list_append(pixi_write->pixel_updates, r);
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
EINA_LIST_FOREACH(obj->proxy->proxies, l, eo_obj2)
{
Evas_Object_Protected_Data *obj2 = efl_data_scope_get(eo_obj2, EFL_CANVAS_OBJECT_CLASS);
evas_object_change(eo_obj2, obj2);
}
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_buffer_alpha_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool has_alpha)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
evas_object_async_block(obj);
2018-09-02 23:19:02 -07:00
if ((o->preload & EVAS_IMAGE_PRELOADING) && (o->engine_data))
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_TRUE);
}
has_alpha = !!has_alpha;
if (has_alpha == o->cur->has_alpha)
2002-11-08 00:02:15 -08:00
return;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->has_alpha = has_alpha;
state_write->opaque_valid = 0;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
2002-11-08 00:02:15 -08:00
if (o->engine_data)
{
int stride = 0;
o->engine_data = ENFN->image_alpha_set(ENC, o->engine_data, o->cur->has_alpha);
if (ENFN->image_scale_hint_set)
ENFN->image_scale_hint_set(ENC, o->engine_data, o->scale_hint);
if (ENFN->image_content_hint_set)
ENFN->image_content_hint_set(ENC, o->engine_data, o->content_hint);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = o->cur->image.w * 4;
if (o->cur->image.stride != stride)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->image.stride = stride;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
o->written = EINA_TRUE;
}
efl_gfx_buffer_update_add(eo_obj, NULL);
EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_gfx_buffer_alpha_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
return o->cur->has_alpha;
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_smooth_scale_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool smooth_scale)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if (((smooth_scale) && (o->cur->smooth_scale)) ||
((!smooth_scale) && (!o->cur->smooth_scale)))
2002-11-08 00:02:15 -08:00
return;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->smooth_scale = smooth_scale;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->changed = EINA_TRUE;
evas_object_change(eo_obj, obj);
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_gfx_image_smooth_scale_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
return o->cur->smooth_scale;
}
2005-05-21 19:49:50 -07:00
EOLIAN static double
_efl_canvas_image_internal_efl_gfx_image_ratio_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
if (!o->cur->image.h) return 1.0;
return (double)o->cur->image.w / (double)o->cur->image.h;
}
EOLIAN static Eina_Error
_efl_canvas_image_internal_efl_gfx_image_image_load_error_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
return o->load_error;
}
2014-03-12 07:28:40 -07:00
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_file_save_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file, const char *key, const Efl_File_Save_Info *info)
{
int quality = 80, compress = 9, ok = 0;
const char *encoding = NULL;
Image_Entry *ie;
Evas_Colorspace cspace = EVAS_COLORSPACE_ARGB8888;
Evas_Colorspace want_cspace = EVAS_COLORSPACE_ARGB8888;
Evas_Object_Protected_Data *obj;
Eina_Bool unmap_it = EINA_FALSE;
Eina_Bool tofree = EINA_FALSE;
int imagew, imageh, uvw, uvh;
Eina_Rw_Slice slice = {};
DATA32 *data = NULL;
void *pixels;
void *output;
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
evas_object_async_block(obj);
output = _evas_object_image_output_find(obj);
pixels = _evas_image_pixels_get((Eo *)eo_obj, obj, ENC, output, NULL, NULL,
0, 0,
&imagew, &imageh, &uvw, &uvh, EINA_TRUE, EINA_TRUE);
if (!pixels) goto no_pixels;
cspace = ENFN->image_file_colorspace_get(ENC, pixels);
want_cspace = cspace;
if (info)
{
encoding = info->encoding;
quality = info->quality;
compress = info->compression;
}
if (encoding)
{
const char *ext = strrchr(file, '.');
if (ext && !strcasecmp(ext, ".tgv"))
{
if (!strcmp(encoding, "auto"))
want_cspace = cspace;
else if (!strcmp(encoding, "etc1"))
want_cspace = EVAS_COLORSPACE_ETC1;
else if (!strcmp(encoding, "etc2"))
{
if (!ENFN->image_alpha_get(ENC, pixels))
want_cspace = EVAS_COLORSPACE_RGB8_ETC2;
else
want_cspace = EVAS_COLORSPACE_RGBA8_ETC2_EAC;
}
else if (!strcmp(encoding, "etc1+alpha"))
want_cspace = EVAS_COLORSPACE_ETC1_ALPHA;
}
}
if (ENFN->image_data_direct_get && (o->cur->orient == EVAS_IMAGE_ORIENT_NONE))
{
Evas_Colorspace cs;
Eina_Slice sl;
ok = ENFN->image_data_direct_get(ENC, pixels, 0, &sl, &cs, EINA_TRUE, &tofree);
if (ok && (cs == want_cspace))
data = (DATA32 *)sl.mem;
}
if (!data)
{
int stride;
cspace = EVAS_COLORSPACE_ARGB8888;
ok = ENFN->image_data_map(ENC, &pixels, &slice, &stride, 0, 0, imagew, imageh,
cspace, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0);
if (!ok || !slice.mem) goto no_pixels;
unmap_it = EINA_TRUE;
data = slice.mem;
if (stride != (imagew * 4))
WRN("Invalid stride: saved image may look wrong!");
}
ie = evas_cache_image_data(evas_common_image_cache_get(),
imagew, imageh, data, o->cur->has_alpha, cspace);
if (ie)
{
RGBA_Image *im = (RGBA_Image *)ie;
ok = evas_common_save_image_to_file(im, file, key, quality, compress, encoding);
evas_cache_image_drop(ie);
}
else ok = EINA_FALSE;
if (unmap_it)
ENFN->image_data_unmap(ENC, pixels, &slice);
if (tofree) free(data);
if (!ok) ERR("Image save failed.");
2014-03-12 07:28:40 -07:00
return ok;
no_pixels:
ERR("Could not get image pixels for saving.");
return EINA_FALSE;
}
EOLIAN static Efl_Gfx_Colorspace
_efl_canvas_image_internal_efl_gfx_buffer_colorspace_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
return (Efl_Gfx_Colorspace)o->cur->cspace;
}
static void
_on_image_native_surface_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *einfo EINA_UNUSED)
{
evas_object_image_native_surface_set(obj, NULL);
}
Eina_Bool
_evas_image_native_surface_set(Eo *eo_obj, Evas_Native_Surface *surf)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
evas_object_async_block(obj);
evas_object_event_callback_del_full
(eo_obj, EVAS_CALLBACK_DEL, _on_image_native_surface_del, NULL);
if (surf) // We need to unset native surf on del to remove shared hash refs
evas_object_event_callback_add
(eo_obj, EVAS_CALLBACK_DEL, _on_image_native_surface_del, NULL);
o->can_scanout = EINA_FALSE;
evas_render_rendering_wait(obj->layer->evas);
_evas_image_cleanup(eo_obj, obj, o);
if (!ENFN->image_native_set) return EINA_FALSE;
if ((surf) &&
((surf->version < 2) ||
(surf->version > EVAS_NATIVE_SURFACE_VERSION))) return EINA_FALSE;
o->engine_data = ENFN->image_native_set(ENC, o->engine_data, surf);
if (surf && surf->version > 4)
{
switch (surf->type)
{
case EVAS_NATIVE_SURFACE_WL_DMABUF:
if (surf->data.wl_dmabuf.scanout.handler)
o->can_scanout = EINA_TRUE;
break;
default:
break;
}
}
return o->engine_data != NULL;
}
Evas_Native_Surface *
_evas_image_native_surface_get(const Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
Evas_Native_Surface *surf = NULL;
if (ENFN->image_native_get)
surf = ENFN->image_native_get(ENC, o->engine_data);
2014-03-12 07:28:40 -07:00
return surf;
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_scale_hint_set(Eo *eo_obj, Evas_Image_Data *o, Efl_Gfx_Image_Scale_Hint hint)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if (o->scale_hint == hint) return;
o->scale_hint = hint;
if (o->engine_data)
{
int stride = 0;
if (ENFN->image_scale_hint_set)
ENFN->image_scale_hint_set(ENC, o->engine_data, o->scale_hint);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = o->cur->image.w * 4;
if (o->cur->image.stride != stride)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->image.stride = stride;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
}
}
EOLIAN static Efl_Gfx_Image_Scale_Hint
_efl_canvas_image_internal_efl_gfx_image_scale_hint_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
return o->scale_hint;
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_content_hint_set(Eo *eo_obj, Evas_Image_Data *o, Efl_Gfx_Image_Content_Hint hint)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if (o->content_hint == hint) return;
o->content_hint = hint;
if (o->engine_data)
{
int stride = 0;
if (ENFN->image_content_hint_set)
ENFN->image_content_hint_set(ENC, o->engine_data, o->content_hint);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = o->cur->image.w * 4;
if (o->cur->image.stride != stride)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->image.stride = stride;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
}
}
EOLIAN static Efl_Gfx_Image_Content_Hint
_efl_canvas_image_internal_efl_gfx_image_content_hint_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
{
2014-03-12 07:28:40 -07:00
return o->content_hint;
}
void
_evas_image_unload(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool dirty)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o;
Eina_Bool resize_call = EINA_FALSE;
o = efl_data_scope_get(eo_obj, MY_CLASS);
if ((!o->cur->f) ||
(o->pixels_checked_out > 0)) return;
evas_object_async_block(obj);
if (dirty)
{
if (o->engine_data)
o->engine_data = ENFN->image_dirty_region(ENC, o->engine_data,
0, 0,
o->cur->image.w, o->cur->image.h);
}
2002-11-08 00:02:15 -08:00
if (o->engine_data)
{
2018-09-02 23:19:02 -07:00
if (o->preload & EVAS_IMAGE_PRELOADING)
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
}
ENFN->image_free(ENC, o->engine_data);
}
2005-05-21 19:49:50 -07:00
o->engine_data = NULL;
o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_NONE;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->has_alpha = EINA_TRUE;
state_write->cspace = EVAS_COLORSPACE_ARGB8888;
if ((state_write->image.w != 0) || (state_write->image.h != 0)) resize_call = EINA_TRUE;
state_write->image.w = 0;
state_write->image.h = 0;
state_write->image.stride = 0;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
if (resize_call) evas_object_inform_call_image_resize(eo_obj);
2002-11-08 00:02:15 -08:00
}
void
_evas_image_load(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
2002-11-08 00:02:15 -08:00
{
Evas_Image_Load_Opts lo;
int load_error = 0;
2005-05-21 19:49:50 -07:00
2004-09-22 18:58:50 -07:00
if (o->engine_data) return;
2005-05-21 19:49:50 -07:00
lo.emile.scale_down_by = o->load_opts->scale_down_by;
lo.emile.dpi = o->load_opts->dpi;
lo.emile.w = o->load_opts->w;
lo.emile.h = o->load_opts->h;
lo.emile.region.x = o->load_opts->region.x;
lo.emile.region.y = o->load_opts->region.y;
lo.emile.region.w = o->load_opts->region.w;
lo.emile.region.h = o->load_opts->region.h;
lo.emile.scale_load.src_x = o->load_opts->scale_load.src_x;
lo.emile.scale_load.src_y = o->load_opts->scale_load.src_y;
lo.emile.scale_load.src_w = o->load_opts->scale_load.src_w;
lo.emile.scale_load.src_h = o->load_opts->scale_load.src_h;
lo.emile.scale_load.dst_w = o->load_opts->scale_load.dst_w;
lo.emile.scale_load.dst_h = o->load_opts->scale_load.dst_h;
lo.emile.scale_load.smooth = o->load_opts->scale_load.smooth;
lo.emile.scale_load.scale_hint = o->load_opts->scale_load.scale_hint;
lo.emile.orientation = o->load_opts->orientation;
lo.emile.degree = 0;
lo.skip_head = o->skip_head;
o->engine_data = ENFN->image_mmap(ENC, o->cur->f, o->cur->key, &load_error, &lo);
o->load_error = _evas_load_error_to_efl_gfx_image_load_error(load_error);
2013-07-11 00:03:01 -07:00
if (o->engine_data)
{
int w, h;
int stride = 0;
Eina_Bool resize_call = EINA_FALSE;
ENFN->image_size_get(ENC, o->engine_data, &w, &h);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = w * 4;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->has_alpha = ENFN->image_alpha_get(ENC, o->engine_data);
state_write->cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
if ((state_write->image.w != w) || (state_write->image.h != h))
resize_call = EINA_TRUE;
state_write->image.w = w;
state_write->image.h = h;
state_write->image.stride = stride;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
if (resize_call) evas_object_inform_call_image_resize(eo_obj);
}
else
{
o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
}
}
void
_evas_image_load_post_update(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
2002-11-08 00:02:15 -08:00
if (o->engine_data)
{
int w, h;
int stride = 0;
Eina_Bool resize_call = EINA_FALSE;
2005-05-21 19:49:50 -07:00
ENFN->image_size_get(ENC, o->engine_data, &w, &h);
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENC, o->engine_data, &stride);
else
stride = w * 4;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->has_alpha = ENFN->image_alpha_get(ENC, o->engine_data);
state_write->cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
if ((state_write->image.w != w) || (state_write->image.h != h))
resize_call = EINA_TRUE;
state_write->image.w = w;
state_write->image.h = h;
state_write->image.stride = stride;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
o->changed = EINA_TRUE;
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOADED;
if (resize_call) evas_object_inform_call_image_resize(eo_obj);
evas_object_change(eo_obj, obj);
2018-09-02 23:19:02 -07:00
//preloading error check
if (ENFN->image_load_error_get)
o->load_error = _evas_load_error_to_efl_gfx_image_load_error(ENFN->image_load_error_get(ENC, o->engine_data));
2002-11-08 00:02:15 -08:00
}
else
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
2002-11-08 00:02:15 -08:00
}
}
static Evas_Coord
evas_object_image_figure_x_fill(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret)
{
Evas_Coord w;
w = ((size * obj->layer->evas->output.w) /
(Evas_Coord)obj->layer->evas->viewport.w);
if (size <= 0) size = 1;
if (start > 0)
{
while (start - size > 0)
start -= size;
}
else if (start < 0)
{
while (start < 0)
start += size;
}
start = ((start * obj->layer->evas->output.w) /
(Evas_Coord)obj->layer->evas->viewport.w);
*size_ret = w;
return start;
}
static Evas_Coord
evas_object_image_figure_y_fill(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret)
{
Evas_Coord h;
h = ((size * obj->layer->evas->output.h) /
(Evas_Coord)obj->layer->evas->viewport.h);
if (size <= 0) size = 1;
if (start > 0)
{
while (start - size > 0)
start -= size;
}
else if (start < 0)
{
while (start < 0)
start += size;
}
start = ((start * obj->layer->evas->output.h) /
(Evas_Coord)obj->layer->evas->viewport.h);
*size_ret = h;
return start;
}
2002-11-08 00:02:15 -08:00
static void
evas_object_image_init(Evas_Object *eo_obj)
2002-11-08 00:02:15 -08:00
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2002-11-08 00:02:15 -08:00
/* set up methods (compulsory) */
obj->func = &object_func;
obj->private_data = efl_data_ref(eo_obj, MY_CLASS);
2002-11-08 00:02:15 -08:00
obj->type = o_type;
obj->is_image_object = EINA_TRUE;
2002-11-08 00:02:15 -08:00
}
2014-03-12 07:28:40 -07:00
EOLIAN static void
_efl_canvas_image_internal_efl_object_destructor(Eo *eo_obj, Evas_Image_Data *o EINA_UNUSED)
2002-11-08 00:02:15 -08:00
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
if (obj->legacy.ctor)
evas_object_image_video_surface_set(eo_obj, NULL);
evas_object_image_free(eo_obj, obj);
efl_destructor(efl_super(eo_obj, MY_CLASS));
}
void
_evas_object_image_free(Evas_Object *obj)
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o;
EINA_SAFETY_ON_FALSE_RETURN(efl_isa(obj, MY_CLASS));
o = efl_data_scope_get(obj, MY_CLASS);
// eina_cow_free reset the pointer to the default read only state
eina_cow_free(evas_object_image_load_opts_cow, (const Eina_Cow_Data **)&o->load_opts);
eina_cow_free(evas_object_image_pixels_cow, (const Eina_Cow_Data **)&o->pixels);
eina_cow_free(evas_object_image_state_cow, (const Eina_Cow_Data **)&o->cur);
eina_cow_free(evas_object_image_state_cow, (const Eina_Cow_Data **)&o->prev);
}
static void
evas_object_image_free(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
Eina_Rectangle *r;
2002-11-08 00:02:15 -08:00
/* free obj */
eina_file_close(o->cur->f);
if (o->cur->key) eina_stringshare_del(o->cur->key);
if (o->cur->source) _evas_image_proxy_unset(eo_obj, obj, o);
if (o->cur->scene) _evas_image_3d_unset(eo_obj, obj, o);
if (obj->layer && obj->layer->evas)
{
if (o->engine_data && ENC)
{
2018-09-02 23:19:02 -07:00
if (o->preload & EVAS_IMAGE_PRELOADING)
{
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
}
ENFN->image_free(ENC, o->engine_data);
}
if (o->engine_data_prep && ENC)
{
ENFN->image_free(ENC, o->engine_data_prep);
}
if (o->video_surface)
{
o->video_surface = EINA_FALSE;
obj->layer->evas->video_objects = eina_list_remove(obj->layer->evas->video_objects, eo_obj);
}
}
o->engine_data = NULL;
o->engine_data_prep = NULL;
if (o->pixels->images_to_free)
{
eina_hash_free(o->pixels->images_to_free);
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
pixi_write->images_to_free = NULL;
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
if (o->pixels->pixel_updates)
{
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, r)
eina_rectangle_free(r);
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
2002-11-08 00:02:15 -08:00
}
static void
_draw_image(Evas_Object_Protected_Data *obj,
void *engine, void *data, void *context, void *surface, void *image,
int src_x, int src_y, int src_w, int src_h, int dst_x,
int dst_y, int dst_w, int dst_h, int smooth,
Eina_Bool do_async)
{
Eina_Bool async_unref;
async_unref = ENFN->image_draw(engine, data, context, surface,
image, src_x, src_y,
src_w, src_h, dst_x,
dst_y, dst_w, dst_h,
smooth, do_async);
if (do_async && async_unref)
{
evas_cache_image_ref((Image_Entry *)image);
evas_unref_queue_image_put(obj->layer->evas, image);
}
}
void
evas_draw_image_map_async_check(Evas_Object_Protected_Data *obj,
void *engine, void *data, void *context, void *surface,
void *image, RGBA_Map *m, int smooth, int level,
Eina_Bool do_async)
{
Eina_Bool async_unref;
obj->layer->evas->engine.func->context_anti_alias_set(engine, context,
obj->cur->anti_alias);
async_unref = ENFN->image_map_draw(engine, data, context,
surface, image, m,
smooth, level,
do_async);
if (do_async && async_unref)
{
evas_cache_image_ref((Image_Entry *)image);
evas_unref_queue_image_put(obj->layer->evas, image);
}
}
void
evas_object_pixels_get_force(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
{
Evas_Image_Data *o = obj->private_data;
o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, eo_obj);
}
static void *
2014-03-12 07:28:40 -07:00
evas_process_dirty_pixels(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o,
void *engine, void *output, void *surface, void *pixels)
{
Eina_Bool direct_override = EINA_FALSE, direct_force_off = EINA_FALSE;
if (o->dirty_pixels)
{
if (o->pixels->func.get_pixels)
{
Evas_Coord x, y, w, h;
if (ENFN->image_native_get)
{
Evas_Native_Surface *ns;
ns = ENFN->image_native_get(engine, o->engine_data);
if (ns)
{
Eina_Bool direct_renderable = EINA_FALSE;
// Check if we can do direct rendering...
if (ENFN->gl_direct_override_get)
ENFN->gl_direct_override_get(engine, &direct_override, &direct_force_off);
if (ENFN->gl_surface_direct_renderable_get)
direct_renderable = ENFN->gl_surface_direct_renderable_get(engine, output, ns, &direct_override, surface);
if (((direct_override) ||
((direct_renderable) &&
(obj->cur->geometry.w == o->cur->image.w) &&
(obj->cur->geometry.h == o->cur->image.h) &&
(obj->cur->color.r == 255) &&
(obj->cur->color.g == 255) &&
(obj->cur->color.b == 255) &&
(obj->cur->color.a == 255) &&
(obj->cur->cache.clip.r == 255) &&
(obj->cur->cache.clip.g == 255) &&
(obj->cur->cache.clip.b == 255) &&
(obj->cur->cache.clip.a == 255) &&
(!obj->map->cur.map))
) && (!direct_force_off))
{
if (ENFN->gl_get_pixels_set)
ENFN->gl_get_pixels_set(engine, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj);
if (ENFN->gl_image_direct_set)
ENFN->gl_image_direct_set(engine, o->engine_data, EINA_TRUE);
o->direct_render = EINA_TRUE;
}
else
o->direct_render = EINA_FALSE;
}
if ((ns) &&
(ns->type == EVAS_NATIVE_SURFACE_X11))
{
if (ENFN->context_flush)
ENFN->context_flush(engine);
}
}
x = obj->cur->geometry.x;
y = obj->cur->geometry.y;
w = obj->cur->geometry.w;
h = obj->cur->geometry.h;
if (!o->direct_render)
{
if (ENFN->gl_get_pixels_pre)
ENFN->gl_get_pixels_pre(engine, output);
o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, eo_obj);
if (ENFN->gl_get_pixels_post)
ENFN->gl_get_pixels_post(engine, output);
}
if (!(obj->cur->geometry.x == x &&
obj->cur->geometry.y == y &&
obj->cur->geometry.w == w &&
obj->cur->geometry.h == h))
2014-03-12 07:28:40 -07:00
CRI("Evas_Image_Data geometry did change during pixels get callback !");
o->engine_data = ENFN->image_dirty_region
(engine, o->engine_data,
0, 0, o->cur->image.w, o->cur->image.h);
if (o->engine_data != pixels)
pixels = o->engine_data;
}
o->dirty_pixels = EINA_FALSE;
}
else
{
// Check if the it's not dirty but it has direct rendering
if (o->direct_render && ENFN->image_native_get)
{
Evas_Native_Surface *ns;
ns = ENFN->image_native_get(engine, o->engine_data);
if (ENFN->gl_direct_override_get)
ENFN->gl_direct_override_get(engine, &direct_override, &direct_force_off);
if (ENFN->gl_surface_direct_renderable_get)
ENFN->gl_surface_direct_renderable_get(engine, output, ns, &direct_override, surface);
if (direct_override && !direct_force_off)
{
// always use direct rendering
if (ENFN->gl_get_pixels_set)
ENFN->gl_get_pixels_set(engine, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj);
if (ENFN->gl_image_direct_set)
ENFN->gl_image_direct_set(engine, o->engine_data, EINA_TRUE);
}
else
{
// Auto-fallback to FBO rendering (for perf & power consumption)
if (ENFN->gl_get_pixels_pre)
ENFN->gl_get_pixels_pre(engine, output);
o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, obj->object);
if (ENFN->gl_get_pixels_post)
ENFN->gl_get_pixels_post(engine, output);
o->direct_render = EINA_FALSE;
}
}
}
return pixels;
}
EOLIAN static void
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_dirty(Eo *eo_obj, Evas_Image_Data *o)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
o->changed = 1;
evas_object_change(eo_obj, obj);
}
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_alpha(
Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o EINA_UNUSED)
{
return EINA_FALSE;
}
EOLIAN static void
_efl_canvas_image_internal_efl_gfx_filter_filter_program_set(Eo *obj, Evas_Image_Data *pd,
const char *code, const char *name)
{
pd->has_filter = (code != NULL);
efl_gfx_filter_program_set(efl_super(obj, MY_CLASS), code, name);
}
EOLIAN static void
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_state_prepare(
Eo *eo_obj, Evas_Image_Data *o EINA_UNUSED, Efl_Canvas_Filter_State *state, void *data EINA_UNUSED)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
memset(&state->text, 0, sizeof(state->text));
#define STATE_COLOR(dst, src) dst.r = src.r; dst.g = src.g; dst.b = src.b; dst.a = src.a
STATE_COLOR(state->color, obj->cur->color);
#undef STATE_COLOR
state->w = obj->cur->geometry.w;
state->h = obj->cur->geometry.h;
state->scale = obj->cur->scale;
}
static inline Eina_Bool
_image_has_border(Evas_Object_Protected_Data *obj EINA_UNUSED, Evas_Image_Data *o)
{
return o->cur->border.l || o->cur->border.r || o->cur->border.t ||
o->cur->border.b || (o->cur->border.fill == 0);
}
static inline Eina_Bool
_image_is_filled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
if (o->filled) return EINA_TRUE;
return !o->cur->fill.x && !o->cur->fill.y &&
(o->cur->fill.w == obj->cur->geometry.w) &&
(o->cur->fill.h == obj->cur->geometry.h);
}
static inline Eina_Bool
_image_is_scaled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
return (obj->cur->geometry.w != o->cur->image.w) ||
(obj->cur->geometry.h != o->cur->image.h);
}
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
Eo *eo_obj, Evas_Image_Data *o,
void *_filter, void *engine, void *output, void *context, void *data EINA_UNUSED,
int l, int r EINA_UNUSED, int t, int b EINA_UNUSED,
int x, int y, Eina_Bool do_async)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Filter_Context *filter = _filter;
void *surface, *ctx;
Eina_Bool ok;
int W, H;
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
// FIXME: In GL we could use the image even if scaled
if (!_image_has_border(obj, o) && _image_is_filled(obj, o) && !_image_is_scaled(obj, o))
{
int imagew, imageh, uvw, uvh;
surface = _evas_image_pixels_get(eo_obj, obj, engine, output, context, NULL, x, y,
&imagew, &imageh, &uvw, &uvh, EINA_FALSE, EINA_FALSE);
ok = evas_filter_buffer_backing_set(filter, EVAS_FILTER_BUFFER_INPUT_ID, surface);
if (ok) return EINA_TRUE;
}
surface = evas_filter_buffer_backing_get(filter, EVAS_FILTER_BUFFER_INPUT_ID, EINA_TRUE);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
if (!o->filled)
{
l = 0;
t = 0;
r = 0;
b = 0;
}
ctx = ENFN->context_new(engine);
if (o->cur->has_alpha && !obj->cur->snapshot)
{
ENFN->context_color_set(engine, ctx, 0, 0, 0, 0);
ENFN->context_render_op_set(engine, ctx, EVAS_RENDER_COPY);
ENFN->rectangle_draw(engine, output, ctx, surface, 0, 0, W, H, do_async);
ENFN->context_color_set(engine, ctx, 255, 255, 255, 255);
ENFN->context_render_op_set(engine, ctx, EVAS_RENDER_BLEND);
}
_evas_image_render(eo_obj, obj,
engine, output, ctx, surface,
x + l - obj->cur->geometry.x,
y + t - obj->cur->geometry.y,
l, t, r, b, EINA_TRUE, do_async);
ENFN->context_free(engine, ctx);
ENFN->image_free(engine, surface);
return EINA_TRUE;
}
void
_evas_object_image_plane_release(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
Efl_Canvas_Output *output)
{
Evas_Image_Data *o;
if (!obj) return;
o = obj->private_data;
if (!o->engine_data) return;
if (!o->plane) return;
ENFN->image_plane_release(output->output, o->engine_data, o->plane);
output->planes = eina_list_remove(output->planes, obj);
o->plane = NULL;
}
Eina_Bool
_evas_object_image_can_use_plane(Evas_Object_Protected_Data *obj,
Efl_Canvas_Output *output)
{
Evas_Native_Surface *ns;
Evas_Image_Data *o = obj->private_data;
/* Let the video surface code handle this one... */
if (o->video_surface)
return EINA_TRUE;
if (!o->can_scanout)
return EINA_FALSE;
if (!o->engine_data)
return EINA_FALSE;
if (!ENFN->image_plane_assign)
return EINA_FALSE;
if (!ENFN->image_native_get)
return EINA_FALSE;
ns = ENFN->image_native_get(ENC, o->engine_data);
if (!ns) return EINA_FALSE;
// FIXME: adjust position with output offset.
o->plane = ENFN->image_plane_assign(output->output, o->engine_data,
obj->cur->geometry.x,
obj->cur->geometry.y);
if (!o->plane)
return EINA_FALSE;
output->planes = eina_list_append(output->planes, obj);
return EINA_TRUE;
}
static int
evas_object_image_is_on_plane(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data)
{
Evas_Image_Data *o = type_private_data;
if (o->plane) return 1;
return 0;
}
static int
evas_object_image_plane_changed(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data)
{
Evas_Image_Data *o = type_private_data;
if (!!o->plane != o->plane_status)
{
o->plane_status = !!o->plane;
return 1;
}
return 0;
}
2002-11-08 00:02:15 -08:00
static void
evas_object_image_render(Evas_Object *eo_obj, 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)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
2002-11-08 00:02:15 -08:00
/* image is not ready yet, skip rendering. Leave it to next frame */
2018-09-02 23:19:02 -07:00
if (o->preload == EVAS_IMAGE_PRELOADING) return;
if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1))
return; /* no error message, already printed in pre_render */
/* Proxy sanity */
if (o->proxyrendering)
{
_evas_image_proxy_error(eo_obj, engine, output, context, surface, x, y, EINA_FALSE);
return;
}
/* Mask sanity */
if (obj->mask->is_mask && (surface != obj->mask->surface))
{
ERR("Drawing a mask to another surface? Something's wrong...");
return;
}
if (o->engine_data_prep)
{
ENFN->context_multiplier_unset(engine, context);
ENFN->context_render_op_set(engine, context, obj->cur->render_op);
ENFN->image_draw(engine, output, context, surface, o->engine_data_prep,
0, 0, obj->cur->geometry.w, obj->cur->geometry.h,
obj->cur->geometry.x + x, obj->cur->geometry.y + y,
obj->cur->geometry.w, obj->cur->geometry.h,
0, do_async);
return;
}
if (o->plane)
{
/* We must call pixels get because enlightenment uses it for internal
* bookkeeping and won't send frame callbacks to wayland clients if we
* don't
*/
evas_object_pixels_get_force(eo_obj, obj);
#if 0
Evas_Native_Surface *ns;
/* Draw a bright red rectangle where the object replaced by
* a hardware plane would have been.
*/
ns = ENFN->image_native_get(ENC, o->engine_data);
if (ns && ns->type == EVAS_NATIVE_SURFACE_WL_DMABUF)
{
ENFN->context_color_set(output, context, 255, 0, 0, 255);
ENFN->context_multiplier_unset(output, context);
ENFN->context_render_op_set(output, context, EVAS_RENDER_COPY);
ENFN->rectangle_draw(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
return;
}
/* We are displaying the overlay */
if (o->video_visible)
{
/* Create a transparent rectangle */
ENFN->context_color_set(engine, context, 0, 0, 0, 0);
ENFN->context_multiplier_unset(engine, context);
ENFN->context_render_op_set(engine, context, EVAS_RENDER_COPY);
ENFN->rectangle_draw(engine, output, context, surface,
obj->cur->geometry.x + x, obj->cur->geometry.y + y,
obj->cur->geometry.w, obj->cur->geometry.h,
do_async);
return;
}
ENFN->context_color_set(engine, context, 255, 255, 255, 255);
2005-05-21 19:49:50 -07:00
if ((obj->cur->cache.clip.r == 255) &&
(obj->cur->cache.clip.g == 255) &&
(obj->cur->cache.clip.b == 255) &&
(obj->cur->cache.clip.a == 255))
2002-11-08 00:02:15 -08:00
{
ENFN->context_multiplier_unset(engine, context);
2002-11-08 00:02:15 -08:00
}
else
ENFN->context_multiplier_set(engine, context,
obj->cur->cache.clip.r,
obj->cur->cache.clip.g,
obj->cur->cache.clip.b,
obj->cur->cache.clip.a);
ENFN->context_render_op_set(engine, context, obj->cur->render_op);
// Clear out the pixel get stuff..
if (ENFN->gl_get_pixels_set)
ENFN->gl_get_pixels_set(engine, NULL, NULL, NULL);
if (ENFN->gl_image_direct_set)
ENFN->gl_image_direct_set(engine, o->engine_data, EINA_FALSE);
/* Render filter */
if (o->has_filter)
{
if (evas_filter_object_render(eo_obj, obj, engine, output, context, surface, x, y, do_async, EINA_FALSE))
return;
}
_evas_image_render(eo_obj, obj, engine, output, context, surface, x, y, 0, 0, 0, 0, EINA_FALSE, do_async);
}
void *
_evas_image_pixels_get(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *engine, void *output, void *context, void *surface,
int x, int y,
int *imagew, int *imageh, int *uvw, int *uvh,
Eina_Bool filtered, Eina_Bool needs_post_render)
{
Evas_Image_Data *o = obj->private_data, *oi = NULL;
Evas_Object_Protected_Data *source = NULL;
void *pixels = NULL;
EVAS_OBJECT_DATA_ALIVE_CHECK(obj, NULL);
if (filtered && o->has_filter)
pixels = evas_filter_output_buffer_get(eo_obj);
if (!pixels && o->cur->source)
{
source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
if (source && (source->type == o_type))
oi = efl_data_scope_get(o->cur->source, MY_CLASS);
}
if (pixels)
{
ENFN->image_size_get(engine, pixels, imagew, imageh);
*uvw = *imagew;
*uvh = *imageh;
}
else if (o->cur->scene)
{
_evas_image_3d_render(obj->layer->evas->evas, eo_obj, obj, o, o->cur->scene, engine, output);
pixels = obj->data_3d->surface;
*imagew = obj->data_3d->w;
*imageh = obj->data_3d->h;
*uvw = *imagew;
*uvh = *imageh;
}
else if (obj->cur->snapshot)
{
pixels = o->engine_data;
*imagew = o->cur->image.w;
*imageh = o->cur->image.h;
*uvw = *imagew;
*uvh = *imageh;
}
else if (!o->cur->source || !source)
{
// normal image (from file or user pixel set)
needs_post_render = EINA_FALSE;
if (output && surface)
pixels = evas_process_dirty_pixels(eo_obj, obj, o, engine, output, surface, o->engine_data);
else
pixels = o->engine_data;
*imagew = o->cur->image.w;
*imageh = o->cur->image.h;
*uvw = *imagew;
*uvh = *imageh;
}
else if (source->proxy->surface && !source->proxy->redraw)
{
pixels = source->proxy->surface;
*imagew = source->proxy->w;
*imageh = source->proxy->h;
*uvw = *imagew;
*uvh = *imageh;
}
else if (oi && oi->engine_data)
{
if (oi->has_filter)
pixels = evas_filter_output_buffer_get(source->object);
if (!pixels)
pixels = oi->engine_data;
*imagew = oi->cur->image.w;
*imageh = oi->cur->image.h;
*uvw = source->cur->geometry.w;
*uvh = source->cur->geometry.h;
/* check source_clip since we skip proxy_subrender here */
if (context && o->proxy_src_clip && source->cur->clipper)
{
ENFN->context_clip_clip(engine, context,
source->cur->clipper->cur->cache.clip.x + x,
source->cur->clipper->cur->cache.clip.y + y,
source->cur->clipper->cur->cache.clip.w,
source->cur->clipper->cur->cache.clip.h);
}
}
else
{
o->proxyrendering = EINA_TRUE;
evas_render_proxy_subrender(obj->layer->evas->evas, output, o->cur->source,
eo_obj, obj, o->proxy_src_clip, EINA_FALSE);
pixels = source->proxy->surface;
*imagew = source->proxy->w;
*imageh = source->proxy->h;
*uvw = *imagew;
*uvh = *imageh;
o->proxyrendering = EINA_FALSE;
}
if (needs_post_render && !obj->layer->evas->inside_post_render)
{
ERR("Can not save or map this image now! Proxies, snapshots and "
"filtered images support those operations only from inside a "
"post-render event.");
return NULL;
}
return pixels;
}
static void
_evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *engine, void *output, void *context, void *surface, int x, int y,
int l, int t, int r, int b, Eina_Bool skip_map, Eina_Bool do_async)
{
Evas_Image_Data *o = obj->private_data;
int imagew, imageh, uvw, uvh, cw, ch;
int ix, iy, iw, ih, offx, offy;
int idw, idh, idx, idy;
void *pixels;
pixels = _evas_image_pixels_get(eo_obj, obj, engine, output, context, surface, x, y,
&imagew, &imageh, &uvw, &uvh, EINA_FALSE, EINA_FALSE);
if (!pixels) return;
if (ENFN->context_clip_get(engine, context, NULL, NULL, &cw, &ch) && (!cw || !ch))
return;
if (!skip_map && (obj->map->cur.map) && (obj->map->cur.map->count > 3)
&& (obj->map->cur.usemap))
2002-11-08 00:02:15 -08:00
{
evas_object_map_update(eo_obj, x, y, imagew, imageh, uvw, uvh);
evas_draw_image_map_async_check(
obj, engine, output, context, surface, pixels, obj->map->spans,
o->cur->smooth_scale | obj->map->cur.map->smooth, 0, do_async);
return;
}
ENFN->image_scale_hint_set(engine, pixels, o->scale_hint);
idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw);
idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh);
if (idw < 1) idw = 1;
if (idh < 1) idh = 1;
if (idx > 0) idx -= idw;
if (idy > 0) idy -= idh;
offx = obj->cur->geometry.x + x;
offy = obj->cur->geometry.y + y;
while (idx < obj->cur->geometry.w)
{
int ydy, dobreak_w = 0;
ydy = idy;
ix = idx;
if ((o->cur->fill.w == obj->cur->geometry.w) &&
(o->cur->fill.x == 0))
{
dobreak_w = 1;
iw = obj->cur->geometry.w;
}
else
iw = idx + idw - ix;
// Filter stuff
if (o->filled)
{
iw -= l + r;
if (iw <= 0) break;
}
while (idy < obj->cur->geometry.h)
{
int dobreak_h = 0;
iy = idy;
if ((o->cur->fill.h == obj->cur->geometry.h) &&
(o->cur->fill.y == 0))
{
ih = obj->cur->geometry.h;
dobreak_h = 1;
}
else
ih = idy + idh - iy;
// Filter stuff
if (o->filled)
{
ih -= t + b;
if (ih <= 0) break;
}
if ((o->cur->border.l == 0) && (o->cur->border.r == 0) &&
(o->cur->border.t == 0) && (o->cur->border.b == 0) &&
(o->cur->border.fill != 0))
{
_draw_image(obj, engine, output, context, surface, pixels,
0, 0, imagew, imageh,
offx + ix, offy + iy, iw, ih,
o->cur->smooth_scale, do_async);
}
else
{
int inx, iny, inw, inh, outx, outy, outw, outh;
int bl, br, bt, bb, bsl, bsr, bst, bsb;
int imw, imh, ox, oy;
ox = offx + ix;
oy = offy + iy;
imw = imagew;
imh = imageh;
bl = o->cur->border.l;
br = o->cur->border.r;
bt = o->cur->border.t;
bb = o->cur->border.b;
// fix impossible border settings if img pixels not enough
if ((bl + br) > 0)
{
if ((bl + br) > imw)
{
bl = (bl * imw) / (bl + br);
br = imw - bl;
}
if ((bl + br) == imw)
{
if (bl < br) br--;
else bl--;
}
}
if ((bt + bb) > 0)
{
if ((bt + bb) > imh)
{
bt = (bt * imh) / (bt + bb);
bb = imh - bt;
}
if ((bt + bb) == imh)
{
if (bt < bb) bb--;
else bt--;
}
}
if (!EINA_DBL_EQ(o->cur->border.scale, 1.0))
{
bsl = ((double)bl * o->cur->border.scale);
bsr = ((double)br * o->cur->border.scale);
bst = ((double)bt * o->cur->border.scale);
bsb = ((double)bb * o->cur->border.scale);
}
else
{
bsl = bl; bsr = br; bst = bt; bsb = bb;
}
// adjust output border rendering if it doesnt fit
if ((bsl + bsr) > iw)
{
int b0 = bsl, b1 = bsr;
if ((bsl + bsr) > 0)
{
bsl = (bsl * iw) / (bsl + bsr);
bsr = iw - bsl;
}
if (b0 > 0) bl = (bl * bsl) / b0;
else bl = 0;
if (b1 > 0) br = (br * bsr) / b1;
else br = 0;
}
if ((bst + bsb) > ih)
{
int b0 = bst, b1 = bsb;
if ((bst + bsb) > 0)
{
bst = (bst * ih) / (bst + bsb);
bsb = ih - bst;
}
if (b0 > 0) bt = (bt * bst) / b0;
else bt = 0;
if (b1 > 0) bb = (bb * bsb) / b1;
else bb = 0;
}
// #--.
// | |
// '--'
inx = 0; iny = 0;
inw = bl; inh = bt;
outx = ox; outy = oy;
outw = bsl; outh = bst;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .##.
// | |
// '--'
inx = bl; iny = 0;
inw = imw - bl - br; inh = bt;
outx = ox + bsl; outy = oy;
outw = iw - bsl - bsr; outh = bst;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .--#
// | |
// '--'
inx = imw - br; iny = 0;
inw = br; inh = bt;
outx = ox + iw - bsr; outy = oy;
outw = bsr; outh = bst;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .--.
// # |
// '--'
inx = 0; iny = bt;
inw = bl; inh = imh - bt - bb;
outx = ox; outy = oy + bst;
outw = bsl; outh = ih - bst - bsb;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .--.
// |##|
// '--'
if (o->cur->border.fill > EVAS_BORDER_FILL_NONE)
{
inx = bl; iny = bt;
inw = imw - bl - br; inh = imh - bt - bb;
outx = ox + bsl; outy = oy + bst;
outw = iw - bsl - bsr; outh = ih - bst - bsb;
if ((o->cur->border.fill == EVAS_BORDER_FILL_SOLID) &&
(obj->cur->cache.clip.a == 255) &&
(!obj->clip.mask) &&
(obj->cur->render_op == EVAS_RENDER_BLEND))
{
ENFN->context_render_op_set(engine, context, EVAS_RENDER_COPY);
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
ENFN->context_render_op_set(engine, context, obj->cur->render_op);
}
else
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
}
// .--.
// | #
// '--'
inx = imw - br; iny = bt;
inw = br; inh = imh - bt - bb;
outx = ox + iw - bsr; outy = oy + bst;
outw = bsr; outh = ih - bst - bsb;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .--.
// | |
// #--'
inx = 0; iny = imh - bb;
inw = bl; inh = bb;
outx = ox; outy = oy + ih - bsb;
outw = bsl; outh = bsb;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .--.
// | |
// '##'
inx = bl; iny = imh - bb;
inw = imw - bl - br; inh = bb;
outx = ox + bsl; outy = oy + ih - bsb;
outw = iw - bsl - bsr; outh = bsb;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
// .--.
// | |
// '--#
inx = imw - br; iny = imh - bb;
inw = br; inh = bb;
outx = ox + iw - bsr; outy = oy + ih - bsb;
outw = bsr; outh = bsb;
_draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
}
idy += idh;
if (dobreak_h) break;
}
idx += idw;
idy = ydy;
if (dobreak_w) break;
}
2002-11-08 00:02:15 -08:00
}
static void
evas_object_image_render_pre(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
int is_v = 0, was_v = 0;
Eina_Bool changed_prep = EINA_TRUE;
2002-11-08 00:02:15 -08:00
/* image is not ready yet, skip rendering. Leave it to next frame */
2018-09-02 23:19:02 -07:00
if (o->preload & EVAS_IMAGE_PRELOADING) return;
2002-11-08 00:02:15 -08:00
/* dont pre-render the obj twice! */
if (obj->pre_render_done) return;
obj->pre_render_done = EINA_TRUE;
2002-11-08 00:02:15 -08:00
/* pre-render phase. this does anything an object needs to do just before */
/* rendering. this could mean loading the image data, retrieving it from */
/* elsewhere, decoding video etc. */
/* then when this is done the object needs to figure if it changed and */
/* if so what and where and add the appropriate redraw rectangles */
Evas_Public_Data *e = obj->layer->evas;
if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1)) return;
2002-11-08 00:02:15 -08:00
/* if someone is clipping this obj - go calculate the clipper */
if (obj->cur->clipper)
2002-11-08 00:02:15 -08:00
{
if (obj->cur->cache.clip.dirty)
evas_object_clip_recalc(obj->cur->clipper);
obj->cur->clipper->func->render_pre(obj->cur->clipper->object,
obj->cur->clipper,
obj->cur->clipper->private_data);
2002-11-08 00:02:15 -08:00
}
/* Proxy: Do it early */
if (o->cur->source)
{
Evas_Object_Protected_Data *source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
if (source->proxy->redraw || source->changed)
{
/* XXX: Do I need to sort out the map here? */
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
}
else if (o->cur->scene)
{
Evas_Canvas3D_Scene *scene = o->cur->scene;
2014-04-25 10:28:38 -07:00
Eina_Bool dirty;
dirty = evas_canvas3d_object_dirty_get(scene, EVAS_CANVAS3D_STATE_ANY);
2014-04-25 10:28:38 -07:00
if (dirty)
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
}
2002-11-08 00:02:15 -08:00
/* now figure what changed and add draw rects */
/* if it just became visible or invisible */
is_v = evas_object_is_visible(eo_obj, obj);
was_v = evas_object_was_visible(eo_obj, obj);
2002-11-08 00:02:15 -08:00
if (is_v != was_v)
{
evas_object_render_pre_visible_change(&e->clip_changes, eo_obj, is_v, was_v);
goto done;
2002-11-08 00:02:15 -08:00
}
if (obj->changed_map || obj->changed_src_visible)
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
/* it's not visible - we accounted for it appearing or not so just abort */
2002-11-08 00:02:15 -08:00
if (!is_v) goto done;
/* clipper changed this is in addition to anything else for obj */
if (was_v)
evas_object_render_pre_clipper_change(&e->clip_changes, eo_obj);
/* if we restacked (layer or just within a layer) and don't clip anyone */
2002-11-08 00:02:15 -08:00
if (obj->restack)
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
2002-11-08 00:02:15 -08:00
}
/* if it changed color */
if ((obj->cur->color.r != obj->prev->color.r) ||
(obj->cur->color.g != obj->prev->color.g) ||
(obj->cur->color.b != obj->prev->color.b) ||
(obj->cur->color.a != obj->prev->color.a) ||
(obj->cur->cache.clip.r != obj->prev->cache.clip.r) ||
(obj->cur->cache.clip.g != obj->prev->cache.clip.g) ||
(obj->cur->cache.clip.b != obj->prev->cache.clip.b) ||
(obj->cur->cache.clip.a != obj->prev->cache.clip.a))
2002-11-08 00:02:15 -08:00
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
2002-11-08 00:02:15 -08:00
}
if ((obj->cur->render_op != obj->prev->render_op) || /* if it changed render op */
(obj->cur->anti_alias != obj->prev->anti_alias)) /* if it changed anti_alias */
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
2002-11-08 00:02:15 -08:00
if (o->changed)
{
if (((o->cur->f) && (!o->prev->f)) ||
((!o->cur->f) && (o->prev->f)) ||
((o->cur->key) && (!o->prev->key)) ||
((!o->cur->key) && (o->prev->key))
)
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
if ((o->cur->image.w != o->prev->image.w) ||
(o->cur->image.h != o->prev->image.h) ||
(o->cur->has_alpha != o->prev->has_alpha) ||
(o->cur->cspace != o->prev->cspace) ||
(o->cur->smooth_scale != o->prev->smooth_scale))
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
if ((o->cur->border.l != o->prev->border.l) ||
(o->cur->border.r != o->prev->border.r) ||
(o->cur->border.t != o->prev->border.t) ||
(o->cur->border.b != o->prev->border.b) ||
(o->cur->border.fill != o->prev->border.fill) ||
(!EINA_DBL_EQ(o->cur->border.scale, o->prev->border.scale)))
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
if ((o->cur->frame != o->prev->frame) ||
(o->cur->orient != o->prev->orient) ||
/* Legacy compatibility (invalid behaviour): dirty_set() used to
* trigger full image redraw, even though this was not correct. */
(o->dirty_pixels && !o->pixels->pixel_updates))
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
//pre-loading is finished
2018-09-02 23:19:02 -07:00
if (o->preload == EVAS_IMAGE_PRELOADED)
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2018-09-02 23:19:02 -07:00
o->preload = EVAS_IMAGE_PRELOAD_NONE;
goto done;
}
2002-11-08 00:02:15 -08:00
}
if (((obj->cur->geometry.x != obj->prev->geometry.x) ||
(obj->cur->geometry.y != obj->prev->geometry.y) ||
(obj->cur->geometry.w != obj->prev->geometry.w) ||
(obj->cur->geometry.h != obj->prev->geometry.h))
)
2002-11-08 00:02:15 -08:00
{
if ((obj->cur->geometry.w == obj->prev->geometry.w) &&
(obj->cur->geometry.h == obj->prev->geometry.h))
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
}
else
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
2002-11-08 00:02:15 -08:00
}
if (o->changed)
{
if ((o->cur->fill.x != o->prev->fill.x) ||
(o->cur->fill.y != o->prev->fill.y) ||
(o->cur->fill.w != o->prev->fill.w) ||
(o->cur->fill.h != o->prev->fill.h))
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
goto done;
}
if (o->pixels->pixel_updates)
{
if ((o->cur->border.l == 0) &&
(o->cur->border.r == 0) &&
(o->cur->border.t == 0) &&
(o->cur->border.b == 0) &&
(o->cur->image.w > 0) &&
(o->cur->image.h > 0) &&
(!((obj->map->cur.map) && (obj->map->cur.usemap))))
{
Eina_Rectangle *rr;
if ((!o->cur->has_alpha) &&
(evas_object_is_opaque(eo_obj, obj)) &&
(obj->cur->color.a == 255))
{
Evas_Coord x, y, w, h;
x = obj->cur->cache.clip.x;
y = obj->cur->cache.clip.y;
w = obj->cur->cache.clip.w;
h = obj->cur->cache.clip.h;
if (obj->cur->clipper)
{
if (obj->cur->clipper->cur->cache.clip.a != 255)
w = 0;
else
{
RECTS_CLIP_TO_RECT(x, y, w, h,
obj->cur->clipper->cur->cache.clip.x,
obj->cur->clipper->cur->cache.clip.y,
obj->cur->clipper->cur->cache.clip.w,
obj->cur->clipper->cur->cache.clip.h);
}
}
if ((w > 0) && (h > 0))
evas_render_update_del(e,
x + e->framespace.x,
y + e->framespace.y,
w, h);
}
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, rr)
{
Evas_Coord idw, idh, idx, idy;
int x, y, w, h;
e->engine.func->image_dirty_region(ENC, o->engine_data, rr->x, rr->y, rr->w, rr->h);
idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw);
idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh);
if (idw < 1) idw = 1;
if (idh < 1) idh = 1;
if (idx > 0) idx -= idw;
if (idy > 0) idy -= idh;
while (idx < obj->cur->geometry.w)
{
Evas_Coord ydy;
ydy = idy;
x = idx;
w = ((int)(idx + idw)) - x;
while (idy < obj->cur->geometry.h)
{
Eina_Rectangle r;
y = idy;
h = ((int)(idy + idh)) - y;
r.x = (rr->x * w) / o->cur->image.w;
r.y = (rr->y * h) / o->cur->image.h;
r.w = ((rr->w * w) + (o->cur->image.w * 2) - 1) / o->cur->image.w;
r.h = ((rr->h * h) + (o->cur->image.h * 2) - 1) / o->cur->image.h;
r.x += obj->cur->geometry.x + x;
r.y += obj->cur->geometry.y + y;
RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h,
obj->cur->cache.clip.x, obj->cur->cache.clip.y,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
evas_add_rect(&e->clip_changes, r.x, r.y, r.w, r.h);
idy += h;
}
idx += idw;
idy = ydy;
}
eina_rectangle_free(rr);
}
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
else
{
if ((o->cur->image.w > 0) &&
(o->cur->image.h > 0) &&
(o->cur->image.w == obj->cur->geometry.w) &&
(o->cur->image.h == obj->cur->geometry.h) &&
(o->cur->fill.x == 0) &&
(o->cur->fill.y == 0) &&
(o->cur->fill.w == o->cur->image.w) &&
(o->cur->fill.h == o->cur->image.h) &&
(!((obj->map->cur.map) && (obj->map->cur.usemap))))
{
Eina_Rectangle *rr;
if ((!o->cur->has_alpha) &&
(evas_object_is_opaque(eo_obj, obj)) &&
(obj->cur->color.a == 255))
{
Evas_Coord x, y, w, h;
x = obj->cur->cache.clip.x;
y = obj->cur->cache.clip.y;
w = obj->cur->cache.clip.w;
h = obj->cur->cache.clip.h;
if (obj->cur->clipper)
{
if (obj->cur->clipper->cur->cache.clip.a != 255)
w = 0;
else
{
RECTS_CLIP_TO_RECT(x, y, w, h,
obj->cur->clipper->cur->cache.clip.x,
obj->cur->clipper->cur->cache.clip.y,
obj->cur->clipper->cur->cache.clip.w,
obj->cur->clipper->cur->cache.clip.h);
}
}
if ((w > 0) && (h > 0))
evas_render_update_del(e,
x + e->framespace.x,
y + e->framespace.y,
w, h);
}
else if ((o->cur->border.fill == EVAS_BORDER_FILL_SOLID) &&
(obj->cur->color.a == 255))
{
Evas_Coord x, y, w, h;
x = obj->cur->geometry.x + o->cur->border.l;
y = obj->cur->geometry.y + o->cur->border.t;
w = obj->cur->geometry.w - o->cur->border.l - o->cur->border.r;
h = obj->cur->geometry.h - o->cur->border.t - o->cur->border.b;
if (obj->cur->clipper)
{
if (obj->cur->clipper->cur->cache.clip.a != 255)
w = 0;
else
{
RECTS_CLIP_TO_RECT(x, y, w, h,
obj->cur->clipper->cur->cache.clip.x,
obj->cur->clipper->cur->cache.clip.y,
obj->cur->clipper->cur->cache.clip.w,
obj->cur->clipper->cur->cache.clip.h);
}
}
if ((w > 0) && (h > 0))
evas_render_update_del(e,
x + e->framespace.x,
y + e->framespace.y,
w, h);
}
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, rr)
{
Eina_Rectangle r;
e->engine.func->image_dirty_region(ENC, o->engine_data, rr->x, rr->y, rr->w, rr->h);
r.x = rr->x;
r.y = rr->y;
r.w = rr->w;
r.h = rr->h;
r.x += obj->cur->geometry.x;
r.y += obj->cur->geometry.y;
RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h,
obj->cur->cache.clip.x, obj->cur->cache.clip.y,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
evas_add_rect(&e->clip_changes, r.x, r.y, r.w, r.h);
eina_rectangle_free(rr);
}
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
else
{
Eina_Rectangle *r;
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, r)
eina_rectangle_free(r);
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
e->engine.func->image_dirty_region(ENC, o->engine_data, 0, 0, o->cur->image.w, o->cur->image.h);
evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj,
obj);
}
}
goto done;
}
2002-11-08 00:02:15 -08:00
}
/* it obviously didn't change - add a NO obscure - this "unupdates" this */
/* area so if there were updates for it they get wiped. don't do it if we */
/* aren't fully opaque and we are visible */
if (evas_object_is_opaque(eo_obj, obj))
{
Evas_Coord x, y, w, h;
x = obj->cur->cache.clip.x;
y = obj->cur->cache.clip.y;
w = obj->cur->cache.clip.w;
h = obj->cur->cache.clip.h;
if (obj->cur->clipper)
{
RECTS_CLIP_TO_RECT(x, y, w, h,
obj->cur->clipper->cur->cache.clip.x,
obj->cur->clipper->cur->cache.clip.y,
obj->cur->clipper->cur->cache.clip.w,
obj->cur->clipper->cur->cache.clip.h);
}
evas_render_update_del(e,
x + e->framespace.x,
y + e->framespace.y,
w, h);
changed_prep = EINA_FALSE;
}
else
changed_prep = EINA_FALSE;
done:
evas_object_render_pre_effect_updates(&e->clip_changes, eo_obj, is_v, was_v);
if (o->pixels->pixel_updates)
{
Eina_Rectangle *rr;
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, rr)
{
eina_rectangle_free(rr);
}
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
if (changed_prep)
{
if (o->engine_data_prep)
{
ENFN->image_free(ENC, o->engine_data_prep);
o->engine_data_prep = NULL;
}
}
o->changed = EINA_FALSE;
2002-11-08 00:02:15 -08:00
}
static void
evas render - drop eo overhead by using ptrs we already have several calls, specifically evas_object_change_reset, evas_object_cur_prev, and evas_object_clip_changes_clean that are called directly or indirectly as part of evas render on at least every active object if not more, were doing full eo obj lookups when their calling functions already all had the eo protected data looked up. tha's silly and just adds overhead we don't need. my test dropped _eo_obj_pointer_get overhead in perf profiles from 4.48% to 2.65%. see: 4.48% libeo.so.1.18.99 [.] _eo_obj_pointer_get 4.23% libevas.so.1.18.99 [.] evas_render_updates_internal 2.61% libevas.so.1.18.99 [.] evas_render_updates_internal_loop 1.68% libeo.so.1.18.99 [.] efl_data_scope_get 1.57% libc-2.24.so [.] _int_malloc 1.42% libevas.so.1.18.99 [.] evas_object_smart_changed_get 1.09% libevas.so.1.18.99 [.] evas_object_clip_recalc.part.37 1.08% libpthread-2.24.so [.] pthread_getspecific 1.05% libevas.so.1.18.99 [.] efl_canvas_object_class_get 1.01% libevas.so.1.18.99 [.] evas_object_cur_prev 0.99% libeo.so.1.18.99 [.] _efl_object_event_callback_legacy_call 0.87% libevas.so.1.18.99 [.] _evas_render_phase1_object_ctx_render_cache_append 0.82% libpthread-2.24.so [.] pthread_mutex_lock 0.81% libevas.so.1.18.99 [.] _evas_render_phase1_object_process 0.79% libc-2.24.so [.] _int_free vs now the improved: 4.82% libevas.so.1.18.99 [.] evas_render_updates_internal 3.44% libevas.so.1.18.99 [.] evas_render_updates_internal_loop 2.65% libeo.so.1.18.99 [.] _eo_obj_pointer_get 2.22% libc-2.24.so [.] _int_malloc 1.46% libevas.so.1.18.99 [.] evas_object_smart_changed_get 1.04% libeo.so.1.18.99 [.] _efl_object_event_callback_legacy_call 1.03% libevas.so.1.18.99 [.] _evas_render_phase1_object_ctx_render_cache_append 0.97% libeina.so.1.18.99 [.] eina_chained_mempool_malloc 0.93% libevas.so.1.18.99 [.] evas_object_clip_recalc.part.37 0.92% libpthread-2.24.so [.] pthread_mutex_lock 0.91% libevas.so.1.18.99 [.] _evas_render_phase1_object_process 0.84% libc-2.24.so [.] _int_free 0.84% libevas.so.1.18.99 [.] evas_object_cur_prev 0.83% libeina.so.1.18.99 [.] eina_chained_mempool_free 0.80% libeo.so.1.18.99 [.] efl_data_scope_get of course other things "increase their percentage" as oe overhead now dropped, and things seem to move around a bit, but it does make sense to do this with no downsides i can see as we already are accessing the protected data ptr in the parent func.
2017-02-03 18:31:55 -08:00
evas_object_image_render_post(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
Eina_Rectangle *r;
2002-11-08 00:02:15 -08:00
/* image is not ready yet, skip rendering. Leave it to next frame */
if (o->preload & EVAS_IMAGE_PRELOADING) return;
2002-11-08 00:02:15 -08:00
/* this moves the current data to the previous state parts of the object */
/* in whatever way is safest for the object. also if we don't need object */
/* data anymore we can free it if the object deems this is a good idea */
/* remove those pesky changes */
evas render - drop eo overhead by using ptrs we already have several calls, specifically evas_object_change_reset, evas_object_cur_prev, and evas_object_clip_changes_clean that are called directly or indirectly as part of evas render on at least every active object if not more, were doing full eo obj lookups when their calling functions already all had the eo protected data looked up. tha's silly and just adds overhead we don't need. my test dropped _eo_obj_pointer_get overhead in perf profiles from 4.48% to 2.65%. see: 4.48% libeo.so.1.18.99 [.] _eo_obj_pointer_get 4.23% libevas.so.1.18.99 [.] evas_render_updates_internal 2.61% libevas.so.1.18.99 [.] evas_render_updates_internal_loop 1.68% libeo.so.1.18.99 [.] efl_data_scope_get 1.57% libc-2.24.so [.] _int_malloc 1.42% libevas.so.1.18.99 [.] evas_object_smart_changed_get 1.09% libevas.so.1.18.99 [.] evas_object_clip_recalc.part.37 1.08% libpthread-2.24.so [.] pthread_getspecific 1.05% libevas.so.1.18.99 [.] efl_canvas_object_class_get 1.01% libevas.so.1.18.99 [.] evas_object_cur_prev 0.99% libeo.so.1.18.99 [.] _efl_object_event_callback_legacy_call 0.87% libevas.so.1.18.99 [.] _evas_render_phase1_object_ctx_render_cache_append 0.82% libpthread-2.24.so [.] pthread_mutex_lock 0.81% libevas.so.1.18.99 [.] _evas_render_phase1_object_process 0.79% libc-2.24.so [.] _int_free vs now the improved: 4.82% libevas.so.1.18.99 [.] evas_render_updates_internal 3.44% libevas.so.1.18.99 [.] evas_render_updates_internal_loop 2.65% libeo.so.1.18.99 [.] _eo_obj_pointer_get 2.22% libc-2.24.so [.] _int_malloc 1.46% libevas.so.1.18.99 [.] evas_object_smart_changed_get 1.04% libeo.so.1.18.99 [.] _efl_object_event_callback_legacy_call 1.03% libevas.so.1.18.99 [.] _evas_render_phase1_object_ctx_render_cache_append 0.97% libeina.so.1.18.99 [.] eina_chained_mempool_malloc 0.93% libevas.so.1.18.99 [.] evas_object_clip_recalc.part.37 0.92% libpthread-2.24.so [.] pthread_mutex_lock 0.91% libevas.so.1.18.99 [.] _evas_render_phase1_object_process 0.84% libc-2.24.so [.] _int_free 0.84% libevas.so.1.18.99 [.] evas_object_cur_prev 0.83% libeina.so.1.18.99 [.] eina_chained_mempool_free 0.80% libeo.so.1.18.99 [.] efl_data_scope_get of course other things "increase their percentage" as oe overhead now dropped, and things seem to move around a bit, but it does make sense to do this with no downsides i can see as we already are accessing the protected data ptr in the parent func.
2017-02-03 18:31:55 -08:00
evas_object_clip_changes_clean(obj);
if (o->pixels->pixel_updates)
{
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, r)
eina_rectangle_free(r);
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
2002-11-08 00:02:15 -08:00
/* move cur to prev safely for object data */
evas render - drop eo overhead by using ptrs we already have several calls, specifically evas_object_change_reset, evas_object_cur_prev, and evas_object_clip_changes_clean that are called directly or indirectly as part of evas render on at least every active object if not more, were doing full eo obj lookups when their calling functions already all had the eo protected data looked up. tha's silly and just adds overhead we don't need. my test dropped _eo_obj_pointer_get overhead in perf profiles from 4.48% to 2.65%. see: 4.48% libeo.so.1.18.99 [.] _eo_obj_pointer_get 4.23% libevas.so.1.18.99 [.] evas_render_updates_internal 2.61% libevas.so.1.18.99 [.] evas_render_updates_internal_loop 1.68% libeo.so.1.18.99 [.] efl_data_scope_get 1.57% libc-2.24.so [.] _int_malloc 1.42% libevas.so.1.18.99 [.] evas_object_smart_changed_get 1.09% libevas.so.1.18.99 [.] evas_object_clip_recalc.part.37 1.08% libpthread-2.24.so [.] pthread_getspecific 1.05% libevas.so.1.18.99 [.] efl_canvas_object_class_get 1.01% libevas.so.1.18.99 [.] evas_object_cur_prev 0.99% libeo.so.1.18.99 [.] _efl_object_event_callback_legacy_call 0.87% libevas.so.1.18.99 [.] _evas_render_phase1_object_ctx_render_cache_append 0.82% libpthread-2.24.so [.] pthread_mutex_lock 0.81% libevas.so.1.18.99 [.] _evas_render_phase1_object_process 0.79% libc-2.24.so [.] _int_free vs now the improved: 4.82% libevas.so.1.18.99 [.] evas_render_updates_internal 3.44% libevas.so.1.18.99 [.] evas_render_updates_internal_loop 2.65% libeo.so.1.18.99 [.] _eo_obj_pointer_get 2.22% libc-2.24.so [.] _int_malloc 1.46% libevas.so.1.18.99 [.] evas_object_smart_changed_get 1.04% libeo.so.1.18.99 [.] _efl_object_event_callback_legacy_call 1.03% libevas.so.1.18.99 [.] _evas_render_phase1_object_ctx_render_cache_append 0.97% libeina.so.1.18.99 [.] eina_chained_mempool_malloc 0.93% libevas.so.1.18.99 [.] evas_object_clip_recalc.part.37 0.92% libpthread-2.24.so [.] pthread_mutex_lock 0.91% libevas.so.1.18.99 [.] _evas_render_phase1_object_process 0.84% libc-2.24.so [.] _int_free 0.84% libevas.so.1.18.99 [.] evas_object_cur_prev 0.83% libeina.so.1.18.99 [.] eina_chained_mempool_free 0.80% libeo.so.1.18.99 [.] efl_data_scope_get of course other things "increase their percentage" as oe overhead now dropped, and things seem to move around a bit, but it does make sense to do this with no downsides i can see as we already are accessing the protected data ptr in the parent func.
2017-02-03 18:31:55 -08:00
evas_object_cur_prev(obj);
eina_cow_memcpy(evas_object_image_state_cow, (const Eina_Cow_Data **)&o->prev, o->cur);
2002-11-08 00:02:15 -08:00
/* FIXME: copy strings across */
//Somehow(preloading cancelled) image has been changed, need to redraw.
if (o->changed) evas_object_change(eo_obj, obj);
2002-11-08 00:02:15 -08:00
}
static void *
evas_object_image_engine_data_get(Evas_Object *eo_obj)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
if (!o) return NULL;
return o->engine_data;
}
2002-11-08 00:02:15 -08:00
static int
evas_object_image_is_opaque(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data)
2002-11-08 00:02:15 -08:00
{
/* this returns 1 if the internal object data implies that the object is */
/* currently fully opaque over the entire rectangle it occupies */
/* disable caching due tyo maps screwing with this
o->cur.opaque_valid = 0;*/
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
if (o->preload == EVAS_IMAGE_PRELOADING) return 0;
if (o->cur->opaque_valid)
{
if (!o->cur->opaque) return 0;
}
else
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->opaque = 0;
state_write->opaque_valid = 1;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1))
return o->cur->opaque;
if (((o->cur->border.l != 0) ||
(o->cur->border.r != 0) ||
(o->cur->border.t != 0) ||
(o->cur->border.b != 0)) &&
(!o->cur->border.fill))
return o->cur->opaque;
if (!o->engine_data)
return o->cur->opaque;
if (o->has_filter)
return o->cur->opaque;
// FIXME: use proxy
if (o->cur->source)
{
Evas_Object_Protected_Data *cur_source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->opaque = evas_object_is_opaque(o->cur->source, cur_source);
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
return o->cur->opaque; /* FIXME: Should go poke at the object */
}
if (o->cur->has_alpha)
return o->cur->opaque;
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->opaque = 1;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
if ((obj->map->cur.map) && (obj->map->cur.usemap))
{
Evas_Map *m = obj->map->cur.map;
if ((m->points[0].a == 255) &&
(m->points[1].a == 255) &&
(m->points[2].a == 255) &&
(m->points[3].a == 255))
{
if (((EINA_DBL_EQ(m->points[0].x, m->points[3].x)) &&
(EINA_DBL_EQ(m->points[1].x, m->points[2].x)) &&
(EINA_DBL_EQ(m->points[0].y, m->points[1].y)) &&
(EINA_DBL_EQ(m->points[2].y, m->points[3].y))) ||
((EINA_DBL_EQ(m->points[0].x, m->points[1].x)) &&
(EINA_DBL_EQ(m->points[2].x, m->points[3].x)) &&
(EINA_DBL_EQ(m->points[0].y, m->points[3].y)) &&
(EINA_DBL_EQ(m->points[1].y, m->points[2].y))))
{
if ((EINA_DBL_EQ(m->points[0].x, obj->cur->geometry.x)) &&
(EINA_DBL_EQ(m->points[0].y, obj->cur->geometry.y)) &&
(EINA_DBL_EQ(m->points[2].x,
obj->cur->geometry.x + obj->cur->geometry.w)) &&
(EINA_DBL_EQ(m->points[2].y,
obj->cur->geometry.y + obj->cur->geometry.h)))
return o->cur->opaque;
}
}
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->opaque = 0;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
return o->cur->opaque;
}
if (obj->cur->render_op == EVAS_RENDER_COPY)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
{
state_write->opaque = 1;
}
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
return o->cur->opaque;
}
return o->cur->opaque;
2002-11-08 00:02:15 -08:00
}
static int
evas_object_image_was_opaque(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data)
2002-11-08 00:02:15 -08:00
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
2002-11-08 00:02:15 -08:00
/* this returns 1 if the internal object data implies that the object was */
/* previously fully opaque over the entire rectangle it occupies */
if (o->prev->opaque_valid)
{
if (!o->prev->opaque) return 0;
}
else
{
EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
{
state_write->opaque = 0;
state_write->opaque_valid = 1;
}
EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
if ((o->prev->fill.w < 1) || (o->prev->fill.h < 1))
return o->prev->opaque;
if (((o->prev->border.l != 0) ||
(o->prev->border.r != 0) ||
(o->prev->border.t != 0) ||
(o->prev->border.b != 0)) &&
(!o->prev->border.fill))
return o->prev->opaque;
if (!o->engine_data)
return o->prev->opaque;
// FIXME: use proxy
if (o->prev->source)
return o->prev->opaque; /* FIXME: Should go poke at the object */
if (o->prev->has_alpha)
return o->prev->opaque;
if (o->has_filter)
return o->cur->opaque;
EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
{
state_write->opaque = 1;
}
EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
}
if (obj->map->prev.usemap)
{
Evas_Map *m = obj->map->prev.map;
if ((m->points[0].a == 255) &&
(m->points[1].a == 255) &&
(m->points[2].a == 255) &&
(m->points[3].a == 255))
{
if (((EINA_DBL_EQ(m->points[0].x, m->points[3].x)) &&
(EINA_DBL_EQ(m->points[1].x, m->points[2].x)) &&
(EINA_DBL_EQ(m->points[0].y, m->points[1].y)) &&
(EINA_DBL_EQ(m->points[2].y, m->points[3].y))) ||
((EINA_DBL_EQ(m->points[0].x, m->points[1].x)) &&
(EINA_DBL_EQ(m->points[2].x, m->points[3].x)) &&
(EINA_DBL_EQ(m->points[0].y, m->points[3].y)) &&
(EINA_DBL_EQ(m->points[1].y, m->points[2].y))))
{
if ((EINA_DBL_EQ(m->points[0].x, obj->prev->geometry.x)) &&
(EINA_DBL_EQ(m->points[0].y, obj->prev->geometry.y)) &&
(EINA_DBL_EQ(m->points[2].x,
obj->prev->geometry.x + obj->prev->geometry.w)) &&
(EINA_DBL_EQ(m->points[2].y,
obj->prev->geometry.y + obj->prev->geometry.h)))
return o->prev->opaque;
}
}
EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
{
state_write->opaque = 0;
}
EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
return o->prev->opaque;
}
if (obj->prev->render_op == EVAS_RENDER_COPY)
{
EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
{
state_write->opaque = 1;
}
EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
return o->prev->opaque;
}
if (obj->prev->render_op != EVAS_RENDER_BLEND)
{
EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
{
state_write->opaque = 0;
}
EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
return o->prev->opaque;
}
return o->prev->opaque;
2002-11-08 00:02:15 -08:00
}
static int
evas_object_image_is_inside(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data,
Evas_Coord px, Evas_Coord py)
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
int imagew, imageh, uvw, uvh, ix, iy, iw, ih, idw, idh, idx, idy;
int is_inside = 0;
void *pixels;
void *output;
// FIXME: The below loop is incredibly dubious and probably should be simplified.
// We're looking for one single pixel, not a random series of positions.
// Original comment:
/* the following code is similar to evas_object_image_render(), but doesn't
* draw, just get the pixels so we can check the transparency.
*/
output = _evas_object_image_output_find(obj);
pixels = _evas_image_pixels_get(eo_obj, obj, ENC, output, NULL, NULL, 0, 0,
&imagew, &imageh, &uvw, &uvh, EINA_TRUE, EINA_FALSE);
if (!pixels) return is_inside;
if (o->dirty_pixels)
{
if (o->pixels->func.get_pixels)
{
if (ENFN->gl_get_pixels_pre)
ENFN->gl_get_pixels_pre(ENC, output);
o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, eo_obj);
if (ENFN->gl_get_pixels_post)
ENFN->gl_get_pixels_post(ENC, output);
}
2009-06-03 07:16:55 -07:00
}
/* TODO: not handling map, need to apply map to point */
if ((obj->map->cur.map) && (obj->map->cur.map->count > 3) && (obj->map->cur.usemap))
2009-06-03 07:16:55 -07:00
{
evas_object_map_update(eo_obj, 0, 0, imagew, imageh, uvw, uvh);
ERR("map not supported");
return is_inside;
}
idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw);
idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh);
if (idw < 1) idw = 1;
if (idh < 1) idh = 1;
if (idx > 0) idx -= idw;
if (idy > 0) idy -= idh;
while (idx < obj->cur->geometry.w)
{
int ydy, dobreak_w = 0;
ydy = idy;
ix = idx;
if ((o->cur->fill.w == obj->cur->geometry.w) &&
(o->cur->fill.x == 0))
{
dobreak_w = 1;
iw = obj->cur->geometry.w;
}
else
iw = idx + idw - ix;
while (idy < obj->cur->geometry.h)
{
int dobreak_h = 0;
DATA8 alpha = 0;
iy = idy;
if ((o->cur->fill.h == obj->cur->geometry.h) &&
(o->cur->fill.y == 0))
{
ih = obj->cur->geometry.h;
dobreak_h = 1;
}
else
ih = idy + idh - iy;
if ((o->cur->border.l == 0) && (o->cur->border.r == 0) &&
(o->cur->border.t == 0) && (o->cur->border.b == 0) &&
(o->cur->border.fill != 0))
{
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
0, 0, imagew, imageh,
obj->cur->geometry.x + ix,
obj->cur->geometry.y + iy,
iw, ih))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
}
else
{
int inx, iny, inw, inh, outx, outy, outw, outh;
int bl, br, bt, bb, bsl, bsr, bst, bsb;
int imw, imh, ox, oy;
ox = obj->cur->geometry.x + ix;
oy = obj->cur->geometry.y + iy;
imw = imagew;
imh = imageh;
bl = o->cur->border.l;
br = o->cur->border.r;
bt = o->cur->border.t;
bb = o->cur->border.b;
if ((bl + br) > iw)
{
bl = iw / 2;
br = iw - bl;
}
if ((bl + br) > imw)
{
bl = imw / 2;
br = imw - bl;
}
if ((bt + bb) > ih)
{
bt = ih / 2;
bb = ih - bt;
}
if ((bt + bb) > imh)
{
bt = imh / 2;
bb = imh - bt;
}
if (!EINA_DBL_EQ(o->cur->border.scale, 1.0))
{
bsl = ((double)bl * o->cur->border.scale);
bsr = ((double)br * o->cur->border.scale);
bst = ((double)bt * o->cur->border.scale);
bsb = ((double)bb * o->cur->border.scale);
}
else
{
bsl = bl; bsr = br; bst = bt; bsb = bb;
}
// #--
// |
inx = 0; iny = 0;
inw = bl; inh = bt;
outx = ox; outy = oy;
outw = bsl; outh = bst;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// .##
// |
inx = bl; iny = 0;
inw = imw - bl - br; inh = bt;
outx = ox + bsl; outy = oy;
outw = iw - bsl - bsr; outh = bst;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// --#
// |
inx = imw - br; iny = 0;
inw = br; inh = bt;
outx = ox + iw - bsr; outy = oy;
outw = bsr; outh = bst;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// .--
// #
inx = 0; iny = bt;
inw = bl; inh = imh - bt - bb;
outx = ox; outy = oy + bst;
outw = bsl; outh = ih - bst - bsb;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// .--.
// |##|
if (o->cur->border.fill > EVAS_BORDER_FILL_NONE)
{
inx = bl; iny = bt;
inw = imw - bl - br; inh = imh - bt - bb;
outx = ox + bsl; outy = oy + bst;
outw = iw - bsl - bsr; outh = ih - bst - bsb;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
}
// --.
// #
inx = imw - br; iny = bt;
inw = br; inh = imh - bt - bb;
outx = ox + iw - bsr; outy = oy + bst;
outw = bsr; outh = ih - bst - bsb;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// |
// #--
inx = 0; iny = imh - bb;
inw = bl; inh = bb;
outx = ox; outy = oy + ih - bsb;
outw = bsl; outh = bsb;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// |
// .##
inx = bl; iny = imh - bb;
inw = imw - bl - br; inh = bb;
outx = ox + bsl; outy = oy + ih - bsb;
outw = iw - bsl - bsr; outh = bsb;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
// |
// --#
inx = imw - br; iny = imh - bb;
inw = br; inh = bb;
outx = ox + iw - bsr; outy = oy + ih - bsb;
outw = bsr; outh = bsb;
if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
inx, iny, inw, inh,
outx, outy, outw, outh))
{
is_inside = alpha > 0;
dobreak_h = 1;
dobreak_w = 1;
break;
}
}
idy += idh;
if (dobreak_h) break;
}
idx += idw;
idy = ydy;
if (dobreak_w) break;
}
return is_inside;
}
static int
evas_object_image_has_opaque_rect(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data)
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
if ((obj->map->cur.map) && (obj->map->cur.usemap)) return 0;
if (((o->cur->border.l | o->cur->border.r | o->cur->border.t | o->cur->border.b) != 0) &&
(o->cur->border.fill == EVAS_BORDER_FILL_SOLID) &&
(obj->cur->render_op == EVAS_RENDER_BLEND) &&
(obj->cur->cache.clip.a == 255) &&
(o->cur->fill.x == 0) &&
(o->cur->fill.y == 0) &&
(o->cur->fill.w == obj->cur->geometry.w) &&
(o->cur->fill.h == obj->cur->geometry.h)
) return 1;
return 0;
}
static int
evas_object_image_get_opaque_rect(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data,
Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
{
2014-03-12 07:28:40 -07:00
Evas_Image_Data *o = type_private_data;
if (!o->cur->has_alpha)
{
*x = obj->cur->geometry.x;
*y = obj->cur->geometry.y;
*w = obj->cur->geometry.w;
*h = obj->cur->geometry.h;
}
else if (o->cur->border.fill == EVAS_BORDER_FILL_SOLID)
{
*x = obj->cur->geometry.x + (o->cur->border.l * o->cur->border.scale);
*y = obj->cur->geometry.y + (o->cur->border.t * o->cur->border.scale);
*w = obj->cur->geometry.w - ((o->cur->border.l * o->cur->border.scale)
+ (o->cur->border.r * o->cur->border.scale));
if (*w < 0) *w = 0;
*h = obj->cur->geometry.h - ((o->cur->border.t * o->cur->border.scale)
+ (o->cur->border.b * o->cur->border.scale));
if (*h < 0) *h = 0;
}
else
{
*w = 0;
*h = 0;
}
return 1;
}
static int
evas_object_image_can_map(Evas_Object *obj EINA_UNUSED)
{
return 1;
}
void *
_evas_image_data_convert_internal(Evas_Image_Data *o, void *data, Evas_Colorspace to_cspace)
{
void *out = NULL;
if (!data)
return NULL;
switch (o->cur->cspace)
{
case EVAS_COLORSPACE_ARGB8888:
out = evas_common_convert_argb8888_to(data,
o->cur->image.w,
o->cur->image.h,
o->cur->image.stride >> 2,
o->cur->has_alpha,
to_cspace);
break;
case EVAS_COLORSPACE_RGB565_A5P:
out = evas_common_convert_rgb565_a5p_to(data,
o->cur->image.w,
o->cur->image.h,
o->cur->image.stride >> 1,
o->cur->has_alpha,
to_cspace);
break;
case EVAS_COLORSPACE_YCBCR422601_PL:
out = evas_common_convert_yuv_422_601_to(data,
o->cur->image.w,
o->cur->image.h,
to_cspace);
break;
case EVAS_COLORSPACE_YCBCR422P601_PL:
out = evas_common_convert_yuv_422P_601_to(data,
o->cur->image.w,
o->cur->image.h,
to_cspace);
break;
case EVAS_COLORSPACE_YCBCR420NV12601_PL:
out = evas_common_convert_yuv_420_601_to(data,
o->cur->image.w,
o->cur->image.h,
to_cspace);
break;
case EVAS_COLORSPACE_YCBCR420TM12601_PL:
out = evas_common_convert_yuv_420T_601_to(data,
o->cur->image.w,
o->cur->image.h,
to_cspace);
break;
case EVAS_COLORSPACE_AGRY88:
out = evas_common_convert_agry88_to(data,
o->cur->image.w,
o->cur->image.h,
o->cur->image.stride,
o->cur->has_alpha,
to_cspace);
break;
case EVAS_COLORSPACE_GRY8:
out = evas_common_convert_gry8_to(data,
o->cur->image.w,
o->cur->image.h,
o->cur->image.stride,
o->cur->has_alpha,
to_cspace);
break;
default:
WRN("unknown colorspace: %i\n", o->cur->cspace);
break;
}
return out;
}
static void
evas_object_image_filled_resize_listener(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *einfo EINA_UNUSED)
{
Evas_Image_Data *o = efl_data_scope_get(obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
Eina_Size2D sz;
sz = efl_gfx_entity_size_get(obj);
if (sz.w < 1) sz.w = 1;
if (sz.h < 1) sz.h = 1;
_evas_image_fill_set(obj, o, 0, 0, sz.w, sz.h);
}
Eina_Bool
_evas_object_image_preloading_get(const Evas_Object *eo_obj)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
2018-09-02 23:19:02 -07:00
return o->preload;
}
Evas_Object *
_evas_object_image_video_parent_get(Evas_Object *eo_obj)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
return o->video_surface ? o->pixels->video.parent : NULL;
}
void
_evas_object_image_video_overlay_show(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
if (obj->cur->cache.clip.x != obj->prev->cache.clip.x ||
obj->cur->cache.clip.y != obj->prev->cache.clip.y ||
o->created || !o->video_visible)
o->delayed.video_move = EINA_TRUE;
if (obj->cur->cache.clip.w != obj->prev->cache.clip.w ||
obj->cur->cache.clip.h != obj->prev->cache.clip.h ||
o->created || !o->video_visible)
o->delayed.video_resize = EINA_TRUE;
if (!o->video_visible || o->created)
{
o->delayed.video_show = EINA_TRUE;
o->delayed.video_hide = EINA_FALSE;
}
else
{
/* Cancel dirty on the image */
Eina_Rectangle *r;
o->dirty_pixels = EINA_FALSE;
EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
{
EINA_LIST_FREE(pixi_write->pixel_updates, r)
eina_rectangle_free(r);
}
EINA_COW_PIXEL_WRITE_END(o, pixi_write);
}
o->video_visible = EINA_TRUE;
o->created = EINA_FALSE;
}
void
_evas_object_image_video_overlay_hide(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
if (o->video_visible || o->created)
{
o->delayed.video_hide = EINA_TRUE;
o->delayed.video_show = EINA_FALSE;
}
if (evas_object_is_visible(eo_obj, obj))
o->pixels->video.update_pixels(o->pixels->video.data, eo_obj, &o->pixels->video);
o->video_visible = EINA_FALSE;
o->created = EINA_FALSE;
}
void
_evas_object_image_video_overlay_do(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
Evas_Public_Data *e = obj->layer->evas;
if (o->delayed.video_move)
o->pixels->video.move(o->pixels->video.data, eo_obj, &o->pixels->video,
obj->cur->cache.clip.x + e->framespace.x,
obj->cur->cache.clip.y + e->framespace.y);
if (o->delayed.video_resize)
o->pixels->video.resize(o->pixels->video.data, eo_obj,
&o->pixels->video,
obj->cur->cache.clip.w,
obj->cur->cache.clip.h);
if (o->delayed.video_show)
o->pixels->video.show(o->pixels->video.data, eo_obj, &o->pixels->video);
else if (o->delayed.video_hide)
o->pixels->video.hide(o->pixels->video.data, eo_obj, &o->pixels->video);
o->delayed.video_move = EINA_FALSE;
o->delayed.video_resize = EINA_FALSE;
o->delayed.video_show = EINA_FALSE;
o->delayed.video_hide = EINA_FALSE;
}
void *
_evas_object_image_surface_get(Evas_Object_Protected_Data *obj, Eina_Bool create)
{
Evas_Image_Data *pd = obj->private_data;
if (pd->engine_data &&
(pd->cur->image.w == obj->cur->geometry.w) &&
(pd->cur->image.h == obj->cur->geometry.h))
return pd->engine_data;
if (pd->engine_data)
{
ENFN->image_free(ENC, pd->engine_data);
pd->engine_data = NULL;
}
if (!create) return pd->engine_data;
// FIXME: alpha forced to 1 for now, need to figure out Evas alpha here
EINA_COW_IMAGE_STATE_WRITE_BEGIN(pd, state_write)
{
pd->engine_data = ENFN->image_map_surface_new(ENC,
obj->cur->geometry.w,
obj->cur->geometry.h,
1);
state_write->image.w = obj->cur->geometry.w;
state_write->image.h = obj->cur->geometry.h;
}
EINA_COW_IMAGE_STATE_WRITE_END(pd, state_write);
return pd->engine_data;
}
EOLIAN static void
2017-07-24 22:42:54 -07:00
_efl_canvas_image_internal_efl_object_debug_name_override(Eo *eo_obj, Evas_Image_Data *o, Eina_Strbuf *sb)
{
efl_debug_name_override(efl_super(eo_obj, MY_CLASS), sb);
if (o->cur->f)
2017-07-24 22:42:54 -07:00
{
const char *fname = eina_file_filename_get(o->cur->f);
2017-07-24 22:42:54 -07:00
eina_strbuf_append_printf(sb, ":file='%s',key='%s'", fname, o->cur->key);
}
else if (o->pixels && o->pixels->func.get_pixels)
{
eina_strbuf_append_printf(sb, ":get_pixels=%p:dirty=%d",
o->pixels->func.get_pixels, o->dirty_pixels);
}
else if (o->cur->source)
{
eina_strbuf_append_printf(sb, ":proxy_source=%p", o->cur->source);
}
else
{
eina_strbuf_append_printf(sb, ":unknown_image");
}
}
#define EFL_CANVAS_IMAGE_INTERNAL_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_canvas_image_internal_efl_object_dbg_info_get)
#include "canvas/efl_canvas_image_internal.eo.c"
/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/