Mercurial > MadButterfly
changeset 158:c1cdd3fcd28f
Postponing rdman_coord_free() and rdman_remove_shape().
rdman will access free memory if coords or shapes are free when it
is dirty. The requests are postponed until rdman is clean.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Fri, 03 Oct 2008 10:22:08 +0800 |
parents | 5cd12609a5c7 |
children | b90abd31a281 |
files | src/event.c src/mb_types.h src/redraw_man.c src/redraw_man.h src/tools.h |
diffstat | 5 files changed, 210 insertions(+), 122 deletions(-) [+] |
line wrap: on
line diff
--- a/src/event.c Wed Oct 01 16:30:05 2008 +0800 +++ b/src/event.c Fri Oct 03 10:22:08 2008 +0800 @@ -23,6 +23,8 @@ return OK; } +DARRAY_DEFINE(geos, geo_t *); + /*! \brief Add a geo_t object to general geo list. * * General geo list can use to temporary keep a list of geo_t @@ -31,21 +33,10 @@ * from a redraw manager. */ static int add_gen_geo(redraw_man_t *rdman, geo_t *geo) { - int max_gen_geos; int r; - if(rdman->n_gen_geos >= rdman->max_gen_geos) { - max_gen_geos = rdman->max_gen_geos + ARRAY_EXT_SZ; - r = extend_memblk((void **)&rdman->gen_geos, - sizeof(geo_t *) * rdman->n_gen_geos, - sizeof(geo_t *) * max_gen_geos); - if(r != OK) - return ERR; - rdman->max_gen_geos = max_gen_geos; - } - - rdman->gen_geos[rdman->n_gen_geos++] = geo; - return OK; + r = geos_add(&rdman->gen_geos, geo); + return r == 0? OK: ERR; } static int collect_shapes_at_point(redraw_man_t *rdman, @@ -57,7 +48,7 @@ if(r != OK) return ERR; - rdman->n_gen_geos = 0; + rdman->gen_geos.num = 0; for(geo = rdman_geos(rdman, NULL); geo != NULL; @@ -94,9 +85,9 @@ cairo_t *cr; int i; - geos = rdman->gen_geos; + geos = rdman->gen_geos.ds; cr = rdman->cr; - for(i = rdman->n_gen_geos - 1; i >= 0; i--) { + for(i = rdman->gen_geos.num - 1; i >= 0; i--) { geo = geos[i]; if(geo->flags & GEF_HIDDEN) continue;
--- a/src/mb_types.h Wed Oct 01 16:30:05 2008 +0800 +++ b/src/mb_types.h Fri Oct 03 10:22:08 2008 +0800 @@ -53,6 +53,7 @@ }; #define GEF_DIRTY 0x1 #define GEF_HIDDEN 0x2 +#define GEF_FREE 0x4 extern int is_overlay(area_t *r1, area_t *r2); extern void area_init(area_t *area, int n_pos, co_aix pos[][2]); @@ -120,6 +121,7 @@ #define COF_SKIP_TRIVAL 0x8 /*!< Temporary skip descendants * when trivaling. */ +#define COF_FREE 0x10 extern void coord_init(coord_t *co, coord_t *parent); extern void coord_trans_pos(coord_t *co, co_aix *x, co_aix *y); @@ -160,22 +162,9 @@ }; enum { SHT_UNKNOW, SHT_PATH, SHT_TEXT, SHT_RECT }; -#define sh_attach_geo(sh, g) \ - do { \ - (sh)->geo = g; \ - (g)->shape = (shape_t *)(sh); \ - } while(0) -#define sh_detach_geo(sh) \ - do { \ - (sh)->geo->shape = NULL; \ - (sh)->geo = NULL; \ - } while(0) -#define sh_get_geo(sh) ((sh)->geo) #define sh_get_mouse_event_subject(sh) ((sh)->geo->mouse_event) #define sh_hide(sh) do { (sh)->geo->flags |= GEF_HIDDEN; } while(0) #define sh_show(sh) do { (sh)->geo->flags &= ~GEF_HIDDEN; } while(0) -#define sh_attach_coord(sh, coord) do { (sh)->coord = coord; } while(0) -#define sh_detach_coord(sh) do { (sh)->coord = NULL; } while(0) #endif /* __MB_TYPES_H_ */
--- a/src/redraw_man.c Wed Oct 01 16:30:05 2008 +0800 +++ b/src/redraw_man.c Fri Oct 03 10:22:08 2008 +0800 @@ -12,6 +12,24 @@ /* NOTE: bounding box should also consider width of stroke. */ +#define sh_attach_geo(sh, g) \ + do { \ + (sh)->geo = g; \ + (g)->shape = (shape_t *)(sh); \ + } while(0) +#define sh_detach_geo(sh) \ + do { \ + (sh)->geo->shape = NULL; \ + (sh)->geo = NULL; \ + } while(0) +#define sh_get_geo(sh) ((sh)->geo) +#define sh_attach_coord(sh, coord) do { (sh)->coord = coord; } while(0) +#define sh_detach_coord(sh) do { (sh)->coord = NULL; } while(0) +#define rdman_is_dirty(rdman) \ + ((rdman)->dirty_coords.num != 0 || \ + (rdman)->dirty_geos.num != 0 || \ + (rdman)->dirty_areas.num != 0) + #define OK 0 #define ERR -1 @@ -78,76 +96,38 @@ } } -static int extend_memblk(void **buf, int o_size, int n_size) { - void *new_buf; +DARRAY_DEFINE(coords, coord_t *); +DARRAY_DEFINE(geos, geo_t *); +DARRAY_DEFINE(areas, area_t *); - new_buf = realloc(*buf, n_size); - if(new_buf == NULL) - return ERR; +/*! Use \brief DARRAY to implement dirty & free lists. + */ +#define ADD_DATA(sttype, field, v) \ + int r; \ + r = sttype ## _add(&rdman->field, v); \ + return r == 0? OK: ERR; - *buf = new_buf; - - return OK; -} static int add_dirty_coord(redraw_man_t *rdman, coord_t *coord) { - int max_dirty_coords; - int r; - - if(rdman->n_dirty_coords >= rdman->max_dirty_coords) { - /* Max of dirty_coords is not big enough. */ - max_dirty_coords = rdman->max_dirty_coords + 16; - - r = extend_memblk((void **)&rdman->dirty_coords, - sizeof(coord_t *) * rdman->n_dirty_coords, - sizeof(coord_t *) * max_dirty_coords); - if(r != OK) - return ERR; - rdman->max_dirty_coords = max_dirty_coords; - } - - rdman->dirty_coords[rdman->n_dirty_coords++] = coord; coord->flags |= COF_DIRTY; - return OK; + ADD_DATA(coords, dirty_coords, coord); } static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) { - int max_dirty_geos; - int r; - - if(rdman->n_dirty_geos >= rdman->max_dirty_geos) { - max_dirty_geos = rdman->max_dirty_geos + ARRAY_EXT_SZ; - r = extend_memblk((void **)&rdman->dirty_geos, - sizeof(geo_t *) * rdman->n_dirty_geos, - sizeof(geo_t *) * max_dirty_geos); - if(r != OK) - return ERR; - rdman->max_dirty_geos = max_dirty_geos; - } - - rdman->dirty_geos[rdman->n_dirty_geos++] = geo; - return OK; + geo->flags |= GEF_DIRTY; + ADD_DATA(geos, dirty_geos, geo); } static int add_dirty_area(redraw_man_t *rdman, area_t *area) { - int max_dirty_areas; - int r; + ADD_DATA(areas, dirty_areas, area); +} - if(rdman->n_dirty_areas >= rdman->max_dirty_areas) { - /* every geo object and coord object can contribute 2 areas. - * rdman_draw_area() may also contribute 1 area. - */ - max_dirty_areas = rdman->max_dirty_areas + ARRAY_EXT_SZ; - r = extend_memblk((void **)&rdman->dirty_areas, - sizeof(area_t *) * rdman->n_dirty_areas, - sizeof(area_t *) * max_dirty_areas); - if(r != OK) - return ERR; - rdman->max_dirty_areas = max_dirty_areas; - } +static int add_free_coord(redraw_man_t *rdman, coord_t *coord) { + ADD_DATA(coords, free_coords, coord); +} - rdman->dirty_areas[rdman->n_dirty_areas++] = area; - return OK; +static int add_free_geo(redraw_man_t *rdman, geo_t *geo) { + ADD_DATA(geos, free_geos, geo); } static void area_to_positions(area_t *area, co_aix (*poses)[2]) { @@ -294,13 +274,23 @@ void redraw_man_destroy(redraw_man_t *rdman) { coord_t *coord, *saved_coord; + geo_t *member; coord = postorder_coord_subtree(rdman->root_coord, NULL); while(coord) { saved_coord = coord; coord = postorder_coord_subtree(rdman->root_coord, coord); + FORMEMBERS(saved_coord, member) { + rdman_remove_shape(rdman, member->shape); + } rdman_coord_free(rdman, saved_coord); } + FORMEMBERS(saved_coord, member) { + rdman_remove_shape(rdman, member->shape); + } + /* Resources of root_coord is free by elmpool_free() or + * caller; for canvas + */ elmpool_free(rdman->coord_pool); elmpool_free(rdman->geo_pool); @@ -308,12 +298,13 @@ elmpool_free(rdman->observer_pool); elmpool_free(rdman->subject_pool); elmpool_free(rdman->paint_color_pool); - if(rdman->dirty_coords) - free(rdman->dirty_coords); - if(rdman->dirty_geos) - free(rdman->dirty_geos); - if(rdman->gen_geos) - free(rdman->gen_geos); + + DARRAY_DESTROY(&rdman->dirty_coords); + DARRAY_DESTROY(&rdman->dirty_geos); + DARRAY_DESTROY(&rdman->dirty_areas); + DARRAY_DESTROY(&rdman->gen_geos); + DARRAY_DESTROY(&rdman->free_coords); + DARRAY_DESTROY(&rdman->free_geos); } @@ -354,7 +345,6 @@ geo_attach_coord(geo, coord); /* New one should be dirty to recompute it when drawing. */ - geo->flags |= GEF_DIRTY; r = add_dirty_geo(rdman, geo); if(r != OK) return ERR; @@ -368,15 +358,31 @@ /*! \brief Remove a shape object from redraw manager. * * \note Shapes should be removed after redrawing or when rdman is in clean. + * \note Removing shapes or coords when a rdman is dirty, removing + * is postponsed. * \todo redraw shape objects that overlaid with removed one. - * \todo To allow shapes be removed at anytime. */ int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { geo_t *geo; coord_t *coord; + int r; geo = shape->geo; coord = shape->coord; + + if(rdman_is_dirty(rdman)) { + geo->flags |= GEF_FREE | GEF_HIDDEN; + if(!(geo->flags & GEF_DIRTY)) { + r = add_dirty_geo(rdman, geo); + if(r != OK) + return ERR; + } + r = add_free_geo(rdman, geo); + if(r != OK) + return ERR; + return OK; + } + geo_detach_coord(geo, coord); subject_free(&rdman->ob_factory, geo->mouse_event); sh_detach_geo(shape); @@ -428,20 +434,49 @@ * * \param coord is a coord_t without children and members. * \return 0 for successful, -1 for error. + * + * \note Removing coords when the rdman is dirty, the removing is postponsed. */ int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { coord_t *parent; + coord_t *child; + geo_t *member; + int r; parent = coord->parent; if(parent == NULL) return ERR; + if(rdman_is_dirty(rdman)) { + FORCHILDREN(coord, child) { + if(!(child->flags & COF_FREE)) + return ERR; + } + FORMEMBERS(coord, member) { + if(!(member->flags & GEF_FREE)) + return ERR; + } + coord->flags |= COF_FREE | COF_HIDDEN; + if(!(coord->flags & COF_DIRTY)) { + r = add_dirty_coord(rdman, coord); + if(r != OK) + return ERR; + } + r = add_free_coord(rdman, coord); + if(r != OK) + return ERR; + return OK; + } + if(FIRST_MEMBER(coord) != NULL) return ERR; if(FIRST_CHILD(coord) != NULL) return ERR; + if(coord->flags & COF_FREE) + return ERR; + /* Free canvas (\ref redraw) */ if(coord->flags & COF_OWN_CANVAS) free_canvas(coord->canvas); @@ -517,7 +552,6 @@ r = add_dirty_geo(rdman, geo); if(r == ERR) return ERR; - geo->flags |= GEF_DIRTY; return OK; } @@ -655,9 +689,9 @@ int n_dirty_coords; int i, r; - n_dirty_coords = rdman->n_dirty_coords; + n_dirty_coords = rdman->dirty_coords.num; if(n_dirty_coords > 0) { - dirty_coords = rdman->dirty_coords; + dirty_coords = rdman->dirty_coords.ds; _insert_sort((void **)dirty_coords, n_dirty_coords, OFFSET(coord_t, order)); for(i = 0; i < n_dirty_coords; i++) { @@ -671,7 +705,7 @@ add_dirty_area(rdman, &coord->areas[0]); add_dirty_area(rdman, &coord->areas[1]); } - rdman->n_dirty_coords = 0; + rdman->dirty_coords.num = 0; } return OK; } @@ -682,9 +716,9 @@ geo_t **dirty_geos; geo_t *visit_geo; - n_dirty_geos = rdman->n_dirty_geos; + n_dirty_geos = rdman->dirty_geos.num; if(n_dirty_geos > 0) { - dirty_geos = rdman->dirty_geos; + dirty_geos = rdman->dirty_geos.ds; for(i = 0; i < n_dirty_geos; i++) { visit_geo = dirty_geos[i]; if(!(visit_geo->flags & GEF_DIRTY)) @@ -695,7 +729,7 @@ add_dirty_area(rdman, visit_geo->cur_area); add_dirty_area(rdman, visit_geo->last_area); } - rdman->n_dirty_geos = 0; + rdman->dirty_geos.num = 0; } return OK; @@ -952,24 +986,41 @@ event_t event; ob_factory_t *factory; subject_t *redraw; + geo_t *geo; + coord_t *coord; + int i; r = clean_rdman_dirties(rdman); if(r != OK) return ERR; - n_dirty_areas = rdman->n_dirty_areas; - dirty_areas = rdman->dirty_areas; + n_dirty_areas = rdman->dirty_areas.num; + dirty_areas = rdman->dirty_areas.ds; if(n_dirty_areas > 0) { /*! \brief Draw shapes in preorder of coord tree and support opacity * rules. */ clean_canvas(rdman->cr); draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); - copy_cr_2_backend(rdman, rdman->n_dirty_areas, rdman->dirty_areas); - rdman->n_dirty_areas = 0; + copy_cr_2_backend(rdman, rdman->dirty_areas.num, + rdman->dirty_areas.ds); + rdman->dirty_areas.num = 0; reset_clip(rdman); } - rdman->n_dirty_areas = 0; + rdman->dirty_areas.num = 0; + + /* Free postponsed removing */ + for(i = 0; i < rdman->free_geos.num; i++) { + geo = rdman->free_geos.ds[i]; + rdman_remove_shape(rdman, geo->shape); + } + DARRAY_CLEAN(&rdman->free_geos); + + for(i = 0; i < rdman->free_coords.num; i++) { + coord = rdman->free_coords.ds[i]; + rdman_remove_shape(rdman, coord); + } + DARRAY_CLEAN(&rdman->free_coords); factory = rdman_get_ob_factory(rdman); redraw = rdman_get_redraw_subject(rdman); @@ -1003,7 +1054,7 @@ * \sa * - rdman_redraw_all() * - rdman_redraw_changed() - * = draw_shapes_in_areas() + * - draw_shapes_in_areas() */ int rdman_redraw_all(redraw_man_t *rdman) {
--- a/src/redraw_man.h Wed Oct 01 16:30:05 2008 +0800 +++ b/src/redraw_man.h Fri Oct 03 10:22:08 2008 +0800 @@ -6,6 +6,10 @@ #include "mb_types.h" #include "observer.h" +DARRAY(coords, coord_t *); +DARRAY(geos, geo_t *); +DARRAY(areas, area_t *); + /*! \brief Manage redrawing of shapes (graphic elements). * * Every coord_t and geo_t object is assigned with a unique @@ -33,23 +37,14 @@ elmpool_t *subject_pool; elmpool_t *paint_color_pool; - int max_dirty_coords; - int n_dirty_coords; - coord_t **dirty_coords; /*!< coordinates their transform - * matric are chagned. - */ + coords_t dirty_coords; + geos_t dirty_geos; + areas_t dirty_areas; - int max_dirty_geos; - int n_dirty_geos; - geo_t **dirty_geos; /*!< geometries that need re-computed */ + geos_t gen_geos; - int max_dirty_areas; - int n_dirty_areas; - area_t **dirty_areas; /*!< \brief are areas need to redraw. */ - - int max_gen_geos; - int n_gen_geos; - geo_t **gen_geos; /* general geo list (for temporary store) */ + coords_t free_coords; + geos_t free_geos; cairo_t *cr; cairo_t *backend;
--- a/src/tools.h Wed Oct 01 16:30:05 2008 +0800 +++ b/src/tools.h Fri Oct 03 10:22:08 2008 +0800 @@ -62,6 +62,68 @@ } \ } while(0) +/*! \defgroup darray Dynamic Array + * + * DARRAY is a dynamic sized array/list, it's length is a variable. + * It is extended, automatically, if it is full and more elemnts are + * putted in. + * + * Users of DARRAY must declare a new type to store data. The way to + * declear a new type is to invoke DARRAY() with paramters of name of + * type and type of data to be stored in. The new storage type is named + * with foo_t where foo is the name you pass in. + * + * DARRAY_DEFINE() is inovked to define foo_add() function; foo is name + * of storage type. You can call foo_add() to add a data element + * into a storage object. + * + * Get ith element in a storage object, use + * \code + * obj->ds[i] + * \endcode + * + * To loop over elements in a storage object, us + * \code + * for(i = 0; i < obj->num; i++) { + * v = obj->ds[i]; + * ...... + * } + * \endcode + * @{ + */ +/*! \brief Declare a DARRAY storage type. + * + * \param name is name of storage type. + * \param type is type of data elements that will be stored in. + * + * Type of <name>_t is defined by the macro. It is used to define a + * storage object to contain data elements. + */ +#define DARRAY(name, type) \ + struct _ ## name { \ + int max, num; \ + type *ds; \ + }; \ + typedef struct _ ## name name ## _t +#define DARRAY_DEFINE(name, type) \ + static int name ## _add(name ## _t *da, type v) { \ + type *new_ds; \ + int max; \ + if(da->num >= (da)->max) { \ + max = (da)->max + 32; \ + new_ds = realloc(da->ds, \ + max * sizeof(type)); \ + if(new_ds == NULL) return -1; \ + da->ds = new_ds; \ + da->max = max; \ + } \ + da->ds[da->num++] = v; \ + return 0; \ + } +#define DARRAY_CLEAN(da) do { (da)->num = 0; } while(0) +#define DARRAY_INIT(da) do { (da)->num = (da)->max = 0; (da)->ds = NULL; } +#define DARRAY_DESTROY(da) do { if((da)->ds) free((da)->ds); } while(0) +/* @} */ #include <stdlib.h>