changeset 250:bd8ea44b421e

Fix bug and finish unit test for collision testing in event.c. - mock for cairo, rdman, coord, and shape should be refactoried to a module.
author Thinker K.F. Li <thinker@branda.to>
date Sun, 04 Jan 2009 11:42:32 +0800
parents 81458bb0bf34
children f08b3ba9c1d8
files include/mb_tools.h include/mb_types.h src/event.c
diffstat 3 files changed, 613 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/include/mb_tools.h	Wed Dec 31 23:57:12 2008 +0800
+++ b/include/mb_tools.h	Sun Jan 04 11:42:32 2009 +0800
@@ -61,6 +61,10 @@
 	    }						\
 	}						\
     } while(0)
+#define STAILQ_FOR_EACH(q, type, field, elm)	\
+    for((elm) = (q).head;			\
+	(elm) != NULL;				\
+	(elm) = (elm)->field)
 
 /*! \defgroup darray Dynamic Array
  *
@@ -134,4 +138,7 @@
 #define MEM2OBJ(var, type, mem) ((type *)((void *)var - OFFSET(type, mem)))
 #define OFF2TYPE(obj, off, type) (*(type *)((void *)(obj) + (off)))
 
+#define MAX(a, b) ((a) > (b)? (a): (b))
+#define MIN(a, b) ((a) < (b)? (a): (b))
+
 #endif /* __TOOLS_H_ */
--- a/include/mb_types.h	Wed Dec 31 23:57:12 2008 +0800
+++ b/include/mb_types.h	Sun Jan 04 11:42:32 2009 +0800
@@ -108,6 +108,10 @@
 
 extern int areas_are_overlay(area_t *r1, area_t *r2);
 extern void area_init(area_t *area, int n_pos, co_aix pos[][2]);
