From 530399acdea9406f5eaaf32463f3c90ca62b7905 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Thu, 23 Mar 2017 15:55:41 +0900 Subject: [PATCH] evas filters: Force redraw of snapshot if cutout shrank The situation is clearly visible in the Snapshot test case: increase the radius and a red glow would appear. This is because the snapshot object was not marked as needing redraw and so had no pixels under the opaque rectangle. --- src/lib/evas/canvas/evas_filter_mixin.c | 70 ++++++++++++++++++++++----------- src/lib/evas/canvas/evas_render.c | 51 +++++++++--------------- src/lib/evas/include/evas_inline.x | 12 ++++++ src/lib/evas/include/evas_private.h | 2 +- 4 files changed, 79 insertions(+), 56 deletions(-) diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index f3ed146..1a74cd8 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -27,6 +27,7 @@ struct _Evas_Object_Filter_Data Eina_Hash *sources; // Evas_Filter_Proxy_Binding Eina_Inlist *data; // Evas_Filter_Data_Binding Eina_Rectangle prev_obscured, obscured; + Evas_Filter_Padding prev_padding, padding; void *output; struct { struct { @@ -283,36 +284,31 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, if (!pd->data->chain) { Evas_Filter_Program *pgm; + Eina_Bool invalid; pgm = evas_filter_program_new(pd->data->name, alpha); evas_filter_program_source_set_all(pgm, pd->data->sources); evas_filter_program_data_set_all(pgm, pd->data->data); _evas_filter_state_set_internal(pgm, pd); - if (!evas_filter_program_parse(pgm, pd->data->code)) + invalid = !evas_filter_program_parse(pgm, pd->data->code); + if (invalid) { ERR("Filter program parsing failed"); evas_filter_program_del(pgm); - - if (!pd->data->invalid) - { - fcow = FCOW_BEGIN(pd); - fcow->invalid = EINA_TRUE; - FCOW_END(fcow, pd); - } - - return EINA_FALSE; + pgm = NULL; } fcow = FCOW_BEGIN(pd); + if (!invalid) evas_filter_program_padding_get(pgm, NULL, &fcow->padding); fcow->chain = pgm; - fcow->invalid = EINA_FALSE; + fcow->invalid = invalid; FCOW_END(fcow, pd); + if (invalid) return EINA_FALSE; } else if (previous && !pd->data->changed) { - Eina_Bool redraw; + Eina_Bool redraw = EINA_TRUE; - redraw = _evas_filter_state_set_internal(pd->data->chain, pd); - if (redraw) + if (_evas_filter_state_set_internal(pd->data->chain, pd)) DBG("Filter redraw by state change!"); else if (obj->changed) DBG("Filter redraw by object content change!"); @@ -441,6 +437,8 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, fcow->changed = EINA_FALSE; fcow->async = do_async; fcow->prev_obscured = fcow->obscured; + fcow->prev_padding = fcow->padding; + fcow->padding = pad; fcow->invalid = EINA_FALSE; FCOW_END(fcow, pd); @@ -470,6 +468,7 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_program_set(Eo *eo_obj, Evas_F Evas_Object_Protected_Data *obj; Evas_Filter_Program *pgm = NULL; Evas_Object_Filter_Data *fcow; + Eina_Bool invalid = pd->data->invalid; Eina_Bool alpha; obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); @@ -494,16 +493,21 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_program_set(Eo *eo_obj, Evas_F evas_filter_program_source_set_all(pgm, fcow->sources); evas_filter_program_data_set_all(pgm, fcow->data); _evas_filter_state_set_internal(pgm, pd); - if (!evas_filter_program_parse(pgm, code)) + invalid = !evas_filter_program_parse(pgm, code); + if (invalid) { ERR("Parsing failed!"); evas_filter_program_del(pgm); pgm = NULL; } + else + { + evas_filter_program_padding_get(pgm, NULL, &fcow->padding); + } } fcow->chain = pgm; fcow->changed = EINA_TRUE; - fcow->invalid = (pgm == NULL); + fcow->invalid = invalid; eina_stringshare_replace(&fcow->code, code); } FCOW_END(fcow, pd); @@ -526,6 +530,7 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_source_set(Eo *eo_obj, Evas_Fi Evas_Filter_Proxy_Binding *pb, *pb_old = NULL; Evas_Object_Protected_Data *source = NULL; Evas_Object_Filter_Data *fcow = NULL; + Eina_Bool invalid = pd->data->invalid; obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); if (eo_source) @@ -589,14 +594,15 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_source_set(Eo *eo_obj, Evas_Fi eina_hash_add(fcow->sources, pb->name, pb); evas_filter_program_source_set_all(fcow->chain, fcow->sources); evas_filter_program_data_set_all(fcow->chain, fcow->data); - evas_filter_program_parse(fcow->chain, fcow->code); + invalid = !evas_filter_program_parse(fcow->chain, fcow->code); + if (!invalid) evas_filter_program_padding_get(fcow->chain, NULL, &fcow->padding); // Update object update: if (fcow) { fcow->changed = EINA_TRUE; - fcow->invalid = EINA_FALSE; + fcow->invalid = invalid; FCOW_END(fcow, pd); } @@ -755,6 +761,7 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_data_set(Eo *eo_obj, Evas_Filt { Evas_Filter_Data_Binding *db, *found = NULL; Evas_Object_Filter_Data *fcow; + Eina_Bool invalid = pd->data->invalid; EINA_SAFETY_ON_NULL_RETURN(pd->data); EINA_SAFETY_ON_NULL_RETURN(name); @@ -789,12 +796,13 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_data_set(Eo *eo_obj, Evas_Filt db->execute = execute; fcow->data = eina_inlist_append(fcow->data, EINA_INLIST_GET(db)); } - fcow->invalid = EINA_FALSE; if (fcow->chain) { evas_filter_program_data_set_all(fcow->chain, fcow->data); - evas_filter_program_parse(fcow->chain, fcow->code); + invalid = !evas_filter_program_parse(fcow->chain, fcow->code); + if (!invalid) evas_filter_program_padding_get(fcow->chain, NULL, &fcow->padding); } + fcow->invalid = invalid; fcow->changed = 1; } FCOW_END(fcow, pd); @@ -832,15 +840,18 @@ _efl_canvas_filter_internal_filter_output_buffer_get(Eo *obj EINA_UNUSED, Evas_F return pd->data->output; } -void +Eina_Bool _evas_filter_obscured_region_set(Evas_Object_Protected_Data *obj, const Eina_Rectangle rect) { - Evas_Filter_Data *pd; Evas_Object_Filter_Data *fcow; + Evas_Filter_Data *pd; + Eina_Rectangle prev; pd = efl_data_scope_get(obj->object, MY_CLASS); - if (!pd->data) return; + if (!pd->data) return EINA_FALSE; + + prev = pd->data->prev_obscured; fcow = FCOW_BEGIN(pd); if ((rect.w <= 0) || (rect.h <= 0)) @@ -853,6 +864,19 @@ _evas_filter_obscured_region_set(Evas_Object_Protected_Data *obj, fcow->obscured.h = rect.h; } FCOW_END(fcow, pd); + + // Snapshot objects need to be redrawn if the padding has increased + if ((pd->data->prev_padding.l < pd->data->padding.l) || + (pd->data->prev_padding.r < pd->data->padding.r) || + (pd->data->prev_padding.t < pd->data->padding.t) || + (pd->data->prev_padding.b < pd->data->padding.b)) + return EINA_TRUE; + + // Snapshot objects need to be redrawn if the obscured region has shrank + if (!_evas_eina_rectangle_inside(&prev, &pd->data->obscured)) + return EINA_TRUE; + + return EINA_FALSE; } void diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index cd63a63..5c7720c 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -2747,18 +2747,6 @@ _is_obj_in_rect(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, } #endif -static inline Eina_Bool -_rectangle_inside(Eina_Rectangle *big, Eina_Rectangle *small) -{ - Eina_Rectangle inter = *big; - - if (!eina_rectangle_intersection(&inter, small)) - return EINA_FALSE; - if ((inter.w == small->w) && (inter.h == small->h)) - return EINA_TRUE; - return EINA_FALSE; -} - static void _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap) { @@ -2769,16 +2757,23 @@ _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap const int h = snap->cur->geometry.h; Evas_Object_Protected_Data *obj; Evas_Active_Entry *ent; - Eina_Rectangle snap_rect = { x, y, w, h }; + Eina_Rectangle snap_clip, snap_rect = { x, y, w, h }; Eina_Rectangle opaque = {}; void *surface; // FIXME: Use evas' standard rectangle logic instead of this bad algo + // FIXME: This walks ALL the objects in the canvas to find the opaque region // TODO: Improve opaque region support, maybe have more than one // TODO: Also list redraw regions (partial updates) if (!evas_object_is_visible(snap->object, snap)) return; + evas_object_clip_recalc(snap); + snap_clip.x = snap->cur->cache.clip.x; + snap_clip.y = snap->cur->cache.clip.y; + snap_clip.w = snap->cur->cache.clip.w; + snap_clip.h = snap->cur->cache.clip.h; + surface = _evas_object_image_surface_get(snap, EINA_FALSE); if (!surface) need_redraw = EINA_TRUE; if (snap->changed) add_rect = EINA_TRUE; @@ -2788,7 +2783,6 @@ _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap obj = ent->obj; if (obj == snap) { - if (!need_redraw) break; above = EINA_TRUE; continue; } @@ -2811,35 +2805,28 @@ _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap }; if ((opaque.w * opaque.h) < (cur.w * cur.h)) - { - opaque = cur; - continue; - } - - if (!eina_rectangles_intersect(&snap_rect, &cur)) + opaque = cur; + else if (!eina_rectangles_intersect(&snap_rect, &cur)) continue; - - if (!opaque.w || !opaque.h) + else if (!opaque.w || !opaque.h) opaque = cur; - else if (_rectangle_inside(&cur, &opaque)) + else if (_evas_eina_rectangle_inside(&cur, &opaque)) opaque = cur; - //else if (!_rectangle_inside(&opaque, &cur)) + //else if (!_evas_eina_rectangle_inside(&opaque, &cur)) + + if (_evas_eina_rectangle_inside(&opaque, &snap_clip)) + return; } } } - _evas_filter_obscured_region_set(snap, opaque); + need_redraw |= _evas_filter_obscured_region_set(snap, opaque); snap->snapshot_needs_redraw |= need_redraw; if (add_rect || need_redraw) { - // FIXME: Only add necessary rects - // Note that with filters this is extremely tricky: a simple color - // change would mean redraw all. Also blurs, displace, etc... need - // to expand by the cutout_margin (filter padding). - ENFN->output_redraws_rect_add(ENDT, - snap->cur->geometry.x, snap->cur->geometry.y, - snap->cur->geometry.w, snap->cur->geometry.h); + // FIXME: Only add necessary rects (if object itself hasn't changed) + ENFN->output_redraws_rect_add(ENDT, x, y, w, h); } } diff --git a/src/lib/evas/include/evas_inline.x b/src/lib/evas/include/evas_inline.x index d7aa37a..37cf44d 100644 --- a/src/lib/evas/include/evas_inline.x +++ b/src/lib/evas/include/evas_inline.x @@ -327,6 +327,18 @@ evas_common_draw_context_cache_update(RGBA_Draw_Context *dc) } } +static inline Eina_Bool +_evas_eina_rectangle_inside(const Eina_Rectangle *big, const Eina_Rectangle *small) +{ + Eina_Rectangle inter = *big; + + if (!eina_rectangle_intersection(&inter, small)) + return EINA_FALSE; + if ((inter.w == small->w) && (inter.h == small->h)) + return EINA_TRUE; + return EINA_FALSE; +} + #define _EVAS_COLOR_CLAMP(x, y) do { \ if (x > y) { x = y; bad = 1; } \ if (x < 0) { x = 0; bad = 1; } } while (0) diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 3571cd6..33e5a45 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -2012,7 +2012,7 @@ Eina_Bool evas_vg_loader_svg(Evas_Object *vg, const Eina_File *f, const char *ke void *_evas_object_image_surface_get(Evas_Object_Protected_Data *obj, Eina_Bool create); void _evas_filter_radius_get(Evas_Object_Protected_Data *obj, int *l, int *r, int *t, int *b); -void _evas_filter_obscured_region_set(Evas_Object_Protected_Data *obj, const Eina_Rectangle rect); +Eina_Bool _evas_filter_obscured_region_set(Evas_Object_Protected_Data *obj, const Eina_Rectangle rect); Eina_Bool _evas_image_proxy_source_clip_get(const Eo *eo_obj); void _evas_focus_dispatch_event(Evas_Object_Protected_Data *obj, -- 2.7.4