diff src/redraw_man.c @ 17:41f0907b27ac

Unittest for rdman_redraw_changed(). geo_init() is seperated into geo_init() and geo_from_positions().
author Thinker K.F. Li <thinker@branda.to>
date Fri, 01 Aug 2008 23:32:22 +0800
parents e17e12b112c4
children 0f3baa488a62
line wrap: on
line diff
--- a/src/redraw_man.c	Fri Aug 01 18:20:28 2008 +0800
+++ b/src/redraw_man.c	Fri Aug 01 23:32:22 2008 +0800
@@ -13,6 +13,13 @@
 #define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL)
 #define SWAP(a, b, t) do { t c;  c = a; a = b; b = c; } while(0)
 
+#ifdef UNITTEST
+typedef struct _sh_dummy sh_dummy_t;
+
+extern void sh_dummy_transform(shape_t *shape);
+extern void sh_dummy_draw(shape_t *, cairo_t *);
+#endif /* UNITTEST */
+
 /*! \brief Sort a list of element by a unsigned integer.
  *
  * The result is in ascend order.  The unsigned integers is
@@ -83,6 +90,97 @@
     return OK;
 }
 
+static void clean_shape(shape_t *shape) {
+    switch(shape->sh_type) {
+    case SHT_PATH:
+	sh_path_transform(shape);
+	break;
+#ifdef UNITTEST
+    default:
+	sh_dummy_transform(shape);
+	break;
+#endif /* UNITTEST */
+    }
+    shape->geo->flags &= ~GEF_DIRTY;
+}
+
+static void area_to_positions(area_t *area, co_aix (*poses)[2]) {
+    poses[0][0] = area->x;
+    poses[0][1] = area->y;
+    poses[1][0] = area->x + area->w;
+    poses[1][1] = area->y + area->h;;
+}
+
+static int clean_coord(coord_t *coord) {
+    shape_t *shape;
+    geo_t *geo;
+    co_aix (*poses)[2];
+    int cnt, pos_cnt;
+
+    compute_aggr_of_coord(coord);
+
+    /* Clean member shapes. */
+    cnt = 0;
+    for(shape = STAILQ_HEAD(coord->members);
+	shape != NULL;
+	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
+	geo = shape->geo;
+	SWAP(geo->cur_area, geo->last_area, area_t *);
+	clean_shape(shape);
+	cnt++;
+    }
+
+    /* Compute area of the coord. */
+    poses = (co_aix (*)[2])malloc(sizeof(co_aix [2]) * 2 * cnt);
+    if(poses == NULL)
+	return ERR;
+
+    pos_cnt = 0;
+    for(shape = STAILQ_HEAD(coord->members);
+	shape != NULL;
+	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
+	geo = shape->geo;
+	
+	area_to_positions(geo->cur_area, poses + pos_cnt);
+	pos_cnt += 2;
+    }
+
+    SWAP(coord->cur_area, coord->last_area, area_t *);
+    area_init(coord->cur_area, pos_cnt, poses);
+    free(poses);
+    
+    coord->flags &= ~COF_DIRTY;
+
+    return OK;
+}
+
+static int clean_rdman_coords(redraw_man_t *rdman) {
+    coord_t *coord;
+    coord_t **dirty_coords;
+    int n_dirty_coords;
+    int i, r;
+
+    n_dirty_coords = rdman->n_dirty_coords;
+    if(n_dirty_coords > 0) {
+	dirty_coords = rdman->dirty_coords;
+	_insert_sort((void **)dirty_coords, n_dirty_coords,
+		     OFFSET(coord_t, order));
+	for(i = 0; i < n_dirty_coords; i++) {
+	    coord = dirty_coords[i];
+	    if(!(coord->flags & COF_DIRTY))
+		continue;
+	    r = clean_coord(coord);
+	    if(r != OK)
+		return ERR;
+	    /* These two steps can be avoided for drawing all. */
+	    add_dirty_area(rdman, &coord->areas[0]);
+	    add_dirty_area(rdman, &coord->areas[1]);
+	}
+	rdman->n_dirty_coords = 0;
+    }
+    return OK;
+}
+
 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr) {
     extern void redraw_man_destroy(redraw_man_t *rdman);
 
@@ -195,6 +293,9 @@
     geo = elmpool_elm_alloc(rdman->geo_pool);
     if(geo == NULL)
 	return ERR;
+    
+    geo_init(geo);
+
     sh_attach_geo(shape, geo);
     STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo);
     rdman->n_geos++;
@@ -223,6 +324,10 @@
     return OK;
 }
 