+#define _in_range(a, s, w) ((a) >= (s) && (a) < ((s) + (w)))
+#define area_pos_is_in(area, _x, _y)		\
+    (_in_range(_x, (area)->x, (area)->w) &&	\
+     _in_range(_y, (area)->y, (area)->h))
 extern void geo_init(geo_t *g);
 extern void geo_from_positions(geo_t *g, int n_pos, co_aix pos[][2]);
 extern void geo_mark_overlay(geo_t *g, int n_others, geo_t **others,
@@ -115,10 +119,7 @@
 #define geo_get_shape(g) ((g)->shape)
 #define geo_get_shape_safe(g) ((g)? (g)->shape: NULL)
 #define geo_set_shape(g, sh) do {(g)->shape = sh;} while(0)
-#define _geo_is_in(a, s, w) ((a) >= (s) && (a) < ((s) + (w)))
-#define geo_pos_is_in(g, _x, _y)				\
-    (_geo_is_in(_x, (g)->cur_area->x, (g)->cur_area->w) &&	\
-     _geo_is_in(_y, (g)->cur_area->y, (g)->cur_area->h))
+#define geo_pos_is_in(g, _x, _y) area_pos_is_in((g)->cur_area, _x, _y)
 #define geo_get_area(g) ((g)->cur_area)
 #define geo_get_flags(g, mask) ((g)->flags & (mask))
 #define geo_set_flags(g, mask) do {(g)->flags |= mask;} while(0)
--- a/src/event.c	Wed Dec 31 23:57:12 2008 +0800
+++ b/src/event.c	Sun Jan 04 11:42:32 2009 +0800
@@ -21,52 +21,116 @@
 
 #ifdef UNITTEST
 /* ============================================================ */
+#include <string.h>
+#include "mb_tools.h"
+
+typedef float co_aix;
 
 typedef struct shape shape_t;
+typedef struct cairo_surface cairo_surface_t;
+typedef struct coord coord_t;
 
 typedef struct cairo cairo_t;
 struct cairo {
-    shape_t *drawed;
+    STAILQ(shape_t) drawed;
+    STAILQ(shape_t) clip_pathes;
+    cairo_surface_t *tgt;
 };
-#define cairo_in_fill(cr, x, y) 0
-#define cairo_in_stroke(cr, x, y) 0
-#define cairo_new_path(cr)
-#define cairo_get_target(cr) NULL
-#define cairo_create(target) NULL
-#define cairo_destroy(cr)
-#define cairo_clip(cr)
-#define cairo_fill(cr)
-#define cairo_image_surface_get_data(cr) NULL
-#define cairo_image_surface_get_stride(cr) 1
 
 struct cairo_surface {
+    cairo_t *cr;
+    int w, h;
+    unsigned char *data;
 };
-typedef struct cairo_surface cairo_surface_t;
-#define cairo_image_surface_get_width(surface) 0
-#define cairo_image_surface_get_height(surface) 0
-#define cairo_image_surface_create(surface, w, h) NULL
-#define cairo_surface_destroy(surface)
+
+#define cairo_new_path(cr) do { STAILQ_CLEAN((cr)->drawed); } while(0)
+#define cairo_get_target(cr) (cr)->tgt
+static
+cairo_t *cairo_create(cairo_surface_t *target) {
+    cairo_t *cr;
+
+    cr = (cairo_t *)malloc(sizeof(cairo_t));
+    STAILQ_INIT(cr->drawed);
+    STAILQ_INIT(cr->clip_pathes);
+    cr->tgt = target;
+    target->cr = cr;
 
+    return cr;
+}
+#define cairo_destroy(cr) do { free(cr); } while(0)
+#define cairo_clip(cr)			\
+    do {				\
+	memcpy(&(cr)->clip_pathes,	\
+	       &(cr)->drawed,		\
+	       sizeof((cr)->drawed));	\
+	STAILQ_CLEAN((cr)->drawed);	\
+    } while(0)
+#define cairo_fill(cr)
 
-typedef float co_aix;
+#define cairo_image_surface_get_width(surface) (surface)->w
+#define cairo_image_surface_get_height(surface) (surface)->h
+static
+cairo_surface_t *cairo_image_surface_create(int format, int w, int h) {
+    cairo_surface_t *surf;
+
+    surf = (cairo_surface_t *)malloc(sizeof(cairo_surface_t));
+    surf->w = w;
+    surf->h = h;
+    surf->data = (unsigned char *)malloc(h);
+    memset(surf->data, 0, h);
+
+    return surf;
+}
+#define cairo_surface_destroy(surface)		\
+    do { free((surface)->data); free(surface); } while(0)
+#define cairo_image_surface_get_stride(surface) 1
+#define CAIRO_FORMAT_A1 1
+
 
 typedef struct _area area_t;
 struct _area {
     co_aix x, y;
     co_aix w, h;
 };
-#define range_overlay(as, aw, bs, bw)			\
-    (((bs) - (as)) <= (aw) || ((as) - (bs)) <= (bw))
+#define area_set(area, _x, _y, _w, _h)		\
+    do {					\
+	(area)->x = (_x);			\
+	(area)->y = (_y);			\
+	(area)->w = (_w);			\
+	(area)->h = (_h);			\
+    } while(0)
+#define _in_range(a, s, w) ((a) >= (s) && (a) < ((s) + (w)))
+#define _range_overlay(as, aw, bs, bw)			\
+    (_in_range(as, bs, bw) || _in_range(bs, as, aw))
 #define areas_are_overlay(a1, a2)		\
-    (range_overlay((a1)->x, (a1)->w,		\
-		   (a2)->x, (a2)->w) &&		\
-     range_overlay((a1)->y, (a1)->h,		\
-		   (a2)->y, (a2)->h))
+    (_range_overlay((a1)->x, (a1)->w,		\
+		    (a2)->x, (a2)->w) &&	\
+     _range_overlay((a1)->y, (a1)->h,		\
+		    (a2)->y, (a2)->h))
+#define area_pos_is_in(area, _x, _y)		\
+    (_in_range(_x, (area)->x, (area)->w) &&	\
+     _in_range(_y, (area)->y, (area)->h))
+#define _range_extent(a, s, w)			\
+    do {					\
+	if((a) < (s)) {				\
+	    (w) += (s) - (a);			\
+	    (s) = (a);				\
+	} else {				\
+	    (w) = MAX(w, (a) - (s) + 1);	\
+	}					\
+    } while(0)
+
+static
+void area_extent(area_t *area, co_aix x, co_aix y) {
+    _range_extent(x, area->x, area->w);
+    _range_extent(y, area->y, area->h);
+}
 
 struct mb_obj {
     int obj_type;
 };
 typedef struct mb_obj mb_obj_t;
+#define MB_OBJ_INIT(obj, type) do { (obj)->obj_type = type; } while(0)
 
 #define GEF_OV_DRAW 0x1
 #define GEF_HIDDEN 0x2
@@ -74,7 +138,10 @@
 struct shape {
     mb_obj_t obj;
     
+    coord_t *coord;
     area_t area;
+    shape_t *all_next;
+    shape_t *drawed_next;
 
     void *fill, *stroke;
     struct shape *sibling;
@@ -106,75 +173,165 @@
 #define sh_clear_flags(shape, mask) do { (shape)->flags &= ~(mask); } while(0)
 #define sh_get_area(shape) (&(shape)->area)
 
-typedef struct coord coord_t;
 struct coord {
     mb_obj_t obj;
   
     area_t area;
     int flags;
     coord_t *parent;
-    coord_t *children;
+    STAILQ(coord_t) children;
     coord_t *sibling;
-    shape_t *shapes;
+    STAILQ(shape_t) shapes;
 };
 
 #define COF_SKIP 0x1
 
 #define coord_get_area(coord) (&(coord)->area)
 #define FOR_COORD_SHAPES(coord, shape)		\
-    for(shape = (coord)->shapes;		\
-	shape != NULL;				\
-	shape = (shape)->sibling)
+    for((shape) = STAILQ_HEAD((coord)->shapes);		\
+	(shape) != NULL;				\
+	(shape) = STAILQ_NEXT(shape_t, sibling, shape))
 #define FOR_COORDS_PREORDER(root, last)			\
-    for(last = root;					\
-	last != NULL;					\
-	last = preorder_coord_subtree(root, last))
+    for((last) = (root);				\
+	(last) != NULL;					\
+	(last) = preorder_coord_subtree(root, last))
+#define FOR_COORD_CHILDREN(parent, child)		\
+    for((child) = STAILQ_HEAD((parent)->children);	\
+	(child) != NULL;				\
+	(child) = STAILQ_NEXT(coord_t, sibling, child))
+
+static
+void _areas_merge(area_t *area1, area_t *area2) {
+    co_aix lu_x, lu_y;
+    co_aix rb_x, rb_y;
+    
+    lu_x = area2->x;
+    lu_y = area2->y;
+    rb_x = lu_x + area2->w - 1;
+    rb_y = lu_y + area2->h - 1;
+    area_extent(area1, lu_x, lu_y);
+    area_extent(area1, rb_x, rb_y);
+}
+
+static
+void coord_update_area(coord_t *coord) {
+    area_t *area;
+    shape_t *shape;
+    coord_t *child;
+    area_t *cur_area;
+
+    area = coord_get_area(coord);
+    
+    shape = STAILQ_HEAD(coord->shapes);
+    if(shape != NULL) {
+	cur_area = sh_get_area(shape);
+    } else {
+	child = STAILQ_HEAD(coord->children);
+	if(child == NULL)
+	    return;
+	cur_area = coord_get_area(child);
+    }
+    memcpy(area, cur_area, sizeof(area_t));
+	
+    FOR_COORD_SHAPES(coord, shape) {
+	cur_area = sh_get_area(shape);
+	_areas_merge(area, cur_area);
+    }
+
+    FOR_COORD_CHILDREN(coord, child) {
+	cur_area = coord_get_area(child);
+	_areas_merge(area, cur_area);
+    }
+}
+
+static
+void coord_update_area_ancestors(coord_t *coord) {
+    coord_t *cur;
+
+    for(cur = coord; cur != NULL; cur = cur->parent) {
+	coord_update_area(cur);
+    }
+}
 
 static
 coord_t *preorder_coord_subtree(coord_t *root, coord_t *last) {
-    if(last->children)
-	return last->children;
-    while(last->sibling == NULL)
+    if(STAILQ_HEAD(last->children) && !(last->flags & COF_SKIP))
+	return STAILQ_HEAD(last->children);
+    if(last == root)
+	return NULL;
+    while(STAILQ_NEXT(coord_t, sibling, last) == NULL) {
+	if(last == root)
+	    return NULL;
 	last = last->parent;
-    return last->sibling;
+    }
+    return STAILQ_NEXT(coord_t, sibling, last);
+}
+
+static
+void preorder_coord_skip_subtree(coord_t *coord) {
+    coord->flags &= ~COF_SKIP;
 }
 
 static
 coord_t *postorder_coord_subtree(coord_t *root, coord_t *last) {
     coord_t *cur;
-
+    
     if(last != NULL) {
-	if(last->sibling == NULL) {
+	if(STAILQ_NEXT(coord_t, sibling, last) == NULL) {
+	    if(cur == root)
+		return NULL;
 	    cur = last->parent;
 	    return cur;
 	}
-	cur = last->sibling;
+	cur = STAILQ_NEXT(coord_t, sibling, last);
     }
 
-    cur = last;
-    while(cur->children) {
-	cur = cur->children;
+    cur = root;
+    while(STAILQ_HEAD(cur->children)) {
+	cur = STAILQ_HEAD(cur->children);
     }
     return cur;
 }
 
-#define sh_path_draw(path, cr)
-#define sh_text_draw(path, cr)
-#define sh_rect_draw(path, cr)
+static
+void shape_draw(shape_t *sh, cairo_t *cr) {
+    STAILQ_INS_TAIL(cr->drawed, shape_t, drawed_next, sh);
+}
+
+#define sh_path_draw(path, cr) shape_draw((shape_t *)path, cr)
+#define sh_text_draw(text, cr) shape_draw((shape_t *)text, cr)
+#define sh_rect_draw(rect, cr) shape_draw((shape_t *)rect, cr)
+static
+void sh_update_area(shape_t *sh) {
+    int i;
+    co_aix x, y;
+    area_t *area = &sh->area;
+
+    if(sh->num_points == 0) {
+	area_set(area, 0, 0, 0, 0);
+	return;
+    }
+
+    area_set(area, sh->points[0][0], sh->points[0][1], 1, 1);
+    for(i = 1; i < sh->num_points; i++) {
+	x = sh->points[i][0];
+	y = sh->points[i][1];
+	area_extent(area, x, y);
+    }
+}
 
 
 struct redraw_man {
     cairo_t *cr;
+    coord_t *root_coord;
     int shape_gl_sz;
     shape_t *shape_gl[32];
+    STAILQ(shape_t) all_shapes;
 };
 typedef struct redraw_man redraw_man_t;
 #define rdman_get_cr(rdman) ((rdman)->cr)
-#define rdman_get_gen_geos(rdman) (&(rdman)->gen_geos)
 #define rdman_force_clean(rdman) OK
-#define rdman_geos(rdman, geo) NULL
-#define rdman_clear_shape_gl(rdman)		\
-    do {(rdman)->shape_gl_sz = 0; } while(0)
+#define rdman_clear_shape_gl(rdman) do {(rdman)->shape_gl_sz = 0; } while(0)
 static int rdman_add_shape_gl(redraw_man_t *rdman, shape_t *shape) {
     (rdman)->shape_gl[(rdman)->shape_gl_sz++] = shape;
     return OK;
@@ -182,9 +339,162 @@
 #define rdman_get_shape_gl(rdman, idx)		\
     (rdman)->shape_gl[idx]
 #define rdman_shape_gl_len(rdman) (rdman)->shape_gl_sz
-static shape_t *rdman_shapes(redraw_man_t *rdman, shape_t *last_shape);
+static shape_t *rdman_shapes(redraw_man_t *rdman, shape_t *last_shape) {
+    if(last_shape == NULL)
+	return STAILQ_HEAD(rdman->all_shapes);
+
+    return STAILQ_NEXT(shape_t, all_next, last_shape);
+}
+#define redraw_man_init(rdman, cr, backend)			\
+    do {							\
+	memset(rdman, 0, sizeof(redraw_man_t));			\
+	(rdman)->cr = cr;					\
+	(rdman)->root_coord = rdman_coord_new_noparent(rdman);	\
+    } while(0)
+#define redraw_man_destroy(rdman)			\
+    do {						\
+	free(rdman);					\
+    } while(0)
+#define rdman_get_root(rdman) ((rdman)->root_coord)
+
+static coord_t *rdman_coord_new_noparent(redraw_man_t *rdman);
+
+static
+redraw_man_t *redraw_man_new(cairo_t *cr, cairo_t *backend) {
+    redraw_man_t *rdman;
+
+    rdman = O_ALLOC(redraw_man_t);
+    redraw_man_init(rdman, cr, backend);
+    return rdman;
+}
+#define redraw_man_free(rdman)			\
+    do {					\
+	redraw_man_destroy(rdman);		\
+	free(rdman);				\
+    } while(0)
+
+static
+int cairo_in_fill(cairo_t *cr, int x, int y) {
+    shape_t *shape;
+    int i;
+
+    for(shape = STAILQ_HEAD(cr->drawed);
+	shape != NULL;
+	shape = STAILQ_NEXT(shape_t, drawed_next, shape)) {
+	for(i = 0; i < shape->num_points; i++)
+	    if(shape->points[i][0] == x &&
+	       shape->points[i][1] == y)
+		return 1;
+    }
+    return 0;
+}
+
+#define cairo_in_stroke cairo_in_fill
+
+static
+void rdman_coord_init_noparent(redraw_man_t *rdman, coord_t *co) {
+    memset(co, 0, sizeof(coord_t));
+    MB_OBJ_INIT(&co->obj, MBO_COORD);
+    STAILQ_INIT(co->children);
+    STAILQ_INIT(co->shapes);
+}
+
+static
+void rdman_coord_init(redraw_man_t *rdman, coord_t *co, coord_t *parent) {
+    rdman_coord_init_noparent(rdman, co);
+    STAILQ_INS_TAIL(parent->children, coord_t, sibling, co);
+    co->parent = parent;
+}
+
+static
+coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) {
+    coord_t *coord;
+
+    coord = O_ALLOC(coord_t);
+    rdman_coord_init(rdman, coord, parent);
+
+    return coord;
+}
 
+coord_t *rdman_coord_new_noparent(redraw_man_t *rdman) {
+    coord_t *coord;
 
+    coord = O_ALLOC(coord_t);
+    rdman_coord_init_noparent(rdman, coord);
+
+    return coord;
+}
+
+static
+void rdman_coord_free(redraw_man_t *rdman, coord_t *coord) {
+    free(coord);
+}
+
+static
+shape_t *rdman_shape_new(redraw_man_t *rdman) {
+    shape_t *shape;
+
+    shape = O_ALLOC(shape_t);
+    memset(shape, 0, sizeof(shape_t));
+    MB_OBJ_INIT(&shape->obj, MBO_PATH);
+    STAILQ_INS(rdman->all_shapes, shape_t, all_next, shape);
+    
+    return shape;
+}
+
+static
+void rdman_shape_free(redraw_man_t *rdman, shape_t *shape) {
+    STAILQ_REMOVE(rdman->all_shapes, shape_t, all_next, shape);
+    free(shape);
+}
+
+#define shape_add_point(shape, x, y)				\
+    do {							\
+	(shape)->points[(shape)->num_points][0] = x;		\
+	(shape)->points[(shape)->num_points][1] = y;		\
+	(shape)->num_points++;					\
+	sh_update_area(shape);					\
+	if((shape)->coord)					\
+	    coord_update_area_ancestors((shape)->coord);	\
+    } while(0)
+
+static
+int rdman_add_shape(redraw_man_t *rdman, shape_t *shape,
+		     coord_t *parent) {
+    STAILQ_INS_TAIL(parent->shapes, shape_t, sibling, shape);
+    shape->coord = parent;
+
+    return OK;
+}
+
+static
+void *cairo_image_surface_get_data(cairo_surface_t *surf) {
+    cairo_t *cr;
+    shape_t *shape1, *shape2;
+    co_aix x1, y1, x2, y2;
+    int i, j;
+
+    cr = surf->cr;
+    
+    STAILQ_FOR_EACH(cr->drawed, shape_t, sibling, shape1) {
+	for(i = 0; i < shape1->num_points; i++) {
+	    x1 = shape1->points[i][0];
+	    y1 = shape1->points[i][1];
+	    STAILQ_FOR_EACH(cr->clip_pathes, shape_t, sibling, shape2) {
+		for(j = 0; j < shape2->num_points; j++) {
+		    x2 = shape2->points[j][0];
+		    y2 = shape2->points[j][1];
+		    if(x1 == x2 && y1 == y2) {
+			surf->data[0] = 1;
+			return surf->data;
+		    }
+		}
+	    }
+	}
+    }
+    surf->data[0] = 0;
+    return surf->data;
+}
 /* ============================================================ */
 #endif /* UNITTEST */
 
@@ -303,6 +613,7 @@
 		     co_aix x, co_aix y, int *in_stroke) {
     coord_t *cur_coord, *root;
     shape_t *shape;
+    area_t *area;
     int r;
 
     if(IS_MBO_SHAPES(obj)) {
@@ -311,9 +622,12 @@
 	return r;
     }
     root = (coord_t *)obj;
-    for(cur_coord = postorder_coord_subtree(root, NULL);
-	cur_coord != NULL;
-	cur_coord = postorder_coord_subtree(root, cur_coord)) {
+    FOR_COORDS_PREORDER(root, cur_coord) {
+	area = coord_get_area(cur_coord);
+	if(!area_pos_is_in(area, x, y)) {
+	    preorder_coord_skip_subtree(cur_coord);
+	    continue;
+	}
 	FOR_COORD_SHAPES(cur_coord, shape) {
 	    r = _shape_pos_is_in(shape, x, y, in_stroke, rdman_get_cr(rdman));
 	    if(r)
@@ -529,39 +843,266 @@
 static
 redraw_man_t *_fake_rdman(void) {
     redraw_man_t *rdman;
-    cairo_surface_t *surface;
+    cairo_t *cr, *backend;
+    cairo_surface_t *surf;
 
-    rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
-    surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
-    rdman->cr = cairo_create(surface);
-    DARRAY_INIT(&rdman->gen_geos);
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    backend = cairo_create(surf);
+    rdman = redraw_man_new(cr, backend);
+    
     return rdman;
 }
 
 static
 void _free_fake_rdman(redraw_man_t *rdman) {
+    cairo_surface_destroy(rdman->cr->tgt);
     cairo_destroy(rdman->cr);
-    DARRAY_DESTROY(&rdman->gen_geos);
     free(rdman);
 }
 
 static
 void test_mb_obj_pos_is_in(void) {
     redraw_man_t *rdman;
-    mb_obj_t *obj;
+    shape_t *shape;
+    coord_t *root, *child_coord;
+    int in_stroke = 0;
+    int r;
 
     rdman = _fake_rdman();
     CU_ASSERT(rdman != NULL);
 
+    root = rdman_get_root(rdman);
+
+    child_coord = rdman_coord_new(rdman, root);
+    CU_ASSERT(child_coord != NULL);
+
+    shape = rdman_shape_new(rdman);
+    CU_ASSERT(shape != NULL);
+
+    rdman_add_shape(rdman, shape, child_coord);
+
+    shape_add_point(shape, 3, 12);
+
+    shape->fill = shape;
+    shape->stroke = shape;
+
+    r = mb_obj_pos_is_in(rdman, (mb_obj_t *)shape, 3, 12, &in_stroke);
+    CU_ASSERT(r == TRUE);
+
+    r = mb_obj_pos_is_in(rdman, (mb_obj_t *)shape, 3, 13, &in_stroke);
+    CU_ASSERT(r == FALSE);
+
+    r  = mb_obj_pos_is_in(rdman, (mb_obj_t *)root, 3, 12, &in_stroke);
+    CU_ASSERT(r == TRUE);
+
+    r  = mb_obj_pos_is_in(rdman, (mb_obj_t *)root, 4, 12, &in_stroke);
+    CU_ASSERT(r == FALSE);
+
+    rdman_shape_free(rdman, shape);
     _free_fake_rdman(rdman);
 }
 
 static
 void test_is_obj_objs_overlay(void) {
+    redraw_man_t *rdman;
+    coord_t *root, *coord1, *coord2;
+    shape_t *shape1, *shape2, *shape3;
+    cairo_t *cr;
+    cairo_surface_t *surf;
+    int r;
+
+    rdman = _fake_rdman();
+    CU_ASSERT(rdman != NULL);
+
+    root = rdman_get_root(rdman);
+
+    coord1 = rdman_coord_new(rdman, root);
+    shape1 = rdman_shape_new(rdman);
+    rdman_add_shape(rdman, shape1, coord1);
+
+    coord2 = rdman_coord_new(rdman, root);
+    shape2 = rdman_shape_new(rdman);
+    rdman_add_shape(rdman, shape2, coord2);
+
+    shape3 = rdman_shape_new(rdman);
+    rdman_add_shape(rdman, shape3, coord2);
+
+    shape_add_point(shape1, 3, 2);
+    shape_add_point(shape2, 5, 5);
+    shape_add_point(shape3, 4, 3);
+    
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)coord1, (mb_obj_t *)coord2, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(coord2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)shape1, (mb_obj_t *)coord2, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(coord2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)coord1, (mb_obj_t *)shape2, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)shape1, (mb_obj_t *)shape2, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)shape1, (mb_obj_t *)shape3, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape3, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)coord1, (mb_obj_t *)shape3, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape3, GEF_OV_DRAW);
+    
+    shape_add_point(shape1, 5, 5);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)coord1, (mb_obj_t *)coord2, cr);
+    CU_ASSERT(r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(coord2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)shape1, (mb_obj_t *)coord2, cr);
+    CU_ASSERT(r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(coord2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)coord1, (mb_obj_t *)shape2, cr);
+    CU_ASSERT(r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)shape1, (mb_obj_t *)shape2, cr);
+    CU_ASSERT(r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape2, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)shape1, (mb_obj_t *)shape3, cr);
+    CU_ASSERT(!r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape3, GEF_OV_DRAW);
+
+    surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
+    cr = cairo_create(surf);
+    r = _is_obj_objs_overlay((mb_obj_t *)coord1, (mb_obj_t *)shape3, cr);
+    CU_ASSERT(r);
+    cairo_destroy(cr);
+    cairo_surface_destroy(surf);
+    sh_clear_flags(shape3, GEF_OV_DRAW);
+
+    rdman_shape_free(rdman, shape1);
+    rdman_shape_free(rdman, shape2);
+    rdman_shape_free(rdman, shape3);
+    rdman_coord_free(rdman, coord1);
+    rdman_coord_free(rdman, coord2);
+    _free_fake_rdman(rdman);
 }
 
 static
 void test_mb_objs_are_overlay(void) {
+    redraw_man_t *rdman;
+    coord_t *root, *coord1, *coord2;
+    shape_t *shape1, *shape2, *shape3;
+    int r;
+
+    rdman = _fake_rdman();
+
+    root = rdman_get_root(rdman);
+
+    coord1 = rdman_coord_new(rdman, root);
+    shape1 = rdman_shape_new(rdman);
+    rdman_add_shape(rdman, shape1, coord1);
+
+    coord2 = rdman_coord_new(rdman, root);
+    shape2 = rdman_shape_new(rdman);
+    rdman_add_shape(rdman, shape2, coord2);
+
+    shape3 = rdman_shape_new(rdman);
+    rdman_add_shape(rdman, shape3, coord2);
+
+    shape_add_point(shape1, 3, 2);
+    shape_add_point(shape2, 5, 5);
+    shape_add_point(shape3, 4, 3);
+
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)coord1, (mb_obj_t *)coord2);
+    CU_ASSERT(!r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)shape1, (mb_obj_t *)coord2);
+    CU_ASSERT(!r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)shape1, (mb_obj_t *)shape2);
+    CU_ASSERT(!r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)coord1, (mb_obj_t *)shape2);
+    CU_ASSERT(!r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)shape1, (mb_obj_t *)shape3);
+    CU_ASSERT(!r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)coord1, (mb_obj_t *)shape3);
+    CU_ASSERT(!r);
+
+    shape_add_point(shape1, 5, 5);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)coord1, (mb_obj_t *)coord2);
+    CU_ASSERT(r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)shape1, (mb_obj_t *)coord2);
+    CU_ASSERT(r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)shape1, (mb_obj_t *)shape2);
+    CU_ASSERT(r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)coord1, (mb_obj_t *)shape2);
+    CU_ASSERT(r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)shape1, (mb_obj_t *)shape3);
+    CU_ASSERT(!r);
+    
+    r = mb_objs_are_overlay(rdman, (mb_obj_t *)coord1, (mb_obj_t *)shape3);
+    CU_ASSERT(!r);
+
+    _free_fake_rdman(rdman);
 }
 
 CU_pSuite get_event_suite(void) {