From 0f424acb6ed52fe6edf6e292e731ea2972005f20 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Tue, 1 May 2012 07:31:42 +0000 Subject: [PATCH] evas: and for this nice international hollyday let me introduce a dynamic bounding box for smart object. This make it possible to use the object tree to reduce the number of object, we need to explore to know what is under a specific position. First used by propagation event code. That code is now 4 times faster, enjoy ! As a side cost evas_object_move goes from 925 to 980 valgrind cycle on my computer, so not something you will notice. NOTE: if you notice any breakage regarding event propagation, map, cats, minor or major, please report to me ! I hope I didn't loose my mojo, with such a scary change, I have a big chance to get it back ! SVN revision: 70564 --- legacy/evas/ChangeLog | 4 + legacy/evas/NEWS | 1 + legacy/evas/src/lib/canvas/evas_clip.c | 7 +- legacy/evas/src/lib/canvas/evas_events.c | 11 +- legacy/evas/src/lib/canvas/evas_map.c | 29 +++ legacy/evas/src/lib/canvas/evas_object_main.c | 167 ++++++++++++++++++ legacy/evas/src/lib/include/evas_private.h | 3 + 7 files changed, 218 insertions(+), 4 deletions(-) diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog index 84a95f584b..4246cc0e36 100644 --- a/legacy/evas/ChangeLog +++ b/legacy/evas/ChangeLog @@ -721,3 +721,7 @@ * Add missing files in the tarballs. +2012-05-01 Cedric Bail + + * Compute limited bounding box for Smart object. + * Use bounding box to reduce the number of object explored during event propagation. diff --git a/legacy/evas/NEWS b/legacy/evas/NEWS index a1ac059930..6122a837d6 100644 --- a/legacy/evas/NEWS +++ b/legacy/evas/NEWS @@ -5,6 +5,7 @@ Changes since Evas 1.2.0: Improvements: * Lock less font rendering. + * Reduce cost of propagating event by limiting the object we explore by using a bouncing box. Fixes: * Add missing files in the tarball. diff --git a/legacy/evas/src/lib/canvas/evas_clip.c b/legacy/evas/src/lib/canvas/evas_clip.c index 1ae2f73e57..435a0ffbaa 100644 --- a/legacy/evas/src/lib/canvas/evas_clip.c +++ b/legacy/evas/src/lib/canvas/evas_clip.c @@ -219,7 +219,12 @@ evas_object_clip_set(Evas_Object *obj, Evas_Object *clip) } obj->cur.clipper = clip; clip->clip.clipees = eina_list_append(clip->clip.clipees, obj); - if (clip->clip.clipees) clip->cur.have_clipees = 1; + if (clip->clip.clipees) + { + clip->cur.have_clipees = 1; + if (clip->changed) + evas_object_update_bounding_box(clip); + } /* If it's NOT a rectangle set the mask bits too */ /* FIXME: Optmz ths chck */ diff --git a/legacy/evas/src/lib/canvas/evas_events.c b/legacy/evas/src/lib/canvas/evas_events.c index 1ee8388df1..26fb83fec0 100644 --- a/legacy/evas/src/lib/canvas/evas_events.c +++ b/legacy/evas/src/lib/canvas/evas_events.c @@ -73,9 +73,14 @@ _evas_event_object_list_raw_in_get(Evas *e, Eina_List *in, } else { - in = _evas_event_object_list_in_get - (e, in, evas_object_smart_members_get_direct(obj), - stop, x, y, &norep); + if (obj->child_has_map || + (obj->cur.bounding_box.x <= x && + obj->cur.bounding_box.x + obj->cur.bounding_box.w >= x && + obj->cur.bounding_box.y <= y && + obj->cur.bounding_box.y + obj->cur.bounding_box.h >= y)) + in = _evas_event_object_list_in_get + (e, in, evas_object_smart_members_get_direct(obj), + stop, x, y, &norep); } if (norep) { diff --git a/legacy/evas/src/lib/canvas/evas_map.c b/legacy/evas/src/lib/canvas/evas_map.c index 0dbad30ce0..46ac024bbf 100644 --- a/legacy/evas/src/lib/canvas/evas_map.c +++ b/legacy/evas/src/lib/canvas/evas_map.c @@ -365,9 +365,27 @@ evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y) return evas_map_coords_get(m, x, y, NULL, NULL, 0); } +static Eina_Bool +_evas_object_map_parent_check(Evas_Object *parent) +{ + const Eina_Inlist *list; + const Evas_Object *o; + + if (!parent) return EINA_FALSE; + + list = evas_object_smart_members_get_direct(parent->smart.parent); + EINA_INLIST_FOREACH(list, o) + if (o->cur.usemap) break ; + if (o) return EINA_FALSE; /* Still some child have a map enable */ + parent->child_has_map = EINA_FALSE; + _evas_object_map_parent_check(parent->smart.parent); + return EINA_TRUE; +} + EAPI void evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled) { + Evas_Object *parents; MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); return; MAGIC_CHECK_END(); @@ -406,6 +424,17 @@ evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled) evas_object_change(obj); if (!obj->changed_pchange) obj->changed_pchange = pchange; obj->changed_map = EINA_TRUE; + + if (enabled) + { + for (parents = obj->smart.parent; parents; parents = parents->smart.parent) + parents->child_has_map = EINA_TRUE; + } + else + { + if (_evas_object_map_parent_check(obj->smart.parent)) + evas_object_update_bounding_box(obj); + } } EAPI Eina_Bool diff --git a/legacy/evas/src/lib/canvas/evas_object_main.c b/legacy/evas/src/lib/canvas/evas_object_main.c index 33665d6e0b..f31e7bd9db 100644 --- a/legacy/evas/src/lib/canvas/evas_object_main.c +++ b/legacy/evas/src/lib/canvas/evas_object_main.c @@ -449,6 +449,169 @@ evas_object_del(Evas_Object *obj) evas_object_change(obj); } +void +evas_object_update_bounding_box(Evas_Object *obj) +{ + Eina_Bool propagate = EINA_FALSE; + Evas_Coord x, y, w, h; + Evas_Coord px, py, pw, ph; + Eina_Bool clip; + + if (!obj->smart.parent) return ; + if (obj->child_has_map) return ; /* Disable bounding box computation for this object and its parent */ + /* We could also remove object that are not visible from the bounding box, use the clipping information + to reduce the bounding of the object they are clipping, but for the moment this will do it's jobs */ + clip = !!obj->clip.clipees; + + if (obj->smart.smart) + { + x = obj->cur.bounding_box.x; + y = obj->cur.bounding_box.y; + w = obj->cur.bounding_box.w; + h = obj->cur.bounding_box.h; + px = obj->prev.bounding_box.x; + py = obj->prev.bounding_box.y; + pw = obj->prev.bounding_box.w; + ph = obj->prev.bounding_box.h; + } + else + { + x = obj->cur.geometry.x; + y = obj->cur.geometry.y; + w = obj->cur.geometry.w; + h = obj->cur.geometry.h; + px = obj->prev.geometry.x; + py = obj->prev.geometry.y; + pw = obj->prev.geometry.w; + ph = obj->prev.geometry.h; + } + + /* Update left limit */ + if (!clip && x < obj->smart.parent->cur.bounding_box.x) + { + obj->smart.parent->cur.bounding_box.w += obj->smart.parent->cur.bounding_box.x - x; + obj->smart.parent->cur.bounding_box.x = x; + propagate = EINA_TRUE; + } + else if ((px == obj->smart.parent->cur.bounding_box.x && x > obj->smart.parent->cur.bounding_box.x) + || (clip && x == obj->smart.parent->cur.bounding_box.x)) + { + const Eina_Inlist *list; + const Evas_Object *o; + Evas_Coord minx = clip ? obj->layer->evas->output.w : x; + + list = evas_object_smart_members_get_direct(obj->smart.parent); + EINA_INLIST_FOREACH(list, o) + { + Evas_Coord tx = o->smart.smart ? o->cur.bounding_box.x : o->cur.geometry.x; + + if (!o->clip.clipees && tx < minx) minx = tx; + } + + if (minx != obj->smart.parent->cur.bounding_box.x) + { + obj->smart.parent->cur.bounding_box.w += obj->smart.parent->cur.bounding_box.x - minx; + obj->smart.parent->cur.bounding_box.x = minx; + propagate = EINA_TRUE; + } + } + + /* Update top limit */ + if (y < obj->smart.parent->cur.bounding_box.y) + { + obj->smart.parent->cur.bounding_box.h += obj->smart.parent->cur.bounding_box.x - x; + obj->smart.parent->cur.bounding_box.y = y; + propagate = EINA_TRUE; + } + else if ((py == obj->smart.parent->cur.bounding_box.y && y > obj->smart.parent->cur.bounding_box.y) + || (clip && y == obj->smart.parent->cur.bounding_box.y)) + { + const Eina_Inlist *list; + const Evas_Object *o; + Evas_Coord miny = clip ? obj->layer->evas->output.h : y; + + list = evas_object_smart_members_get_direct(obj->smart.parent); + EINA_INLIST_FOREACH(list, o) + { + Evas_Coord ty = o->smart.smart ? o->cur.bounding_box.y : o->cur.geometry.y; + + if (!o->clip.clipees && ty < miny) miny = ty; + } + + if (miny != obj->smart.parent->cur.bounding_box.y) + { + obj->smart.parent->cur.bounding_box.h += obj->smart.parent->cur.bounding_box.y - miny; + obj->smart.parent->cur.bounding_box.y = miny; + propagate = EINA_TRUE; + } + } + + /* Update right limit */ + if (x + w > obj->smart.parent->cur.bounding_box.x + obj->smart.parent->cur.bounding_box.w) + { + obj->smart.parent->cur.bounding_box.w = x + w - obj->smart.parent->cur.bounding_box.x; + propagate = EINA_TRUE; + } + else if ((px + pw == obj->smart.parent->cur.bounding_box.x + obj->smart.parent->cur.bounding_box.w && + x + w < obj->smart.parent->cur.bounding_box.x + obj->smart.parent->cur.bounding_box.w) + || (clip && x + w == obj->smart.parent->cur.bounding_box.x + obj->smart.parent->cur.bounding_box.w)) + { + const Eina_Inlist *list; + const Evas_Object *o; + Evas_Coord maxw = clip ? 0 : x + w; + + list = evas_object_smart_members_get_direct(obj->smart.parent); + EINA_INLIST_FOREACH(list, o) + { + Evas_Coord tw = o->smart.smart + ? o->cur.bounding_box.x + o->cur.bounding_box.w + : o->cur.geometry.x + o->cur.geometry.w; + + if (!o->clip.clipees && tw > maxw) maxw = tw; + } + + if (maxw != obj->smart.parent->cur.bounding_box.x + obj->smart.parent->cur.bounding_box.w) + { + obj->smart.parent->cur.bounding_box.w = maxw - obj->smart.parent->cur.bounding_box.x; + propagate = EINA_TRUE; + } + } + + /* Update bottom limit */ + if (y + h > obj->smart.parent->cur.bounding_box.y + obj->smart.parent->cur.bounding_box.h) + { + obj->smart.parent->cur.bounding_box.h = y + h - obj->smart.parent->cur.bounding_box.y; + propagate = EINA_TRUE; + } + else if ((py + ph == obj->smart.parent->cur.bounding_box.y + obj->smart.parent->cur.bounding_box.h && + y + h < obj->smart.parent->cur.bounding_box.y + obj->smart.parent->cur.bounding_box.h) || + (clip && y + h == obj->smart.parent->cur.bounding_box.y + obj->smart.parent->cur.bounding_box.h)) + { + const Eina_Inlist *list; + const Evas_Object *o; + Evas_Coord maxh = clip ? 0 : y + h; + + list = evas_object_smart_members_get_direct(obj->smart.parent); + EINA_INLIST_FOREACH(list, o) + { + Evas_Coord th = o->smart.smart + ? o->cur.bounding_box.y + o->cur.bounding_box.h + : o->cur.geometry.y + o->cur.geometry.h; + + if (!o->clip.clipees && th > maxh) maxh = th; + } + + if (maxh != obj->smart.parent->cur.bounding_box.y + obj->smart.parent->cur.bounding_box.h) + { + obj->smart.parent->cur.bounding_box.h = maxh - obj->smart.parent->cur.bounding_box.y; + propagate = EINA_TRUE; + } + } + + if (propagate) + evas_object_update_bounding_box(obj->smart.parent); +} + EAPI void evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) { @@ -505,6 +668,8 @@ evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) obj->cur.geometry.x = nx; obj->cur.geometry.y = ny; + evas_object_update_bounding_box(obj); + //// obj->cur.cache.geometry.validity = 0; obj->changed_move = EINA_TRUE; evas_object_change(obj); @@ -590,6 +755,8 @@ evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) obj->cur.geometry.w = nw; obj->cur.geometry.h = nh; + evas_object_update_bounding_box(obj); + //// obj->cur.cache.geometry.validity = 0; evas_object_change(obj); evas_object_clip_dirty(obj); diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index bf0cfc55a6..af71e89ca1 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -509,6 +509,7 @@ struct _Evas_Object Evas_Object *map_parent; double scale; Evas_Coord_Rectangle geometry; + Evas_Coord_Rectangle bounding_box; struct { struct { Evas_Coord x, y, w, h; @@ -620,6 +621,7 @@ struct _Evas_Object Eina_Bool del_ref : 1; Eina_Bool is_frame : 1; + Eina_Bool child_has_map : 1; }; struct _Evas_Func_Node @@ -889,6 +891,7 @@ extern "C" { Evas_Object *evas_object_new(Evas *e); void evas_object_free(Evas_Object *obj, int clean_layer); +void evas_object_update_bounding_box(Evas_Object *obj); void evas_object_inject(Evas_Object *obj, Evas *e); void evas_object_release(Evas_Object *obj, int clean_layer); void evas_object_change(Evas_Object *obj);