diff src/event.c @ 235:65cabbdd5284

termporary revision
author Thinker K.F. Li <thinker@branda.to>
date Thu, 25 Dec 2008 18:40:27 +0800
parents 527894c2ad39
children 104d83378582
line wrap: on
line diff
--- a/src/event.c	Wed Dec 24 23:43:39 2008 +0800
+++ b/src/event.c	Thu Dec 25 18:40:27 2008 +0800
@@ -3,10 +3,12 @@
  */
 #include <stdio.h>
 #include <stdlib.h>
+#ifndef UNITTEST
 #include <cairo.h>
 #include "mb_types.h"
 #include "mb_redraw_man.h"
 #include "mb_shapes.h"
+#endif
 
 #define OK 0
 #define ERR -1
@@ -15,40 +17,149 @@
 
 #define ARRAY_EXT_SZ 64
 
+#define ASSERT(x)
 
-DARRAY_DEFINE(geos, geo_t *);
+#ifdef UNITTEST
+/* ============================================================ */
+
+typedef struct shape shape_t;
+
+typedef struct cairo cairo_t;
+struct cairo {
+    shape_t *drawed;
+};
+#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 {
+};
+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)
+
+
+typedef float co_aix;
+
+typedef struct _area area_t;
+struct _area {
+    co_aix x, y;
+    co_aix w, h;
+};
+
+struct mb_obj {
+    int obj_type;
+};
+typedef struct mb_obj mb_obj_t;
+
+#define GEF_OV_DRAW 0x1
+#define GEF_HIDDEN 0x2
 
