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
This commit is contained in:
Cedric BAIL 2012-05-01 07:31:42 +00:00
parent 4bac402899
commit 0f424acb6e
7 changed files with 218 additions and 4 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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 */

View File

@ -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)
{

View File

@ -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

View File

@ -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);

View File

@ -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);