evas filters: Fix maps with filtered snapshots

Another wonder of evas render... maps, clips, snapshots, filters...
This fixes animations with windows that have a snapshot decoration.
This commit is contained in:
Jean-Philippe Andre 2017-04-04 14:28:29 +09:00
parent b5a5f61cd6
commit 4cbff5f0ea
8 changed files with 136 additions and 30 deletions

View File

@ -25,6 +25,24 @@ static const char *filter =
"print ('Evaluating filter: ' .. input.width .. 'x' .. input.height)"
;
static inline void
_efl_key_int_set(Eo *obj, const char *key, int val)
{
Eina_Value *v = eina_value_new(EINA_VALUE_TYPE_INT);
eina_value_set(v, val);
efl_key_value_set(obj, key, v);
}
static inline int
_efl_key_int_get(Eo *obj, const char *key)
{
Eina_Value *v = efl_key_value_get(obj, key);
int val;
if (!eina_value_get(v, &val)) return 0;
return val;
}
static inline Eo *
_image_create(Eo *win, const char *path)
{
@ -102,6 +120,49 @@ _close(void *data, const Efl_Event *ev EINA_UNUSED)
efl_del(win);
}
static void
_map_do(void *data, const Efl_Event *ev EINA_UNUSED)
{
Eo *snap = data;
int x, y, w, h;
// Prevent recursive infinite loop :(
static int here = 0;
if (here) return;
here = 1;
efl_gfx_map_populate(snap, 0);
efl_gfx_geometry_get(snap, &x, &y, &w, &h);
efl_gfx_map_zoom(snap, 0.8, 0.8, x + w/2., y + h/2.);
efl_gfx_map_rotate(snap, 45., x + w/2., y + h/2.);
efl_gfx_map_enable_set(snap, EINA_TRUE);
here = 0;
}
static void
_toggle_map(void *data, const Efl_Event *ev EINA_UNUSED)
{
Eo *win = data;
Eo *snap;
snap = efl_key_wref_get(win, "snap");
if (!_efl_key_int_get(snap, "map"))
{
_efl_key_int_set(snap, "map", 1);
_map_do(snap, NULL);
efl_event_callback_add(snap, EFL_GFX_EVENT_RESIZE, _map_do, snap);
efl_event_callback_add(snap, EFL_GFX_EVENT_MOVE, _map_do, snap);
}
else
{
_efl_key_int_set(snap, "map", 0);
efl_event_callback_del(snap, EFL_GFX_EVENT_RESIZE, _map_do, snap);
efl_event_callback_del(snap, EFL_GFX_EVENT_MOVE, _map_do, snap);
efl_gfx_map_enable_set(snap, EINA_FALSE);
}
}
void
test_evas_snapshot(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
@ -191,6 +252,14 @@ test_evas_snapshot(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *e
efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _save_image, win),
efl_gfx_visible_set(efl_added, 1));
efl_add(ELM_BUTTON_CLASS, win,
efl_text_set(efl_added, "Map"),
efl_gfx_size_hint_align_set(efl_added, -1.0, -1.0),
efl_gfx_size_hint_weight_set(efl_added, 1.0, 0.0),
efl_pack(box, efl_added),
efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _toggle_map, win),
efl_gfx_visible_set(efl_added, 1));
efl_add(ELM_BUTTON_CLASS, win,
efl_text_set(efl_added, "Close"),
efl_gfx_size_hint_align_set(efl_added, -1.0, -1.0),

View File

@ -266,6 +266,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
Eina_Bool ok;
void *previous = pd->data->output;
Evas_Object_Filter_Data *fcow;
Eina_Bool use_map = EINA_FALSE;
Evas_Filter_Padding pad;
W = obj->cur->geometry.w;
@ -288,6 +289,15 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
else
ENFN->context_multiplier_unset(output, context);
if (obj->map->cur.usemap && obj->map->cur.map && (obj->map->cur.map->count >= 4))
{
int iw, ih;
use_map = EINA_TRUE;
ENFN->image_size_get(ENDT, previous, &iw, &ih);
evas_object_map_update(eo_obj, x, y, iw, ih, iw, ih);
}
if (!pd->data->chain)
{
Evas_Filter_Program *pgm;
@ -348,12 +358,20 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
if (!redraw)
{
// Render this image only
ENFN->image_draw(ENDT, context,
surface, previous,
0, 0, W, H, // src
X + x, Y + y, W, H, // dst
EINA_FALSE, // smooth
do_async);
if (use_map)
{
ENFN->image_map_draw(ENDT, context, surface, previous,
obj->map->spans, EINA_TRUE, 0, do_async);
}
else
{
ENFN->image_draw(ENDT, context,
surface, previous,
0, 0, W, H, // src
X + x, Y + y, W, H, // dst
EINA_FALSE, // smooth
do_async);
}
return EINA_TRUE;
}
}
@ -427,7 +445,8 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
// Allocate all buffers now
evas_filter_context_buffers_allocate_all(filter);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
evas_filter_target_set(filter, context, surface, X + x, Y + y,
use_map ? obj->map->spans : NULL);
// Request rendering from the object itself (child class)
evas_filter_program_padding_get(pd->data->chain, &pad, NULL);

View File

@ -19,7 +19,7 @@ static void evas_object_image_render(Evas_Object *eo_obj, Evas_Object_Protected_
int x, int y, Eina_Bool do_async);
static void _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *output, void *context, void *surface,
int x, int y, int l, int t, int r, int b, Eina_Bool do_async);
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,
@ -1726,12 +1726,6 @@ _image_has_border(Evas_Object_Protected_Data *obj EINA_UNUSED, Evas_Image_Data *
o->cur->border.b || (o->cur->border.fill == 0);
}
static inline Eina_Bool
_image_has_map(Evas_Object_Protected_Data *obj, Evas_Image_Data *o EINA_UNUSED)
{
return ((obj->map->cur.map) && (obj->map->cur.map->count > 3) && (obj->map->cur.usemap));
}
static inline Eina_Bool
_image_is_filled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
@ -1765,8 +1759,7 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
output = ENDT;
// FIXME: In GL we could use the image even if scaled
if (!_image_has_border(obj, o) && !_image_has_map(obj, o) && _image_is_filled(obj, o)
&& !_image_is_scaled(obj, o))
if (!_image_has_border(obj, o) && _image_is_filled(obj, o) && !_image_is_scaled(obj, o))
{
int imagew, imageh, uvw, uvh;
@ -1802,7 +1795,7 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
_evas_image_render(eo_obj, obj, output, ctx, surface,
x + l - obj->cur->geometry.x,
y + t - obj->cur->geometry.y,
l, t, r, b, do_async);
l, t, r, b, EINA_TRUE, do_async);
ENFN->context_free(output, ctx);
@ -1892,7 +1885,7 @@ evas_object_image_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, v
return;
}
_evas_image_render(eo_obj, obj, output, context, surface, x, y, 0, 0, 0, 0, do_async);
_evas_image_render(eo_obj, obj, output, context, surface, x, y, 0, 0, 0, 0, EINA_FALSE, do_async);
}
void *
@ -2008,7 +2001,7 @@ _evas_image_pixels_get(Eo *eo_obj, Evas_Object_Protected_Data *obj,
static void
_evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *output, void *context, void *surface, int x, int y,
int l, int t, int r, int b, Eina_Bool do_async)
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;
@ -2023,7 +2016,8 @@ _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
if (ENFN->context_clip_get(ENDT, context, NULL, NULL, &cw, &ch) && (!cw || !ch))
return;
if ((obj->map->cur.map) && (obj->map->cur.map->count > 3) && (obj->map->cur.usemap))
if (!skip_map && (obj->map->cur.map) && (obj->map->cur.map->count > 3)
&& (obj->map->cur.usemap))
{
evas_object_map_update(eo_obj, x, y, imagew, imageh, uvw, uvh);

View File

@ -13493,7 +13493,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
obj->cur->cache.clip.b, obj->cur->cache.clip.a);
evas_filter_context_proxy_render_all(ctx, eo_obj, EINA_FALSE);
evas_filter_context_buffers_allocate_all(ctx);
evas_filter_target_set(ctx, context, surface, target.x, target.y);
evas_filter_target_set(ctx, context, surface, target.x, target.y, NULL);
ti->gfx_filter->ctx = ctx;
ti->gfx_filter->do_async = do_async;