-/*! \brief Add a geo_t object to general geo list.
- *
- * General geo list can use to temporary keep a list of geo_t
- * objects for any purpose.  It supposed to be reused by
- * different modules that need to select part of geo_t objects
- * from a redraw manager.
- */
-static int _add_gen_geo(redraw_man_t *rdman, geo_t *geo) {
-    int r;
+struct shape {
+    mb_obj_t obj;
+    
+    void *fill, *stroke;
+    struct shape *sibling;
+    int flags;
+    
+    int num_points;
+    co_aix points[32][2];
+};
+enum { MBO_DUMMY,
+       MBO_COORD,
+       MBO_SHAPES=0x1000,
+       MBO_PATH,
+       MBO_TEXT,
+       MBO_RECT
+};
+#define MBO_TYPE(x) (((mb_obj_t *)(x))->obj_type)
+#define IS_MBO_SHAPES(x) (((mb_obj_t *)(x))->obj_type & MBO_SHAPES)
+#define sh_get_geo(x) ((x)->geo)
+static int sh_pos_is_in(shape_t *shape, co_aix x, co_aix y) {
+    int i;
 
-    r = geos_add(&rdman->gen_geos, geo);
-    return r == 0? OK: ERR;
+    for(i = 0; i < shape->num_points; i++)
+	if(shape->points[i][0] == x && shape->points[i][1] == y)
+	    return TRUE;
+    return FALSE;
+}
+#define sh_get_flags(shape, mask) ((shape)->flags & mask)
+#define sh_set_flags(shape, mask) do { (shape)->flags |= mask; } while(0)
+#define sh_clear_flags(shape, mask) do { (shape)->flags &= ~(mask); } while(0)
+
+typedef struct coord coord_t;
+struct coord {
+    mb_obj_t obj;
+    
+    coord_t *children;
+    coord_t *sibling;
+    shape_t *shapes;
+};
+
+
+static
+coord_t *postorder_coord_subtree(coord_t *root, coord_t *last) {
+    if(last == NULL)
+	return root;
 }
 
-static int _collect_geos_at_point(redraw_man_t *rdman,
+#define sh_path_draw(path, cr)
+#define sh_text_draw(path, cr)
+#define sh_rect_draw(path, cr)
+
+
+struct redraw_man {
+    cairo_t *cr;
+    int shape_gl_sz;
+    shape_t *shape_gl[32];
+};
+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)
+static int rdman_add_shape_gl(redraw_man_t *rdman, shape_t *shape) {
+    (rdman)->shape_gl[(rdman)->shape_gl_sz++] = shape;
+    return OK;
+}
+#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);
+
+
+/* ============================================================ */
+#endif /* UNITTEST */
+
+
+static int _collect_shapes_at_point(redraw_man_t *rdman,
 				   co_aix x, co_aix y) {
-    geo_t *geo;
+    shape_t *shape;
     int r;
     
     r = rdman_force_clean(rdman);
     if(r != OK)
 	return ERR;
 
-    rdman->gen_geos.num = 0;
+    rdman_clear_shape_gl(rdman);
 
-    for(geo = rdman_geos(rdman, NULL);
-	geo != NULL;
-	geo = rdman_geos(rdman, geo)) {
-	if(geo_pos_is_in(geo, x, y)) {
-	    r = _add_gen_geo(rdman, geo);
-	    if(r != OK)
+    for(shape = rdman_shapes(rdman, (shape_t *)NULL);
+	shape != NULL;
+	shape = rdman_shapes(rdman, shape)) {
+	if(sh_pos_is_in(shape, x, y)) {
+	    r = rdman_add_shape_gl(rdman, shape);
+	    if(r != 0)
 		return ERR;
 	}
     }
@@ -88,25 +199,37 @@
     return FALSE;
 }
 
-static geo_t *find_geo_in_pos(redraw_man_t *rdman,
-			      co_aix x, co_aix y, int *in_stroke) {
-    geo_t *geo;
-    geo_t **geos;
+static
+int _shape_pos_is_in(shape_t *shape, co_aix x, co_aix y,
+		     int *in_stroke, cairo_t *cr) {
+    int r;
+
+    r = sh_pos_is_in(shape, x, y);
+    if(!r)
+	return FALSE;
+
+    r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, cr);
+    cairo_new_path(cr);
+    if(!r)
+	return FALSE;
+
+    return TRUE;
+}
+
+static shape_t *_find_shape_in_pos(redraw_man_t *rdman,
+				   co_aix x, co_aix y, int *in_stroke) {
     shape_t *shape;
     cairo_t *cr;
     int i, r;
 
-    geos = rdman->gen_geos.ds;
-    cr = rdman->cr;
-    for(i = rdman->gen_geos.num - 1; i >= 0; i--) {
-	geo = geos[i];
-	if(geo->flags & GEF_HIDDEN)
+    cr = rdman_get_cr(rdman);
+    for(i = rdman_shape_gl_len(rdman) - 1; i >= 0; i--) {
+	shape = rdman_get_shape_gl(rdman, i);
+	if(sh_get_flags(shape, GEF_HIDDEN))
 	    continue;
-	shape = geo_get_shape(geo);
 	r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, cr);
-	cairo_new_path(cr);
 	if(r)
-	    return geo;
+	    return shape;
     }
 
     return NULL;
@@ -114,36 +237,15 @@
 
 shape_t *find_shape_at_pos(redraw_man_t *rdman,
 			   co_aix x, co_aix y, int *in_stroke) {
-    geo_t *geo;
+    shape_t *shape;
     int r;
 
-    r = _collect_geos_at_point(rdman, x, y);
+    r = _collect_shapes_at_point(rdman, x, y);
     if(r != OK)
 	return NULL;
 
-    geo = find_geo_in_pos(rdman, x, y, in_stroke);
-    if(geo == NULL)
-	return NULL;
-
-    return geo_get_shape(geo);
-}
-
-static
-int _shape_pos_is_in(redraw_man_t *rdman, shape_t *shape,
-		     co_aix x, co_aix y, int *in_stroke) {
-    geo_t *geo;
-    int r;
-
-    geo = sh_get_geo(shape);
-    r = geo_pos_is_in(geo, x, y);
-    if(!r)
-	return FALSE;
-
-    r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, rdman->cr);
-    if(!r)
-	return FALSE;
-
-    return TRUE;
+    shape = _find_shape_in_pos(rdman, x, y, in_stroke);
+    return shape;
 }
 
 /*! \brief Test if an object and descendants cover the position
@@ -155,21 +257,19 @@
 		     co_aix x, co_aix y, int *in_stroke) {
     coord_t *cur_coord, *root;
     shape_t *shape;
-    geo_t *geo;
     int r;
 
     if(IS_MBO_SHAPES(obj)) {
 	shape = (shape_t *)obj;
-	r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, rdman->cr);
+	r = _shape_pos_is_in(shape, x, y, in_stroke, rdman_get_cr(rdman));
 	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_COORD_MEMBERS(cur_coord, geo) {
-	    shape = geo_get_shape(geo);
-	    r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, rdman->cr);
+	FOR_COORD_SHAPES(cur_coord, shape) {
+	    r = _shape_pos_is_in(shape, x, y, in_stroke, rdman_get_cr(rdman));
 	    if(r)
 		return TRUE;
 	}
@@ -183,7 +283,7 @@
     cairo_t *cr;
     int w, h;
 
-    rdman_surface = cairo_get_target(rdman->cr);
+    rdman_surface = cairo_get_target(rdman_get_cr(rdman));
     w = cairo_image_surface_get_width(rdman_surface);
     h = cairo_image_surface_get_height(rdman_surface);
     
@@ -203,17 +303,15 @@
     cairo_destroy(cr);
 }
 
-static _draw_to_mask(shape_t *shape, cairo_t *cr) {
-    geo_t *geo;
-
-    geo = sh_get_geo(shape);
-    if(geo->flags & GEF_OV_DRAW)
+static
+void _draw_to_mask(shape_t *shape, cairo_t *cr) {
+    if(sh_get_flags(shape, GEF_OV_DRAW))
 	return;
     
     draw_shape_path(shape, cr);
     cairo_clip(cr);
     
-    geo->flags |= GEF_OV_DRAW;
+    sh_set_flags(shape, GEF_OV_DRAW);
 }
 
 static
@@ -241,13 +339,13 @@
     return FALSE;
 }
 
-/*! \brief Is a mb_obj_t overlaid with another mb_object_t and
+/*! \brief Is a mb_obj_t overlaid with another mb_obj_t and
  *	descendants.
  *
  * coord is relative less than shapes.  Check areas of coord can
- * havily avoid useless computation.  For shapes, it not only check
- * overlay of area.  It also check overlay by actually drawing on a
- * cairo surface.
+ * skip sub-trees and avoid useless heavy computation.  For shapes,
+ * it not only check overlay of area.  It also check overlay by
+ * actually drawing on a cairo surface.
  */
 static
 int _is_obj_objs_overlay(mb_obj_t *obj, mb_obj_t *others_root,
@@ -255,18 +353,14 @@
     area_t *area, *candi_area;
     coord_t *coord, *candi_coord, *root;
     shape_t *shape, *candi_shape;
-    geo_t *geo, *candi_geo;
     int obj_is_shape;
     int r;
-    /*
-     */
     
     obj_is_shape = IS_MBO_SHAPES(obj);
     
     if(obj_is_shape) {
 	shape = (shape_t *)obj;
-	geo = sh_get_geo(shape);
-	area = geo_get_area(geo);
+	area = sh_get_area(shape);
     } else {
 	coord = (coord_t *)obj;
 	area = coord_get_area(coord);
@@ -274,10 +368,9 @@
 	
     if(IS_MBO_SHAPES(others_root)) {
 	candi_shape = (shape_t *)others_root;
-	candi_geo = sh_get_geo(candi_shape);
-	candi_area =  geo_get_area(candi_geo);
+	candi_area =  sh_get_area(candi_shape);
 	
-	r = is_overlay(area, candi_area);
+	r = areas_are_overlay(area, candi_area);
 	if(!r)
 	    return FALSE;
 	
@@ -290,18 +383,20 @@
 	return r;
     }
     
+    ASSERT(IS_MBO_COORD(others_root));
+    
     root = (coord_t *)others_root;
     FOR_COORDS_PREORDER(root, candi_coord) {
 	candi_area = coord_get_area(candi_coord);
-	r = is_overlay(area, candi_area);
+	r = areas_are_overlay(area, candi_area);
 	if(!r) {
-	    preorder_coord_skip_subtree(coord);
+	    preorder_coord_skip_subtree(candi_coord);
 	    continue;
 	}
 	
-	FOR_COORD_MEMBERS(coord, candi_geo) {
-	    candi_area = geo_get_area(candi_geo);
-	    r = is_overlay(area, candi_area);
+	FOR_COORD_SHAPES(candi_coord, candi_shape) {
+	    candi_area = sh_get_area(candi_shape);
+	    r = areas_are_overlay(area, candi_area);
 	    if(!r)
 		continue;
 	    
@@ -318,17 +413,35 @@
     return FALSE;
 }
 
+static
+void _clear_ov_draw(mb_obj_t *obj) {
+    coord_t *coord, *root;
+    shape_t *shape;
+
+    if(IS_MBO_SHAPES(obj)) {
+	shape = (shape_t *)obj;
+	sh_clear_flags(shape, GEF_OV_DRAW);
+	return;
+    }
+
+    root = (coord_t *)obj;
+    FOR_COORDS_PREORDER(root, coord) {
+	FOR_COORD_SHAPES(coord, shape) {
+	    sh_clear_flags(shape, GEF_OV_DRAW);
+	}
+    }
+}
+
 /*! \brief Test if two objects are overlaid.
  *
  * \todo Detect overlay in better way with cairo.
  * \note This function cost heavy on CPU power.
  */
-int mb_objs_is_overlay(redraw_man_t *rdman,
+int mb_objs_are_overlay(redraw_man_t *rdman,
 		       mb_obj_t *obj1, mb_obj_t *obj2) {
     cairo_t *cr;
     area_t *area;
     shape_t *shape;
-    geo_t *geo;
     coord_t *coord, *root;
     int r;
 
@@ -349,8 +462,7 @@
 	    continue;
 	}
 
-	FOR_COORD_MEMBERS(coord, geo) {
-	    shape = geo_get_shape(geo);
+	FOR_COORD_SHAPES(coord, shape) {
 	    r = _is_obj_objs_overlay((mb_obj_t *)shape, obj2, cr);
 	    if(r)
 		goto out;
@@ -359,6 +471,62 @@
     r = FALSE;
     
  out:
+    _clear_ov_draw(obj2);	/* marked by _is_obj_objs_overlay() */
     _release_cairo_for_testing(cr);
     return r;
 }
+
+#ifdef UNITTEST
+
+#include <CUnit/Basic.h>
+
+static
+redraw_man_t *_fake_rdman(void) {
+    redraw_man_t *rdman;
+    cairo_surface_t *surface;
+
+    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);
+    return rdman;
+}
+
+static
+void _free_fake_rdman(redraw_man_t *rdman) {
+    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;
+
+    rdman = _fake_rdman();
+    CU_ASSERT(rdman != NULL);
+
+    _free_fake_rdman(rdman);
+}
+
+static
+void test_is_obj_objs_overlay(void) {
+}
+
+static
+void test_mb_objs_are_overlay(void) {
+}
+
+CU_pSuite get_event_suite(void) {
+    CU_pSuite suite;
+
+    suite = CU_add_suite("Suite_event", NULL, NULL);
+    CU_ADD_TEST(suite, test_mb_obj_pos_is_in);
+    CU_ADD_TEST(suite, test_is_obj_objs_overlay);
+    CU_ADD_TEST(suite, test_mb_objs_are_overlay);
+
+    return suite;
+}
+
+#endif /* UNITTEST */