evas: and for this nice international hollyday let me introduce a dynamic bounding...
authorCedric BAIL <cedric.bail@free.fr>
Tue, 1 May 2012 07:31:42 +0000 (07:31 +0000)
committerCedric BAIL <cedric.bail@free.fr>
Tue, 1 May 2012 07:31:42 +0000 (07:31 +0000)
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
legacy/evas/NEWS
legacy/evas/src/lib/canvas/evas_clip.c
legacy/evas/src/lib/canvas/evas_events.c
legacy/evas/src/lib/canvas/evas_map.c
legacy/evas/src/lib/canvas/evas_object_main.c
legacy/evas/src/lib/include/evas_private.h

index 84a95f5..4246cc0 100644 (file)
 
        * 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.
index a1ac059..6122a83 100644 (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.
index 1ae2f73..435a0ff 100644 (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 */
index 1ee8388..26fb83f 100644 (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)
                     {
index 0dbad30..46ac024 100644 (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
index 33665d6..f31e7bd 100644 (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);
index bf0cfc5..af71e89 100644 (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);