View File

@ -2797,7 +2797,7 @@ _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap
}
}
if (snap->snapshot_no_obscure)
if (snap->snapshot_no_obscure || _evas_render_has_map(snap))
goto skip_obscures;
tiler = eina_tiler_new(w, h);
@ -2881,6 +2881,8 @@ evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *evas,
OBJ_ARRAY_PUSH(&evas->temporary_objects, obj);
if (above_top) continue;
if (obj->cur->snapshot && !evas_object_is_opaque(obj->object, obj))
continue;
/* reset the background of the area if needed (using cutout and engine alpha flag to help) */
if (alpha && !skip_cutouts)
@ -2985,7 +2987,11 @@ evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *evas,
obj2 = eina_array_data_get(&evas->temporary_objects, j);
if (obj2 == top) above_top = EINA_TRUE;
if (above_top && obj2->cur->snapshot) continue;
if (obj2->cur->snapshot)
{
if (above_top) continue;
if (!evas_object_is_opaque(obj2->object, obj2)) continue;
}
#if 1
if (
RECTS_INTERSECT

View File

@ -1489,7 +1489,7 @@ evas_filter_context_obscured_region_set(Evas_Filter_Context *ctx, Eina_Rectangle
/* Final target */
Eina_Bool
evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
void *surface, int x, int y)
void *surface, int x, int y, const RGBA_Map *map)
{
void *mask = NULL;
@ -1509,11 +1509,20 @@ evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
ctx->target.color_use = EINA_FALSE;
ctx->target.rop = ENFN->context_render_op_get(ENDT, draw_context);
free(ctx->target.map);
if (!map) ctx->target.map = NULL;
else
{
size_t len = sizeof(RGBA_Map) + sizeof(RGBA_Map_Point) * (map->count - 1);
ctx->target.map = malloc(len);
memcpy(ctx->target.map, map, len);
}
ENFN->context_clip_image_get
(ENDT, draw_context, &mask, &ctx->target.mask_x, &ctx->target.mask_y);
if (ctx->target.mask)
ctx->evas->engine.func->image_free(ctx->evas->engine.data.output, ctx->target.mask);
ctx->target.mask = mask;
ctx->target.mask = mask; // FIXME: why no ref???
return EINA_TRUE;
}
@ -1558,10 +1567,18 @@ _filter_target_render(Evas_Filter_Context *ctx)
}
ENFN->context_render_op_set(ENDT, drawctx, ctx->target.rop);
ENFN->image_draw(ENDT, drawctx, surface, image,
0, 0, src->w, src->h,
ctx->target.x, ctx->target.y, src->w, src->h,
EINA_TRUE, EINA_FALSE);
if (ctx->target.map)
{
ENFN->image_map_draw(ENDT, drawctx, surface, image,
ctx->target.map, EINA_TRUE, 0, EINA_FALSE);
}
else
{
ENFN->image_draw(ENDT, drawctx, surface, image,
0, 0, src->w, src->h,
ctx->target.x, ctx->target.y, src->w, src->h,
EINA_TRUE, EINA_FALSE);
}
ENFN->context_free(ENDT, drawctx);
evas_ector_buffer_engine_image_release(src->buffer, image);

View File

@ -153,6 +153,7 @@ struct _Evas_Filter_Context
void *mask; // mask
int mask_x, mask_y; // mask offset
Evas_Render_Op rop;
RGBA_Map *map;
Eina_Bool clip_use : 1;
Eina_Bool color_use : 1;
} target;

View File

@ -164,7 +164,7 @@ Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context
Eina_Bool evas_filter_context_run(Evas_Filter_Context *ctx);
Eina_Bool evas_filter_font_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid, Evas_Font_Set *font, int x, int y, Evas_Text_Props *text_props, Eina_Bool do_async);
Eina_Bool evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context, void *surface, int x, int y);
Eina_Bool evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context, void *surface, int x, int y, const RGBA_Map *map);
// utility function
void _evas_filter_source_hash_free_cb(void *data);