jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=4cbff5f0ea011e93a7b2ea6db202dbd8ddf700c8
commit 4cbff5f0ea011e93a7b2ea6db202dbd8ddf700c8 Author: Jean-Philippe Andre <jp.an...@samsung.com> Date: Tue Apr 4 14:28:29 2017 +0900 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. --- src/bin/elementary/test_evas_snapshot.c | 69 +++++++++++++++++++++++++++++ src/lib/evas/canvas/evas_filter_mixin.c | 33 +++++++++++--- src/lib/evas/canvas/evas_object_image.c | 20 +++------ src/lib/evas/canvas/evas_object_textblock.c | 2 +- src/lib/evas/canvas/evas_render.c | 10 ++++- src/lib/evas/filters/evas_filter.c | 29 +++++++++--- src/lib/evas/filters/evas_filter_private.h | 1 + src/lib/evas/include/evas_filter.h | 2 +- 8 files changed, 136 insertions(+), 30 deletions(-) diff --git a/src/bin/elementary/test_evas_snapshot.c b/src/bin/elementary/test_evas_snapshot.c index 845c95c..75ca1ce 100644 --- a/src/bin/elementary/test_evas_snapshot.c +++ b/src/bin/elementary/test_evas_snapshot.c @@ -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) { @@ -192,6 +253,14 @@ test_evas_snapshot(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *e 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), efl_gfx_size_hint_weight_set(efl_added, 1.0, 0.0), diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index 1ac5e1c..d9ada4f 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -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); diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index 0205ed6..41ed31d 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -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, @@ -1727,12 +1727,6 @@ _image_has_border(Evas_Object_Protected_Data *obj EINA_UNUSED, Evas_Image_Data * } 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) { if (o->filled) return EINA_TRUE; @@ -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); diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index 8032abf..f65624f 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -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; diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index 02209f4..5f82dd5 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -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 diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index e5391f2..c9ce182 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -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); diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index 6896ff8..01cda48 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -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; diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index 3c20aa0..6972159 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -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); --