Mercurial > MadButterfly
changeset 12:79e9edf4c00a
Add redraw manager
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Mon, 28 Jul 2008 17:45:36 +0800 |
parents | 128af06c876c |
children | ed55009d96d3 |
files | orgfiles/auto_update.muse src/Makefile src/X_main.c src/coord.c src/geo.c src/mb_types.h src/redraw_man.c src/redraw_man.h src/shape_path.c src/shapes.h src/testcase.c src/tools.c src/tools.h |
diffstat | 13 files changed, 773 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orgfiles/auto_update.muse Mon Jul 28 17:45:36 2008 +0800 @@ -0,0 +1,24 @@ +When an object change it's size, position, or components inside it, +other objects overlaid with the object in old or new positions should +be re-drawed. The place that the object is resident in old or new +position should be cleared before re-drawing. We need a system +to determine and track effected by the change of an object. + +The graphics are grouped into groups in tree-hierachy. One group +can be part of another group. When a group's transformation matrix +is chagned, all child groups should be affected. All it's members +should also be re-drawed. All members of a group been changed are +linked into update list in their order. The one more close to +tree root is more earier in the list. + +Transformations can only apply to groups. A tree of coord_t is +maintained to model relationships of groups. Coord_t is coordination, +a transfromation from user space to upper level's space or devcie space. + +coord_t must know graphics in respective group. Once transformation +matrix of a coord_t object changed, it can ask members to +re-drawed them-self. + +Changes of the transformation of a coord_t should be propagated to +child coord_t objects/groups. +
--- a/src/Makefile Sat Jul 26 06:34:15 2008 +0800 +++ b/src/Makefile Mon Jul 28 17:45:36 2008 +0800 @@ -1,4 +1,4 @@ -SRCS = coord.c geo.c shape_path.c +SRCS = coord.c geo.c shape_path.c redraw_man.c tools.c OBJS = ${SRCS:C/(.*)\.c/\1.o/g} TESTCASE_OBJS = ${SRCS:C/(.*)\.c/testcase-\1.o/g} CFLAGS = -Wall -I/usr/local/include `pkg-config --cflags cairo`
--- a/src/X_main.c Sat Jul 26 06:34:15 2008 +0800 +++ b/src/X_main.c Mon Jul 28 17:45:36 2008 +0800 @@ -7,19 +7,24 @@ #include <string.h> #include "shapes.h" +#include "redraw_man.h" void draw_path(cairo_t *cr, int w, int h) { + redraw_man_t rdman; shape_t *path; - coord_t coord; + coord_t *coord; + + redraw_man_init(&rdman); + coord = rdman.root_coord; path = sh_path_new("M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z "); - memset(coord.aggr_matrix, 0, sizeof(co_aix) * 6); - coord.aggr_matrix[0] = 0.8; - coord.aggr_matrix[1] = 0; - coord.aggr_matrix[2] = 20; - coord.aggr_matrix[4] = 0.8; - coord.aggr_matrix[5] = 20; - sh_path_transform(path, &coord); + coord->aggr_matrix[0] = 0.8; + coord->aggr_matrix[1] = 0; + coord->aggr_matrix[2] = 20; + coord->aggr_matrix[4] = 0.8; + coord->aggr_matrix[5] = 20; + rdman_add_shape(&rdman, (shape_t *)path, coord); + sh_path_transform(path); sh_path_draw(path, cr); } @@ -33,8 +38,8 @@ draw_path(cr, w, h); cairo_set_source_rgb(cr, 0.5, 0.9, 0.8); cairo_move_to(cr, 10, h / 2); - cairo_set_font_size(cr, 48.0); - cairo_text_path(cr, "hello \xe4\xb8\xad\xe6\x96\x87"); + cairo_set_font_size(cr, 36.0); + cairo_text_path(cr, "hello \xe6\xbc\xa2\xe5\xad\x97"); cairo_set_line_width(cr, 2); cairo_stroke(cr); }
--- a/src/coord.c Sat Jul 26 06:34:15 2008 +0800 +++ b/src/coord.c Mon Jul 28 17:45:36 2008 +0800 @@ -6,6 +6,9 @@ #include <string.h> #include "mb_types.h" + +#define ASSERT(x) + /* To keep possibility of changing type of aix */ #define MUL(a, b) ((a) * (b)) #define ADD(a, b) ((a) + (b)) @@ -46,22 +49,22 @@ visit = start; while(visit) { - child = visit->children; + child = STAILQ_HEAD(visit->children); while(child) { compute_transform_function(child); - child = child->sibling; + child = STAILQ_NEXT(coord_t, sibling, child); } - if(visit->children) - visit = visit->children; - else if(visit->sibling) - visit = visit->sibling; + if(STAILQ_HEAD(visit->children)) + visit = STAILQ_HEAD(visit->children); + else if(STAILQ_NEXT(coord_t, sibling, visit)) + visit = STAILQ_NEXT(coord_t, sibling, visit); else { next = NULL; while(visit->parent && visit->parent != start) { visit = visit->parent; - if(visit->sibling) { - next = visit->sibling; + if(STAILQ_NEXT(coord_t, sibling, visit)) { + next = STAILQ_NEXT(coord_t, sibling, visit); break; } } @@ -70,12 +73,17 @@ } } +/*! \brief Initialize a coord object. + * + * The object is cleared and matrix was initialized to ID. + * The object is be a children of specified parent. + */ void coord_init(coord_t *co, coord_t *parent) { memset(co, 0, sizeof(coord_t)); if(parent) { + /* insert at tail of children list. */ co->parent = parent; - co->sibling = parent->children; - parent->children = co; + STAILQ_INS_TAIL(parent->children, coord_t, sibling, co); } co->matrix[0] = 1; co->matrix[4] = 1; @@ -94,6 +102,34 @@ *y = ny; } +coord_t *preorder_coord_tree(coord_t *last) { + coord_t *next; + + ASSERT(last == NULL); + + if(STAILQ_HEAD(last->children)) + next = STAILQ_HEAD(last->children); + else { + next = last; + while(next != NULL && STAILQ_NEXT(coord_t, sibling, next) == NULL) + next = next->parent; + if(next) + next = STAILQ_NEXT(coord_t, sibling, next); + } + + return next; +} + +void sh_attach_coord(shape_t *sh, coord_t *coord) { + STAILQ_INS_TAIL(coord->members, shape_t, coord_mem_next, sh); + sh->coord = coord; +} + +void sh_detach_coord(shape_t *sh) { + STAILQ_REMOVE(sh->coord->members, shape_t, coord_mem_next, sh); + sh->coord = NULL; +} + #ifdef UNITTEST #include <CUnit/Basic.h> @@ -157,11 +193,38 @@ CU_ASSERT(y == 99); } +void test_preorder_coord_tree(void) { + coord_t elms[6]; + coord_t *last; + + coord_init(elms, NULL); + coord_init(elms + 1, elms); + coord_init(elms + 2, elms); + coord_init(elms + 3, elms + 1); + coord_init(elms + 4, elms + 1); + coord_init(elms + 5, elms + 2); + + last = elms; + last = preorder_coord_tree(last); + CU_ASSERT(last == elms + 1); + last = preorder_coord_tree(last); + CU_ASSERT(last == elms + 3); + last = preorder_coord_tree(last); + CU_ASSERT(last == elms + 4); + last = preorder_coord_tree(last); + CU_ASSERT(last == elms + 2); + last = preorder_coord_tree(last); + CU_ASSERT(last == elms + 5); + last = preorder_coord_tree(last); + CU_ASSERT(last == NULL); +} + CU_pSuite get_coord_suite(void) { CU_pSuite suite; suite = CU_add_suite("Suite_coord", NULL, NULL); CU_ADD_TEST(suite, test_update_aggr_matrix); + CU_ADD_TEST(suite, test_preorder_coord_tree); return suite; }
--- a/src/geo.c Sat Jul 26 06:34:15 2008 +0800 +++ b/src/geo.c Mon Jul 28 17:45:36 2008 +0800 @@ -7,15 +7,6 @@ #include <stdio.h> #include "mb_types.h" -struct _geo { - co_aix x, y; - co_aix w, h; - co_aix rel_x, rel_y; - co_aix orig_x, orig_y; - int n_subs; - struct _geo *subs; -}; - static int is_scale_overlay(co_aix x1, co_aix w1, co_aix x2, co_aix w2) { if(x1 > x2) { if((x1 - x2) >= w2) @@ -27,7 +18,7 @@ return 1; } -static int is_overlay(geo_t *r1, geo_t *r2) { +static int _is_overlay(geo_t *r1, geo_t *r2) { if(!is_scale_overlay(r1->x, r1->w, r2->x, r2->w)) return 0; if(!is_scale_overlay(r1->y, r1->h, r2->y, r2->h)) @@ -36,6 +27,10 @@ return 1; } +int is_overlay(geo_t *r1, geo_t *r2) { + return _is_overlay(r1, r2); +} + void geo_init(geo_t *g, int n_pos, co_aix pos[][2]) { co_aix min_x, max_x; co_aix min_y, max_y; @@ -68,7 +63,7 @@ ov_idx = 0; for(i = 0; i < n_others; i++) { - if(is_overlay(g, others[i])) + if(_is_overlay(g, others[i])) overlays[ov_idx++] = others[i]; } *n_overlays = ov_idx;
--- a/src/mb_types.h Sat Jul 26 06:34:15 2008 +0800 +++ b/src/mb_types.h Mon Jul 28 17:45:36 2008 +0800 @@ -1,8 +1,11 @@ #ifndef __MB_TYPES_H_ #define __MB_TYPES_H_ +#include "tools.h" + typedef float co_aix; typedef struct _shape shape_t; +typedef struct _geo geo_t; /*! \brief A coordination system. * @@ -11,28 +14,82 @@ * Source space is where the contained is drawed, and target space * is where the coordination of parent container of the element * represented by this coord object. + * + * \dot + * digraph G { + * graph [rankdir=LR]; + * root -> child00 -> child10 -> child20 [label="children" color="blue"]; + * child00 -> child01 -> child02 [label="sibling"]; + * child10 -> child11 [label="sibling"]; + * } + * \enddot */ typedef struct _coord { - int seq; + unsigned int seq; co_aix matrix[6]; co_aix aggr_matrix[6]; struct _coord *parent; - struct _coord *children, *sibling; - shape_t *members; + STAILQ(struct _coord) children; + struct _coord *sibling; + STAILQ(shape_t) members; /*!< All shape objects in this coord. */ } coord_t; - -typedef struct _geo geo_t; -struct _shape { - int sh_type; - geo_t *geo; - struct _shape *sibling; -}; - -enum { SHT_UNKNOW, SHT_PATH, SHT_TEXT }; - extern void coord_init(coord_t *co, coord_t *parent); extern void coord_trans_pos(coord_t *co, co_aix *x, co_aix *y); extern void update_aggr_matrix(coord_t *start); +extern coord_t *preorder_coord_tree(coord_t *last); + + +/*! \brief A grahpic shape. + * + * \dot + * digraph G { + * "shape" -> "coord"; + * "shape" -> "geo"; + * "geo" -> "shape"; + * "coord" -> "shape" [label="members"] + * "shape" -> "shape" [label="sibling"]; + * } + * \enddot + */ +struct _shape { + int sh_type; + geo_t *geo; + coord_t *coord; + shape_t *coord_mem_next; + struct _shape *sibling; +}; +enum { SHT_UNKNOW, SHT_PATH, SHT_TEXT }; + +#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) +extern void sh_attach_coord(shape_t *sh, coord_t *coord); +extern void sh_detach_coord(shape_t *sh); + + +/*! \brief Geometry data of a shape or a group of shape. + */ +struct _geo { + shape_t *shape; + co_aix x, y; + co_aix w, h; + geo_t *next; /*!< \brief Link geo_t objects. */ + unsigned int seq; +}; + +extern int is_overlay(geo_t *r1, geo_t *r2); +extern void geo_init(geo_t *g, int n_pos, co_aix pos[][2]); +extern void geo_mark_overlay(geo_t *g, int n_others, geo_t **others, + int *n_overlays, geo_t **overlays); +#define geo_get_shape(g) ((g)->shape) +#define geo_set_shape(g, sh) do {(g)->shape = sh;} while(0) #endif /* __MB_TYPES_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/redraw_man.c Mon Jul 28 17:45:36 2008 +0800 @@ -0,0 +1,301 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "mb_types.h" +#include "shapes.h" +#include "tools.h" +#include "redraw_man.h" + +#define OK 0 +#define ERR -1 + +int redraw_man_init(redraw_man_t *rdman) { + extern void redraw_man_destroy(redraw_man_t *rdman); + + memset(rdman, 0, sizeof(redraw_man_t)); + + rdman->geo_pool = elmpool_new(sizeof(geo_t), 128); + if(rdman->geo_pool == NULL) + return ERR; + + rdman->coord_pool = elmpool_new(sizeof(coord_t), 16); + if(rdman->coord_pool == NULL) { + elmpool_free(rdman->geo_pool); + return ERR; + } + + rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); + if(rdman->root_coord == NULL) + redraw_man_destroy(rdman); + + coord_init(rdman->root_coord, NULL); + + return OK; +} + +void redraw_man_destroy(redraw_man_t *rdman) { + elmpool_free(rdman->coord_pool); + elmpool_free(rdman->geo_pool); +} + + +#define ASSERT(x) +/* + * Change transformation matrix + * - update aggregated transformation matrix + * - of coord_t object been changed. + * - of children coord_t objects. + * - redraw members of coord_t objects. + * - redraw shape objects they are overlaid with members. + * - find out overlaid shape objects. + * - geo_t of a coord_t object + * - can make finding more efficiency. + * - fill overlay geo_t objects of members. + * + * Change a shape object + * - redraw changed object. + * - redraw shape objects they are overlaid with changed object. + * - find out overlaid shape objects. + * + * That coord and geo of shape objects are setted by user code + * give user code a chance to collect coord and geo objects together + * and gain interest of higher cache hit rate. + */ + +/*! \brief Find out all affected shape objects. + * + * Find out all shape objects that are overalid with geo_t of + * a geometry changed object. + * + * Linear scan geo_t objects of all shape objects in all_shapes + * list of a redraw_man_t object. + */ +int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo, + geo_t ***overlays) { + int n_geos; + geo_t **geos; + geo_t *geo_cur; + int n_overlays; + geo_t **_overlays; + int i; + + n_geos = rdman->n_geos; + + geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos); + if(geos == NULL) + return -1; + + _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos); + if(geos == NULL) { + free(geos); + return -1; + } + + geo_cur = STAILQ_HEAD(rdman->all_geos); + for(i = 0; i < n_geos; i++) { + geos[i] = geo_cur; + geo_cur = STAILQ_NEXT(geo_t, next, geo_cur); + } + geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays); + + free(geos); + *overlays = _overlays; + + return n_overlays; +} + +int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { + geo_t *geo; + + geo = elmpool_elm_alloc(rdman->geo_pool); + if(geo == NULL) + return ERR; + sh_attach_geo(shape, geo); + STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); + rdman->n_geos++; + sh_attach_coord(shape, coord); + + return OK; +} + +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); + sh_detach_geo(shape); + rdman->n_geos--; + sh_detach_coord(shape); + return OK; +} + +coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { + coord_t *coord; + + coord = elmpool_elm_alloc(rdman->coord_pool); + if(coord == NULL) + return NULL; + + coord_init(coord, parent); + + return coord; +} + +/*! \brief Free a coord of a redraw_man_t object. + * + * \param coord is a coord_t without children and members. + * \return 0 for successful, -1 for error. + */ +int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { + coord_t *parent; + + parent = coord->parent; + if(parent == NULL) + return ERR; + + if(STAILQ_HEAD(coord->members) != NULL) + return ERR; + + if(STAILQ_HEAD(coord->children) != NULL) + return ERR; + + STAILQ_REMOVE(parent->children, coord_t, sibling, coord); + elmpool_elm_free(rdman->coord_pool, coord); + + return OK; +} + +void rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { +} + +/* + * When redraw an area, the affected elements may also extend to + * outside of the area. Since the order of drawing will change + * the result, it will infect more and more elements to keep + * drawing order althrough they are overlaid directly with + * specified area. + * + * To fix the problem, we don't extend the set of redrawing to + * elements they are not overliad directly. The redrawing is + * performed on a temporary surface, clipped to fit the area, and + * update only specified area on the destinate surface. + */ + +/* + * To accelerate speed of transformation, when a matrix changed, + * transformation should be aggregated and computed in a loop. + * It can get intereset of higher hit rate of cache. + * - shapes prvoide list of positions needed to be transformed. + * - redraw_man transforms positions from shapes. + * - shapes drawing with result of transforms. + * - shapes should be called to give them a chance to update geometries. + */ + +#ifdef UNITTEST + +#include <CUnit/Basic.h> + +struct _sh_dummy { + shape_t shape; + co_aix x, y; + co_aix w, h; +}; +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; + + dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); + if(dummy == NULL) + return NULL; + + dummy->x = x; + dummy->y = y; + dummy->w = w; + dummy->h = h; + + return (shape_t *)dummy; +} + +void sh_dummy_free(shape_t *sh) { + free(sh); +} + +void sh_dummy_transform(shape_t *shape) { + sh_dummy_t *dummy = (sh_dummy_t *)shape; + co_aix poses[2][2]; + co_aix x1, y1, x2, y2; + + if(shape->geo && shape->coord) { + x1 = dummy->x; + y1 = dummy->y; + x2 = x1 + dummy->w; + y2 = y1 + dummy->h; + + coord_trans_pos(shape->coord, &x1, &y1); + coord_trans_pos(shape->coord, &x2, &y2); + poses[0][0] = x1; + poses[0][1] = y1; + poses[1][0] = x2; + poses[1][1] = y2; + + geo_init(shape->geo, 2, poses); + } +} + +void test_rdman_find_overlaid_shapes(void) { + redraw_man_t rdman; + geo_t geo; + coord_t *coords[3]; + shape_t *shapes[5]; + geo_t **overlays; + int n; + int i; + + redraw_man_init(&rdman); + coords[0] = rdman.root_coord; + for(i = 1; i < 3; i++) { + coords[i] = rdman_coord_new(&rdman, rdman.root_coord); + } + for(i = 0; i < 5; i++) { + shapes[i] = sh_dummy_new(10 + i * 30, 10 + i * 20, 25, 15); + CU_ASSERT(shapes[i] != NULL); + } + for(i = 0; i < 3; i++) + rdman_add_shape(&rdman, shapes[i], coords[1]); + for(i = 3; i < 5; i++) + rdman_add_shape(&rdman, shapes[i], coords[2]); + + coords[1]->matrix[0] = 2; + coords[0]->matrix[4] = 2; + + update_aggr_matrix(coords[0]); + for(i = 0; i < 5; i++) + sh_dummy_transform(shapes[i]); + + geo.x = 100; + geo.y = 120; + geo.w = 140; + geo.h = 40; + + n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); + CU_ASSERT(n == 2); + CU_ASSERT(overlays != NULL); + CU_ASSERT(overlays[0] == shapes[2]->geo); + CU_ASSERT(overlays[1] == shapes[3]->geo); + + free(overlays); + for(i = 0; i < 5; i++) + sh_dummy_free(shapes[i]); + + redraw_man_destroy(&rdman); +} + +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); + + return suite; +} + +#endif /* UNITTEST */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/redraw_man.h Mon Jul 28 17:45:36 2008 +0800 @@ -0,0 +1,29 @@ +#ifndef __REDRAW_MAN_H_ +#define __REDRAW_MAN_H_ + +#include "tools.h" +#include "mb_types.h" + +/*! \brief Manage redrawing of shapes (graphic elements). */ +typedef struct _redraw_man { + int n_geos; + STAILQ(geo_t) all_geos; + coord_t *root_coord; + elmpool_t *geo_pool; + elmpool_t *coord_pool; + unsigned int seq; +} redraw_man_t; + +extern int redraw_man_init(redraw_man_t *rdman); +extern void redraw_man_destroy(redraw_man_t *rdman); +extern int rdman_find_overlaid_shapes(redraw_man_t *rdman, + geo_t *geo, + geo_t ***overlays); +extern int rdman_add_shape(redraw_man_t *rdman, + shape_t *shape, coord_t *coord); +extern int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape); +extern coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent); +extern int rdman_coord_free(redraw_man_t *rdman, coord_t *coord); + + +#endif /* __REDRAW_MAN_H_ */
--- a/src/shape_path.c Sat Jul 26 06:34:15 2008 +0800 +++ b/src/shape_path.c Mon Jul 28 17:45:36 2008 +0800 @@ -10,6 +10,10 @@ * In user_data or dev_data, 0x00 bytes are padding after commands. * No commands other than 0x00 can resident after 0x00 itself. * It means command processing code can skip commands after a 0x00. + * + * Shapes should check if shape_t::geo is assigned. Once transformation + * matrics are changed, shape objects should update shape_t::geo if + * it is assigned. */ typedef struct _sh_path { shape_t shape; @@ -352,6 +356,7 @@ cmd_cnt = (cmd_cnt + 3) & ~0x3; path = (sh_path_t *)malloc(sizeof(sh_path_t)); + memset(&path->shape, 0, sizeof(shape_t)); path->shape.sh_type = SHT_PATH; path->cmd_len = cmd_cnt; path->arg_len = arg_cnt; @@ -385,9 +390,11 @@ * TODO: associate coord_t with shape objects and transform them * automatically. */ -void sh_path_transform(shape_t *shape, coord_t *coord) { +void sh_path_transform(shape_t *shape) { sh_path_t *path; co_aix *user_args, *dev_args; + co_aix (*poses)[2]; + int arg_len; int i; ASSERT(shape->type == SHT_PATH); @@ -396,12 +403,18 @@ path = (sh_path_t *)shape; user_args = (co_aix *)(path->user_data + path->cmd_len); dev_args = (co_aix *)(path->dev_data + path->cmd_len); - for(i = 0; i < path->arg_len; i += 2) { + arg_len = path->arg_len; + for(i = 0; i < arg_len; i += 2) { dev_args[0] = *user_args++; dev_args[1] = *user_args++; - coord_trans_pos(coord, dev_args, dev_args + 1); + coord_trans_pos(shape->coord, dev_args, dev_args + 1); dev_args += 2; } + + if(path->shape.geo) { + poses = (co_aix (*)[2])(path->dev_data + path->cmd_len); + geo_init(path->shape.geo, arg_len / 2, poses); + } } void sh_path_draw(shape_t *shape, cairo_t *cr) { @@ -562,6 +575,7 @@ sh_path_t *path; co_aix *args; coord_t coord; + geo_t geo; path = (sh_path_t *)sh_path_new("M 33 25l33 55C 33 87 44 22 55 99L33 77z"); CU_ASSERT(path != NULL); @@ -570,13 +584,17 @@ CU_ASSERT(strcmp(path->user_data, "MLCLZ") == 0); CU_ASSERT(strcmp(path->dev_data, "MLCLZ") == 0); + path->shape.geo = &geo; + geo.shape = (shape_t *)path; + coord.aggr_matrix[0] = 1; coord.aggr_matrix[1] = 0; coord.aggr_matrix[2] = 1; coord.aggr_matrix[3] = 0; coord.aggr_matrix[4] = 2; coord.aggr_matrix[5] = 0; - sh_path_transform((shape_t *)path, &coord); + path->shape.coord = &coord; + sh_path_transform((shape_t *)path); args = (co_aix *)(path->dev_data + path->cmd_len); CU_ASSERT(args[0] == 34); @@ -591,6 +609,7 @@ CU_ASSERT(args[9] == 198); CU_ASSERT(args[10] == 34); CU_ASSERT(args[11] == 154); + sh_path_free((shape_t *)path); }
--- a/src/shapes.h Sat Jul 26 06:34:15 2008 +0800 +++ b/src/shapes.h Mon Jul 28 17:45:36 2008 +0800 @@ -1,11 +1,12 @@ #ifndef __SHAPES_H_ #define __SHAPES_H_ +#include <cairo.h> #include "mb_types.h" extern void sh_path_free(shape_t *path); extern shape_t *sh_path_new(char *data); -extern void sh_path_transform(shape_t *shape, coord_t *coord); +extern void sh_path_transform(shape_t *shape); extern void sh_path_draw(shape_t *shape, cairo_t *cr); #endif /* __SHAPES_H_ */
--- a/src/testcase.c Sat Jul 26 06:34:15 2008 +0800 +++ b/src/testcase.c Mon Jul 28 17:45:36 2008 +0800 @@ -1,8 +1,10 @@ #include <CUnit/Basic.h> +extern CU_pSuite get_tools_suite(void); extern CU_pSuite get_coord_suite(void); extern CU_pSuite get_geo_suite(void); extern CU_pSuite get_shape_path_suite(void); +extern CU_pSuite get_redraw_man_suite(void); int main(int argc, char * const argv[]) { @@ -11,9 +13,21 @@ if(CU_initialize_registry() != CUE_SUCCESS) return CU_get_error(); - get_coord_suite(); - get_geo_suite(); - get_shape_path_suite(); + suite = get_tools_suite(); + if(suite == NULL) + return CU_get_error(); + suite = get_coord_suite(); + if(suite == NULL) + return CU_get_error(); + suite = get_geo_suite(); + if(suite == NULL) + return CU_get_error(); + suite = get_shape_path_suite(); + if(suite == NULL) + return CU_get_error(); + suite = get_redraw_man_suite(); + if(suite == NULL) + return CU_get_error(); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools.c Mon Jul 28 17:45:36 2008 +0800 @@ -0,0 +1,152 @@ +#include <stdlib.h> +#include "tools.h" + + +/*! \brief Small fixed size data elements management. + * + * It is used to management a large number of data elements + * they with the same memory size, a fixed size. It allocate + * a large block for a lot of elements a time for more efficiency + * utilization of memory. + * + * Elements with the size and in a large number usually be accessed + * very close in time. Allocate a large block for elements also + * increase cache hit rate. + * + * Blocks are keep track as a linking list. They are freed when + * the elmpool_t is freed. It costs overhead of size of a element + * for each block. We use memory of first element of blocks to + * be next pointer of linking list. So, it can not be used by user + * code. + */ +struct _elmpool { + int elm_sz; + int inc_num; + void *frees; + void *blks; /* list of allocated blocks. */ +}; + +/*! \brief Create a new data elements pool. + * + * elmpool_t provide a pool of fixed size elements to gain better + * utilization of memory. It try to allocate bigger memory blocks + * for multiple elements. + * + * \param elm_sz size of elements. + * \param inc_num is number of elments to allocate every time. (>= 16) + * \return A elmpool or NULL for error. + */ +elmpool_t *elmpool_new(int elm_sz, int inc_num) { + int _elm_sz; + elmpool_t *pool; + + if(inc_num < 16) + return NULL; + + if(elm_sz >= sizeof(void *)) + _elm_sz = elm_sz; + else + _elm_sz = sizeof(void *); + + pool = (elmpool_t *)malloc(sizeof(elmpool_t)); + if(pool == NULL) + return NULL; + + pool->elm_sz = _elm_sz; + if(inc_num == 0) + inc_num = 256; + pool->inc_num = inc_num; + pool->frees = NULL; + pool->blks = NULL; + + return pool; +} + +void *elmpool_elm_alloc(elmpool_t *pool) { + void *blk, *elm; + int elm_sz, inc_num; + int i; + + if(pool->frees == NULL) { + inc_num = pool->inc_num; + elm_sz = pool->elm_sz; + blk = malloc(elm_sz * inc_num); + if(blk == NULL) + return NULL; + + *(void **)blk = pool->blks; + pool->blks = blk; + + blk = blk + elm_sz; + pool->frees = blk; + for(i = 2; i < inc_num; i++) { + *(void **)blk = blk + elm_sz; + blk = *(void **)blk; + } + *(void **)blk = NULL; + } + + elm = pool->frees; + pool->frees = *(void **)elm; + + return elm; +} + +void elmpool_elm_free(elmpool_t *pool, void *elm) { + *(void **)elm = pool->frees; + pool->frees = elm; +} + +void elmpool_free(elmpool_t *pool) { + void *blk, *next_blk; + + blk = pool->blks; + while(blk) { + next_blk = *(void **)blk; + free(blk); + blk = next_blk; + } +} + +#ifdef UNITTEST + +#include <CUnit/Basic.h> + +void test_elmpool(void) { + elmpool_t *pool; + void *elm; + int i; + + pool = elmpool_new(64, 16); + for(i = 0; i < 15; i++) { + elm = elmpool_elm_alloc(pool); + CU_ASSERT(elm != NULL); + } + CU_ASSERT(pool->frees == NULL); + + for(i = 0; i < 15; i++) { + elm = elmpool_elm_alloc(pool); + CU_ASSERT(elm != NULL); + } + CU_ASSERT(pool->frees == NULL); + + elmpool_elm_free(pool, elm); + CU_ASSERT(pool->frees == elm); + + elm = elmpool_elm_alloc(pool); + CU_ASSERT(elm != NULL); + CU_ASSERT(pool->frees == NULL); + + elmpool_free(pool); +} + +CU_pSuite get_tools_suite(void) { + CU_pSuite suite; + + suite = CU_add_suite("Suite_tools", NULL, NULL); + CU_ADD_TEST(suite, test_elmpool); + + return suite; +} + +#endif /* UNITTEST */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools.h Mon Jul 28 17:45:36 2008 +0800 @@ -0,0 +1,60 @@ +#ifndef __TOOLS_H_ +#define __TOOLS_H_ + + +typedef struct _elmpool elmpool_t; + +extern elmpool_t *elmpool_new(int elm_sz, int inc_num); +extern void *elmpool_elm_alloc(elmpool_t *pool); +extern void elmpool_elm_free(elmpool_t *pool, void *elm); +extern void elmpool_free(elmpool_t *pool); + + +#define STAILQ(type) \ + struct { \ + type *head; \ + type *tail; \ + } +#define STAILQ_INIT(q) \ + do { \ + (q).head = (q).tail = NULL; \ + } while(0) +#define STAILQ_HEAD(q) ((q).head) +#define STAILQ_TAIL(q) ((q).tail) +#define STAILQ_NEXT(type, field, elm) ((elm)->field) +#define STAILQ_INS(q, type, field, elm) \ + do { \ + (elm)->field = (q).head; \ + (q).head = elm; \ + if((q).tail == NULL) \ + (q).tail = elm; \ + } while(0) +#define STAILQ_INS_TAIL(q, type, field, elm) \ + do { \ + (elm)->field = NULL; \ + if((q).tail != NULL) \ + (q).tail->field = elm; \ + (q).tail = elm; \ + if((q).head == NULL) \ + (q).head = elm; \ + } while(0) +#define STAILQ_REMOVE(q, type, field, elm) \ + do { \ + if((elm) == (q).head) { \ + (q).head = (elm)->field; \ + if((q).head == NULL) \ + (q).tail = NULL; \ + } else { \ + type *_stailq_cur = (q).head; \ + while(_stailq_cur != NULL && \ + _stailq_cur->field != (elm)) \ + _stailq_cur = _stailq_cur->field; \ + if(_stailq_cur != NULL) { \ + _stailq_cur->field = elm; \ + if((q).tail == (elm)) \ + (q).tail = _stailq_cur; \ + } \ + } \ + } while(0) + +#endif /* __TOOLS_H_ */