+/*! \brief Remove a shape object from redraw manager.
+ *
+ * TODO: redraw shape objects that overlaid with removed one.
+ */
 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) {
     STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo);
     elmpool_elm_free(rdman->geo_pool, shape->geo);
@@ -339,108 +444,24 @@
     return OK;
 }
 
-static void clean_shape(shape_t *shape) {
-    switch(shape->sh_type) {
-    case SHT_PATH:
-	sh_path_transform(shape);
-	break;
-    }
-    shape->geo->flags &= ~GEF_DIRTY;
-}
-
-static void area_to_positions(area_t *area, co_aix (*poses)[2]) {
-    poses[0][0] = area->x;
-    poses[0][1] = area->y;
-    poses[1][0] = area->x + area->w;
-    poses[1][1] = area->y + area->h;;
-}
-
-static int clean_coord(coord_t *coord) {
-    shape_t *shape;
-    geo_t *geo;
-    co_aix (*poses)[2];
-    int cnt, pos_cnt;
-    int i;
-
-    compute_aggr_of_coord(coord);
-
-    /* Clean member shapes. */
-    cnt = 0;
-    for(shape = STAILQ_HEAD(coord->members);
-	shape != NULL;
-	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
-	geo = shape->geo;
-	SWAP(geo->cur_area, geo->last_area, area_t *);
-	clean_shape(shape);
-	cnt++;
-    }
-
-    /* Compute area of the coord. */
-    poses = (co_aix (*)[2])malloc(sizeof(co_aix [2]) * 2 * cnt);
-    if(poses == NULL)
-	return ERR;
-
-    pos_cnt = 0;
-    for(shape = STAILQ_HEAD(coord->members);
-	shape != NULL;
-	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
-	geo = shape->geo;
-	
-	area_to_positions(&geo->areas[0], poses + pos_cnt);
-	pos_cnt += 2;
-	area_to_positions(&geo->areas[1], poses + pos_cnt);
-	pos_cnt += 2;
-    }
-
-#if 0
-    for(i = 0; i < pos_cnt; i++)
-	coord_trans_pos(coord, &poses[i][0], &poses[i][1]);
-#endif
-
-    SWAP(coord->cur_area, coord->last_area, area_t *);
-    area_init(coord->cur_area, pos_cnt, poses);
-    free(poses);
-    
-    coord->flags &= ~COF_DIRTY;
-
-    return OK;
-}
-
-static int clean_rdman_coords(redraw_man_t *rdman) {
-    coord_t *coord;
-    coord_t **dirty_coords;
-    int n_dirty_coords;
-    int i, r;
-
-    n_dirty_coords = rdman->n_dirty_coords;
-    if(n_dirty_coords > 0) {
-	dirty_coords = rdman->dirty_coords;
-	_insert_sort((void **)dirty_coords, n_dirty_coords,
-		     OFFSET(coord_t, order));
-	for(i = 0; i < n_dirty_coords; i++) {
-	    coord = dirty_coords[i];
-	    if(!(coord->flags & COF_DIRTY))
-		continue;
-	    r = clean_coord(coord);
-	    if(r != OK)
-		return ERR;
-	    /* These two steps can be avoided for drawing all. */
-	    add_dirty_area(rdman, &coord->areas[0]);
-	    add_dirty_area(rdman, &coord->areas[1]);
-	}
-	rdman->n_dirty_coords = 0;
-    }
-    return OK;
-}
+/* Drawing and Redrawing
+ * ============================================================
+ */
 
 static void draw_shape(redraw_man_t *rdman, shape_t *shape) {
     switch(shape->sh_type) {
     case SHT_PATH:
 	sh_path_draw(shape, rdman->cr);
 	break;
+#ifdef UNITTEST
+    default:
+	sh_dummy_draw(shape, rdman->cr);
+	break;
+#endif /* UNITTEST */
     }
 }
 
+#ifndef UNITTEST
 static void clean_clip(cairo_t *cr) {
     cairo_pattern_t *pt;
 
@@ -461,7 +482,6 @@
 
     cr = rdman->cr;
 
-    cairo_reset_clip(cr);
     for(i = 0; i < n_dirty_areas; i++) {
 	area = dirty_areas[i];
 	cairo_rectangle(cr, area->x, area->y, area->w, area->h);
@@ -470,6 +490,18 @@
     cairo_clip(cr);
 }
 
+static void reset_clip(redraw_man_t *rdman) {
+    cairo_reset_clip(rdman->cr);
+}
+#else /* UNITTEST */
+static void make_clip(redraw_man_t *rdman, int n_dirty_areas,
+                      area_t **dirty_areas) {
+}
+
+static void reset_clip(redraw_man_t *rdman) {
+}
+#endif /* UNITTEST */
+
 static void draw_shapes_in_areas(redraw_man_t *rdman,
 				 int n_areas,
 				 area_t **areas) {
@@ -555,11 +587,10 @@
 	make_clip(rdman, n_dirty_areas, dirty_areas);
 	draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas);
 	rdman->n_dirty_areas = 0;
+	reset_clip(rdman);
     }
     rdman->n_dirty_areas = 0;
 
