Mercurial > MadButterfly
changeset 138:9f4fc9ecfd1f
Make shapes and coords drawed in post-order of tree.
1. Add opacity for each coord.
2. Trival and draw tree of shapes and coords in post-order.
3. Coords have a before_pmem member variable to note it's order been draw.
It is relative to it's siblings and member shapes of parent coord.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Mon, 22 Sep 2008 11:45:00 +0800 |
parents | 5dcfaafd1a9c |
children | 1695a4b02b14 |
files | src/coord.c src/mb_types.h src/redraw_man.c |
diffstat | 3 files changed, 234 insertions(+), 43 deletions(-) [+] |
line wrap: on
line diff
--- a/src/coord.c Fri Sep 19 09:53:17 2008 +0800 +++ b/src/coord.c Mon Sep 22 11:45:00 2008 +0800 @@ -123,7 +123,7 @@ coord_t *preorder_coord_subtree(coord_t *root, coord_t *last) { coord_t *next; - ASSERT(last == NULL); + ASSERT(last != NULL); if(STAILQ_HEAD(last->children)) next = STAILQ_HEAD(last->children); @@ -140,6 +140,32 @@ return next; } +coord_t *postorder_coord_subtree(coord_t *root, coord_t *last) { + coord_t *next; + + if(root == last) + return NULL; + + if(last == NULL) { + /* Go most left leaf. */ + next = root; + while(STAILQ_HEAD(next->children)) + next = STAILQ_HEAD(next->children); + return next; + } + + next = last; + if(STAILQ_NEXT(coord_t, sibling, next) == NULL) /* most right */ + return next->parent; + + /* Go most left leaf of right sibling sub-tree. */ + next = STAILQ_NEXT(coord_t, sibling, next); + while(STAILQ_HEAD(next->children)) + next = STAILQ_HEAD(next->children); + + 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;
--- a/src/mb_types.h Fri Sep 19 09:53:17 2008 +0800 +++ b/src/mb_types.h Mon Sep 22 11:45:00 2008 +0800 @@ -88,6 +88,14 @@ typedef struct _coord { unsigned int order; unsigned int flags; + co_aix opacity; + /*! Own one or inherit from an ancestor. + * Setup it when clean coords. + * \sa + * - \ref COF_OWN_CANVAS + * - \ref redraw + */ + cairo_t *canvas; area_t *cur_area, *last_area; area_t areas[2]; @@ -97,12 +105,17 @@ struct _coord *parent; STAILQ(struct _coord) children; struct _coord *sibling; + unsigned int before_pmem; /*!< \brief The coord is before nth member + * of parent. */ STAILQ(shape_t) members; /*!< All shape_t objects in this coord. */ subject_t *mouse_event; } coord_t; #define COF_DIRTY 0x1 #define COF_HIDDEN 0x2 +#define COF_OWN_CANVAS 0x4 /*!< A coord owns a canvas or inherit it + * from an ancestor. + */ extern void coord_init(coord_t *co, coord_t *parent); extern void coord_trans_pos(coord_t *co, co_aix *x, co_aix *y); @@ -110,6 +123,7 @@ extern void compute_aggr_of_coord(coord_t *coord); extern void update_aggr_matrix(coord_t *start); extern coord_t *preorder_coord_subtree(coord_t *root, coord_t *last); +extern coord_t *postorder_coord_subtree(coord_t *root, coord_t *last); #define coord_hide(co) do { co->flags |= COF_HIDDEN; } while(0) #define coord_show(co) do { co->flags &= ~COF_HIDDEN; } while(0) #define coord_get_mouse_event(coord) ((coord)->mouse_event)
--- a/src/redraw_man.c Fri Sep 19 09:53:17 2008 +0800 +++ b/src/redraw_man.c Mon Sep 22 11:45:00 2008 +0800 @@ -112,6 +112,31 @@ poses[1][1] = area->y + area->h;; } +static cairo_t *new_canvas(redraw_man_t *rdman) { +#ifndef UNITTEST + cairo_t *cr; + cairo_surface_t *surface, *cr_surface; + int w, h; + + cr_surface = cairo_get_target(rdman->cr); + w = cairo_image_surface_get_width(cr_surface); + h = cairo_image_surface_get_height(cr_surface); + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + w, h); + cr = cairo_create(surface); + + return cr; +#else + return NULL; +#endif +} + +static void free_canvas(cairo_t *canvas) { +#ifndef UNITTEST + cairo_destroy(canvas); +#endif +} + int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend) { extern void redraw_man_destroy(redraw_man_t *rdman); @@ -165,6 +190,9 @@ rdman->root_coord->mouse_event = subject_new(&rdman->ob_factory, rdman->root_coord, OBJT_COORD); + rdman->root_coord->flags |= COF_OWN_CANVAS; + rdman->root_coord->canvas = cr; + rdman->root_coord->opacity = 1; rdman->cr = cr; rdman->backend = backend; @@ -173,6 +201,15 @@ } void redraw_man_destroy(redraw_man_t *rdman) { + coord_t *coord, *saved_coord; + + coord = postorder_coord_subtree(rdman->root_coord, NULL); + while(coord) { + saved_coord = coord; + coord = postorder_coord_subtree(rdman->root_coord, coord); + rdman_coord_free(rdman, saved_coord); + } + elmpool_free(rdman->coord_pool); elmpool_free(rdman->geo_pool); elmpool_free(rdman->shnode_pool); @@ -321,6 +358,10 @@ coord->mouse_event = subject_new(&rdman->ob_factory, coord, OBJT_COORD); + /*! \note default opacity == 1 */ + coord->opacity = 1; + if(parent) + coord->canvas = parent->canvas; rdman->n_coords++; coord->order = ++rdman->next_coord_order; @@ -356,6 +397,10 @@ if(STAILQ_HEAD(coord->children) != NULL) return ERR; + /* Free canvas (\ref redraw) */ + if(coord->flags & COF_OWN_CANVAS) + free_canvas(coord->canvas); + STAILQ_REMOVE(parent->children, coord_t, sibling, coord); subject_free(&rdman->ob_factory, coord->mouse_event); elmpool_elm_free(rdman->coord_pool, coord); @@ -481,12 +526,38 @@ shape->geo->flags &= ~GEF_HIDDEN; } -static int clean_coord(coord_t *coord) { +/*! \brief Setup canvas for the coord. + * + * Own a canvas or inherit it from parent. + * \sa + * - \ref redraw + */ +static void setup_canvas(redraw_man_t *rdman, coord_t *coord) { + if(coord->parent == NULL) + return; + + if(coord->opacity != 1) { + if(!(coord->flags & COF_OWN_CANVAS)) { + coord->canvas = new_canvas(rdman); + coord->flags |= COF_OWN_CANVAS; + } + } else { + if(coord->flags & COF_OWN_CANVAS) { + free_canvas(coord->canvas); + coord->flags &= ~COF_OWN_CANVAS; + } + coord->canvas = coord->parent->canvas; + } +} + +static int clean_coord(redraw_man_t *rdman, coord_t *coord) { shape_t *shape; geo_t *geo; co_aix (*poses)[2]; int cnt, pos_cnt; + setup_canvas(rdman, coord); + compute_aggr_of_coord(coord); /* Clean member shapes. */ @@ -525,8 +596,6 @@ } /*! \brief Clean coord_t objects. - * - * \todo Make objects can be addin or remove out of coord tree any time. */ static int clean_rdman_coords(redraw_man_t *rdman) { coord_t *coord; @@ -543,7 +612,7 @@ coord = dirty_coords[i]; if(!(coord->flags & COF_DIRTY)) continue; - r = clean_coord(coord); + r = clean_coord(rdman, coord); if(r != OK) return ERR; /* These two steps can be avoided for drawing all. */ @@ -629,30 +698,30 @@ } #endif -static void draw_shape(redraw_man_t *rdman, shape_t *shape) { +static void draw_shape(redraw_man_t *rdman, cairo_t *cr, shape_t *shape) { paint_t *fill, *stroke; if(shape->fill || shape->stroke) { switch(shape->sh_type) { case SHT_PATH: - sh_path_draw(shape, rdman->cr); + sh_path_draw(shape, cr); break; case SHT_TEXT: - sh_text_draw(shape, rdman->cr); + sh_text_draw(shape, cr); break; case SHT_RECT: - sh_rect_draw(shape, rdman->cr); + sh_rect_draw(shape, cr); break; #ifdef UNITTEST default: - sh_dummy_fill(shape, rdman->cr); + sh_dummy_fill(shape, cr); break; #endif /* UNITTEST */ } fill = shape->fill; if(shape->fill) { - fill->prepare(fill, rdman->cr); + fill->prepare(fill, cr); if(shape->stroke) fill_path_preserve(rdman); else @@ -661,8 +730,8 @@ stroke = shape->stroke; if(stroke) { - stroke->prepare(stroke, rdman->cr); - set_shape_stroke_param(shape, rdman->cr); + stroke->prepare(stroke, cr); + set_shape_stroke_param(shape, cr); stroke_path(rdman); } } @@ -675,6 +744,12 @@ cairo_paint(cr); } +static void clean_canvas_black(cairo_t *cr) { + /*! \todo clean to background color. */ + cairo_set_source_rgba(cr, 0, 0, 0, 0); + cairo_paint(cr); +} + static void make_clip(cairo_t *cr, int n_dirty_areas, area_t **dirty_areas) { int i; @@ -702,6 +777,9 @@ static void clean_canvas(cairo_t *cr) { } +static void clean_canvas_black(cairo_t *cr) { +} + static void reset_clip(redraw_man_t *rdman) { } @@ -710,26 +788,76 @@ } #endif /* UNITTEST */ +static int is_shape_in_areas(shape_t *shape, + int n_areas, + area_t **areas) { + int i; + geo_t *geo; + + geo = shape->geo; + for(i = 0; i < n_areas; i++) { + if(is_overlay(geo->cur_area, areas[i])) + return 1; + } + return 0; +} + +static void update_canvas_2_parent(redraw_man_t *rdman, coord_t *coord) { + cairo_t *pcanvas, *canvas; + cairo_surface_t *surface; + + if(coord == rdman->root_coord) + return; + + canvas = coord->canvas; + pcanvas = coord->parent->canvas; + surface = cairo_get_target(canvas); + cairo_set_source_surface(pcanvas, surface, 0, 0); + cairo_paint_with_alpha(pcanvas, coord->opacity); +} + +static int draw_coord_shapes_in_areas(redraw_man_t *rdman, + coord_t *coord, + int n_areas, + area_t **areas) { + int dirty = 0; + int r; + shape_t *member; + coord_t *child; + cairo_t *canvas; + int mem_idx; + + canvas = coord->canvas; + member = STAILQ_HEAD(coord->members); + mem_idx = 0; + child = STAILQ_HEAD(coord->children); + while(child != NULL || member != NULL) { + if(child && child->before_pmem == mem_idx) { + r = draw_coord_shapes_in_areas(rdman, child, n_areas, areas); + dirty |= r; + child = STAILQ_NEXT(coord_t, sibling, child); + } else { + ASSERT(member != NULL); + if(is_shape_in_areas(member, n_areas, areas)) { + draw_shape(rdman, canvas, member); + dirty = 1; + } + member = STAILQ_NEXT(shape_t, coord_mem_next, member); + } + } + + if(dirty && coord->flags & COF_OWN_CANVAS) { + update_canvas_2_parent(rdman, coord); + clean_canvas_black(coord->canvas); + } + + return dirty; +} + static void draw_shapes_in_areas(redraw_man_t *rdman, int n_areas, area_t **areas) { - geo_t *visit_geo; - int i; - - for(visit_geo = STAILQ_HEAD(rdman->all_geos); - visit_geo != NULL; - visit_geo = STAILQ_NEXT(geo_t, next, visit_geo)) { - if(visit_geo->flags & GEF_DIRTY) - clean_shape(visit_geo->shape); - if(visit_geo->flags & GEF_HIDDEN) - continue; - for(i = 0; i < n_areas; i++) { - if(is_overlay(visit_geo->cur_area, areas[i])) { - draw_shape(rdman, visit_geo->shape); - break; - } - } - } + draw_coord_shapes_in_areas(rdman, rdman->root_coord, n_areas, areas); } @@ -810,26 +938,49 @@ * NOTE: After redrawing, the content must be copied to the backend surface. */ +/*! \page redraw How to Redraw Shapes? + * + * Coords are corresponding objects for group tags of SVG files. + * In conceptional, every SVG group has a canvas, graphics of child shapes + * are drawed into the canvas, applied filters of group, and blended into + * canvas of parent of the group. + * + * But, we don't need to create actually a surface/canvas for every coord. + * We only create surface for coords their opacity value are not 1 or they + * apply filters on background. Child shapes of coords without canvas + * are drawed on canvas of nearest ancestor which have canvas. It said + * a coord owns a canvas or inherits from an ancestor. (\ref COF_OWN_CANVAS, + * clean_coord()) Except, root_coord always owns a canvas. + * + * \note Default opacity of a coord is 1. + * + * \sa + * - rdman_redraw_all() + * - rdman_redraw_changed() + * = draw_shapes_in_areas() + */ + int rdman_redraw_all(redraw_man_t *rdman) { geo_t *geo; + cairo_surface_t *surface; + area_t area; int r; - r = clean_rdman_dirties(rdman); + area.x = area.y = 0; +#ifndef UNITTEST + surface = cairo_get_target(rdman->cr); + area.w = cairo_image_surface_get_width(surface); + area.h = cairo_image_surface_get_height(surface); +#else + area.w = 1024; + area.h = 1024; +#endif + add_dirty_area(rdman, &area); + + r = rdman_redraw_changed(rdman); if(r != OK) return ERR; - clean_canvas(rdman->cr); - - for(geo = STAILQ_HEAD(rdman->all_geos); - geo != NULL; - geo = STAILQ_NEXT(geo_t, next, geo)) { - if(geo->flags & GEF_HIDDEN) - continue; - draw_shape(rdman, geo->shape); - } - copy_cr_2_backend(rdman, 0, NULL); - rdman->n_dirty_areas = 0; - return OK; }