-    cairo_reset_clip(rdman->cr);
-
     return OK;
 }
 
@@ -569,7 +600,6 @@
     clean_rdman_coords(rdman);
     rdman->n_dirty_areas = 0;
 
-    cairo_reset_clip(rdman->cr);
     for(geo = STAILQ_HEAD(rdman->all_geos);
 	geo != NULL;
 	geo = STAILQ_NEXT(geo_t, next, geo)) {
@@ -577,7 +607,6 @@
 	    clean_shape(geo->shape);
 	draw_shape(rdman, geo->shape);
     }
-    cairo_reset_clip(rdman->cr);
 
     return OK;
 }
@@ -653,8 +682,8 @@
     shape_t shape;
     co_aix x, y;
     co_aix w, h;
+    int draw_cnt;
 };
-typedef struct _sh_dummy sh_dummy_t;
 
 shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) {
     sh_dummy_t *dummy;
@@ -663,10 +692,13 @@
     if(dummy == NULL)
 	return NULL;
 
+    memset(dummy, 0, sizeof(sh_dummy_t));
+
     dummy->x = x;
     dummy->y = y;
     dummy->w = w;
     dummy->h = h;
+    dummy->draw_cnt = 0;
 
     return (shape_t *)dummy;
 }
@@ -693,10 +725,18 @@
 	poses[1][0] = x2;
 	poses[1][1] = y2;
     
-	geo_init(shape->geo, 2, poses);
+	if(shape->geo)
+	    geo_from_positions(shape->geo, 2, poses);
     }
 }
 
+void sh_dummy_draw(shape_t *shape, cairo_t *cr) {
+    sh_dummy_t *dummy;
+
+    dummy = (sh_dummy_t *)shape;
+    dummy->draw_cnt++;
+}
+
 void test_rdman_find_overlaid_shapes(void) {
     redraw_man_t rdman;
     geo_t geo;
@@ -732,7 +772,8 @@
     pos[0][1] = 120;
     pos[1][0] = 100 + 140;
     pos[1][1] = 120 + 40;
-    geo_init(&geo, 2, pos);
+    geo_init(&geo);
+    geo_from_positions(&geo, 2, pos);
 
     n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays);
     CU_ASSERT(n == 2);
@@ -747,11 +788,47 @@
     redraw_man_destroy(&rdman);
 }
 
+void test_rdman_redraw_changed(void) {
+    coord_t *coords[3];
+    shape_t *shapes[3];
+    sh_dummy_t **dummys;
+    redraw_man_t *rdman;
+    redraw_man_t _rdman;
+    int i;
+
+    dummys = (sh_dummy_t **)shapes;
+
+    rdman = &_rdman;
+    redraw_man_init(rdman, NULL);
+    for(i = 0; i < 3; i++) {
+	shapes[i] = sh_dummy_new(0, 0, 50, 50);
+	coords[i] = rdman_coord_new(rdman, rdman->root_coord);
+	coords[i]->matrix[2] = 10 + i * 100;
+	coords[i]->matrix[5] = 10 + i * 100;
+	rdman_coord_changed(rdman, coords[i]);
+	rdman_add_shape(rdman, shapes[i], coords[i]);
+    }
+    rdman_redraw_all(rdman);
+    CU_ASSERT(dummys[0]->draw_cnt == 1);
+    CU_ASSERT(dummys[1]->draw_cnt == 1);
+    CU_ASSERT(dummys[2]->draw_cnt == 1);
+    
+    coords[2]->matrix[2] = 100;
+    coords[2]->matrix[5] = 100;
+    rdman_coord_changed(rdman, coords[2]);
+    rdman_redraw_changed(rdman);
+
+    CU_ASSERT(dummys[0]->draw_cnt == 1);
+    CU_ASSERT(dummys[1]->draw_cnt == 2);
+    CU_ASSERT(dummys[2]->draw_cnt == 2);
+}
+
 CU_pSuite get_redraw_man_suite(void) {
     CU_pSuite suite;
 
     suite = CU_add_suite("Suite_redraw_man", NULL, NULL);
     CU_ADD_TEST(suite, test_rdman_find_overlaid_shapes);
+    CU_ADD_TEST(suite, test_rdman_redraw_changed);
 
     return suite;
 }