Mercurial > MadButterfly
changeset 327:85b8bb36fe71
Move and update in source documents
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Fri, 06 Mar 2009 13:53:27 +0800 |
parents | 85951268ee0f |
children | f61dbcd8c291 |
files | dox/install.h src/redraw_man.c |
diffstat | 2 files changed, 392 insertions(+), 379 deletions(-) [+] |
line wrap: on
line diff
--- a/dox/install.h Fri Mar 06 00:10:02 2009 +0800 +++ b/dox/install.h Fri Mar 06 13:53:27 2009 +0800 @@ -6,6 +6,7 @@ * - automake * - libtools * - install Cairo + * - install Pango * * Get source * - hg clone http://hg.assembla.com/MadButterfly MadButterfly
--- a/src/redraw_man.c Fri Mar 06 00:10:02 2009 +0800 +++ b/src/redraw_man.c Fri Mar 06 13:53:27 2009 +0800 @@ -10,6 +10,287 @@ #include "mb_observer.h" #include "mb_prop.h" +/*! \page dirty Dirty geo, coord, and area. + * + * \section dirty_of_ego Dirty of geo + * A geo is dirty when any of the shape, size or positions is changed. + * It's geo and positions should be recomputed before drawing. So, + * dirty geos are marked as dirty and put into redraw_man_t::dirty_geos list. + * geos in the list are cleaned to compute information as a reaction for + * dirty. It recomputes size, position and other data of + * repective shapes. + * + * \section dirty_of_coord Dirty of coord + * A coord is dirty when it's transformation matrix being changed. + * Dirty coords are marked as dirty and put into dirty_coords list. + * Once a coord is dirty, every member geos of it are also dirty. + * Because, their shape, size and positions will be changed. But, + * they are not marked as dirty and put into dirty_geos list, since + * all these member geos will be recomputed for computing new current + * area of the coord. The changes of a coord also affect child + * coords. Once parent is dirty, all children are also dirty for + * their aggregate matrix out of date. Dirty coords should be + * clean in preorder of tree traversal. The redraw_man_t::dirty_coords + * list are sorted to keep ordering before cleaning. + * Whenever a coord is marked dirty and put into redraw_man_t::dirty_coords + * list, all it's children should also be marked. + * + * The procedure of clean coords comprises recomputing aggregate + * transform matrix and area where members spreading in. The aggregated + * transform matrix can reduce number of matrix mul to transform + * positions from space of a coord to the closest cached ancestor coord. + * + * The list is inspected before drawing to recompute new shape, size, + * and positions of member geos of coords in the list. The drity + * flag of member geos will be clean. + * + * Clean coords should be performed before clean geos, since clean + * coords will also clean member geos. + * + * \section dirty_of_area Dirty of area + * When an area is dirty, it is added to coord_canvas_info_t::dirty_areas + * of it's closest cached coord. Areas are created when a shape is cleaned + * for dirty. The areas where a cleaned shape occupied before and after + * cleaning should be redrawed. Areas are added to dirty area list to + * mark areas where should be redrawed. So, all shapes covered by + * dirty area list should be redrawed to update these areas. So, areas + * are added to dirty lists after cleaning geos due to changes of + * shapes. + * + * For example, when a shape is moved from location A to location B, + * areas where the shape occupied for A and B are changed for moving. + * Bothe areas are added into dirty list to mark these areas should + * be redrawed. + */ + +/*! \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() + * + * \section img_cache Image Cache + * It costs time to redraw every component in a complete graphic. + * Image cache try to cache result of prviously rendering, and reusing it + * to avoid wasting CPU time on repeatitive and redundant rendering. + * + * \ref COF_FAST_CACHE and \ref COF_PRECISE_CACHE are used to tag a + * coord that it's + * rendering result is cached in fast way or precise way. With fast cache, + * MB renders descendants of a coord in once, and reuse the result until it + * being dirty. With precise cache, it alike fast cache, but it also + * performs rendering when an ancester of the coord transform it to larger + * size, in width or height. + * + * coord_t::aggr_matrix of a cached coord is computed from aggr_matrix of + * parent. But, it does not use one from parent directly. parent one is + * transformed as + * \code + * cache_scale_x = sqrt(p_matrix[0]**2 + p_matrix[3]**2); + * cache_scale_y = sqrt(p_matrix[1]**2 + p_matrix[4]**2); + * cache_p_matrix[0] = cache_scale_x; + * cache_p_matrix[1] = 0; + * cache_p_matrix[2] = range_shift_x; + * cache_p_matrix[3] = 0; + * cache_p_matrix[4] = cache_scale_y; + * cache_p_matrix[5] = range_shift_y; + * \endcode + * where p_matrix is parent one, and cache_p_matrix is one derived from + * parent one. coord_t::aggr_matrix of a cached coord is + * \code + * aggr_matrix = cache_p_matrix * matrix + * \endcode + * where matrix is the transform being installed on the cached coord. + * range_shift_x and range_shift_y are defined above. + * + * cache_p_matrix rescales sub-graphic to an appropriately size + * (cache_scale_x, cache_scale_y) and aligns left-top of the minimum + * rectangle (range_shift_x, range_shift_y) that cover the area occupied + * by sub-graphic with origin of the space. + * + * The sub-graphic should be rendered on space defined by cache_p_matrix of + * cached one. But rendering result are transformed to the space defined + * by parent with following matrix. + * \code + * draw_matrix = reverse(p_matrix * reverse(cache_p_matrix)) + * \endcode + * With Cairo, draw_matrix is applied on source surface (canvas) + * to draw image to parent's surface (canvas). draw_matrix is a function + * map points from parent space to the space of cached one. + * + * Cached coords are marked for changing transformation of ancestors only if + * following condition is true. + * \code + * cache_scale_x < sqrt(p_matrix[0]**2 + p_matrix[3]**2) || + * cache_scale_y < sqrt(p_matrix[1]**2 + p_matrix[4]**2) + * \endcode + * where p_matrix is latest aggr_matrix of parent after changing + * transformation, and where cache_scale_* are ones mention above and computed + * before changing transformation of ancestors. + * + * Cache_scale_* can be recovered by following instructions. + * \code + * cache_scale_x = aggr_matrix[0] / matrix[0]; + * cache_scale_y = aggr_matrix[4] / matrix[4]; + * \endcode + * + * \section cache_area Area of cached coord + * - *_transform of shapes works as normal + * - areas of descendants of cached coord are in space defined + * by aggr_matrix of cached coord. + * - descendants are marked with \ref COF_ANCESTOR_CACHE + * + * Since *_transform of shapes compute area with aggr_matrix that is + * derived from aggr_matrix of a cached ancestor, area of + * \ref COF_ANCESTOR_CACHE ones should be transformed to device space in + * find_shape_at_pos() with following statement. + * \code + * area_matrix = p_matrix * reverse(cache_p_matrix) + * \endcode + * where cache_p_matrix and p_matrix are corresponding matrix of + * cached ancestor. We can also perform transforming in reversed + * direction to transform point to space defined by aggr_matrix of cached + * coord. + * + * Since it is costly to transform area of \ref COF_ANCESTOR_CACHE ones to + * device space if more than one ancestor are cached, no ancestor of + * cached coord can be set to cached. + * + * \section cached_bounding Bounding box of cached coord and descendants + * Bounding box of a cached coord and it's descendants is the range that + * cached coord and descendants are rendered on canvas. It is also called + * cached-bounding. + * + * range_shift_x and range_shift_y are computed by initailizing cache_p_matrix + * with range_shift_x == range_shift_y == 0 at first. cache_p_matrix is + * used to compute aggr_matrix and cached-bounding in turn. Then, + * range_shift_x and range_shift_y are initialized to negative of + * x-axis and y-axis, repectively, of left-top of cached-bounding. Then, + * aggr_matrix of cached coord and descendants are updated by + * following statements. + * \code + * aggr_matrix[2] += range_shift_x; + * aggr_matrix[5] += range_shift_y; + * \endcode + * The statements shift the spaces to make cached-bounding + * aligned to origin of coordinate system. + * The purpose of range_shift_* is to reduce size of canvas used to cache + * rendering result. The canvas are shrink to size the same as bounding + * box. + * + * \section cache_redraw How cache and redraw work together? + * When a coord and descedants are cached, the coord is flaged with + * COF_FAST_CACHE or COF_PRECISE_CACHE. When a coord is marked dirty, all + * descendants are also marked dirty by rdman except descendants of cached + * ones. But, cached ones are also marked dirty as normal ones. The + * reason to mark cached ones is giving them a chance to update their + * area. + * + * For precise cached descendants, above rule has an exception. They should + * also be marked dirty if cached coord should be rendered in a larger + * resize factor to get better output. + * + * coord_t::aggr_matrix and cached-bounding of cached coord must be computed + * in the way described in \ref cached_bounding. Propagating range_shift_* + * to descendants must skip cached ones and their descendants. + * Range_shift_* are computed after updating descendants. So, procedure + * of clean descendants of a cached one must performed in two phases. + * One for computing areas of descendants and one for propagating + * range_shift_*. + * + * A cached coord or/and descendants are dirty only for cached coord or + * descendants being marked dirty by application. Once a cached coord or + * descendant is marked dirty, all descendants of marked one are also + * marked. redraw_man_t::dirty_areas collects areas, in device space, + * that should be updated. All shapes overlaid with any area in + * redraw_man_t::dirty_areas should be redraw. Since descendants of cached + * coord compute their areas in spaces other than device space. + * Separated lists should be maintained for each cached coord and it's + * descendants. + * + * \section cache_imp Implementation of Cache + * Both cached coords and coords that opacity != 1 need a canvas to + * draw descendants on. Both cases are traded in the same way. + * Every of them own a canvas_info to describe canvas and related + * information. aggr_matrix of descendants must be adjusted to make + * left-top of range just at origin of canvas. It can save space by setting + * just large enough to hold rendering result of descendants. The process + * of adjusting is zeroing. + * + * Following is rules. + * - zeroing on a cached coord is performed by adjust coord_t::aggr_matrix + * of the cached coord and descendnats. + * - Clean coords works just like before without change. + * - in preorder + * - never perform zeroing on root_coord. + * - zeroing on cached coords marked with \ref COF_MUST_ZEROING. + * - when clean a descendant that moves out-side of it's canvas, + * respective cached coord is marked with \ref COF_MUST_ZEROING. + * - zeroing is performed immediately after clean coords. + * - zeroing will not propagate acrossing boundary of cached coord. + * - It will be stopped at descendants which are cached coords. + * - coord_t::cur_area and coord_t::aggr_matrix of cached coords + * must be ajdusted. + * - the area of a cached coord is defined in parent space. + * - areas of descendants are defined in space defined by aggr_matrix of + * cached coord. + * - parent know the area in where cached coord and descendnats will + * be draw. + * - cached coords keep their private dirty area list. + * - private dirty areas of a cached coord are transformed and added to + * parent cached coord. + * - aggregates areas before adding to parent. + * - canvas of a cached coord is updated if + * - descendants are dirty, or + * - it-self is dirty. + * - change of a canvas must copy to canvas of parent space. + * - a cached is updated if canvas of descendant cached coord is updated. + * - updating canvas is performed by redraw dirty areas. + * - since dirty areas of cached ones would be aggregated and added to + * parent, parent cached coord would copy it from cache of descedants. + * - descendant cached coords must be updated before ancestor cached coords. + * - add dirty areas to parent immediately after updating canvas. + * - Making dirty coords is not propagated through cached ones. + * - cached ones are also made dirty, but stop after that. + * + * Steps: + * - SWAP coord_t::cur_area of dirty coords. + * - SWAP geo_t::cur_area of dirty geos. + * - clean coords + * - coord_t::aggr_matrix of cached coord is not the same as non-cached. + * - see \ref img_cache + * - clean geos + * - Add canvas owner of dirty geos to redraw_man_t::zeroing_coords + * - Cached ancestors of redraw_man_t::dirty_geos + * - Cached ancestors of redraw_man_t::dirty_coords + * - Cached ancestors of zeroed ones should also be zeroed. + * - zeroing + * - Add more dirty areas if canvas should be fully redrawed. + * - From leaf to root. + * - add aggregated dirty areas from descendant cached coords to ancestors. + * - Must include old area of cached coords if it is just clean and + * parent cached one is not just clean. + * - Just clean is a coord cleaned in last time of cleaning coords. + * - draw dirty areas + * - areas are rounded to N at first. + * - from leaf to root. + */ + #ifndef ASSERT #define ASSERT(x) #endif @@ -129,6 +410,33 @@ return r == 0? OK: ERR; +static int is_area_in_areas(area_t *area, + int n_areas, + area_t **areas) { + int i; + + for(i = 0; i < n_areas; i++) { + if(areas_are_overlay(area, areas[i])) + return 1; + } + return 0; +} + +static int is_geo_in_areas(geo_t *geo, + int n_areas, + area_t **areas) { + return is_area_in_areas(geo->cur_area, n_areas, areas); +} + +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;; +} + +/* Maintain Lists */ + static int add_dirty_coord(redraw_man_t *rdman, coord_t *coord) { coord->flags |= COF_DIRTY; ADD_DATA(coords, dirty_coords, coord); @@ -193,12 +501,7 @@ free(rdman->free_objs.objs); } -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 cairo_t *canvas_new(int w, int h) { #ifndef UNITTEST @@ -840,6 +1143,7 @@ return OK; } + /* Clean dirties */ static int is_coord_subtree_hidden(coord_t *coord) { @@ -943,6 +1247,87 @@ return OK; } +/*! \brief Clean dirty coords. + * + * \note coords their opacity != 1 are also traded as cached ones. + */ +static int clean_coord(redraw_man_t *rdman, coord_t *coord) { + int r; + + setup_canvas_info(rdman, coord); + + if(coord->flags & COF_OWN_CANVAS) + compute_aggr_of_cached_coord(coord); + else + compute_aggr_of_coord(coord); + + /* Areas of cached coords are computed in two phase. + * Phase 1 works like other normal ones. Phase 2, is collect + * all areas of descendants to compute a minimum covering area. + * Phase 2 is performed by zeroing_coord(). + */ + r = coord_clean_members_n_compute_area(coord); + if(r != OK) + return ERR; + + coord->flags &= ~COF_DIRTY; + + return OK; +} + +/*! \brief Clean coord_t objects. + */ +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->dirty_coords.num; + if(n_dirty_coords > 0) { + 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++) { + coord = dirty_coords[i]; + if(!(coord->flags & COF_DIRTY)) + continue; + r = clean_coord(rdman, coord); + if(r != OK) + return ERR; + /* These two steps can be avoided for drawing all. */ + add_dirty_area(rdman, coord, &coord->areas[0]); + add_dirty_area(rdman, coord, &coord->areas[1]); + } + } + return OK; +} + +static int clean_rdman_geos(redraw_man_t *rdman) { + int i; + int n_dirty_geos; + geo_t **dirty_geos; + geo_t *visit_geo; + coord_t *coord; + + n_dirty_geos = rdman->dirty_geos.num; + if(n_dirty_geos > 0) { + 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)) + continue; + + clean_shape(visit_geo->shape); + coord = geo_get_coord(visit_geo); + add_dirty_area(rdman, coord, visit_geo->cur_area); + add_dirty_area(rdman, coord, visit_geo->last_area); + } + } + + return OK; +} + /*! \brief Shift space of coord to align left-top of minimum covering. * * Align left-top of minimum rectangle covering occupied area of @@ -1069,87 +1454,6 @@ add_dirty_area(rdman, coord, area); } -/*! \brief Clean dirty coords. - * - * \note coords their opacity != 1 are also traded as cached ones. - */ -static int clean_coord(redraw_man_t *rdman, coord_t *coord) { - int r; - - setup_canvas_info(rdman, coord); - - if(coord->flags & COF_OWN_CANVAS) - compute_aggr_of_cached_coord(coord); - else - compute_aggr_of_coord(coord); - - /* Areas of cached coords are computed in two phase. - * Phase 1 works like other normal ones. Phase 2, is collect - * all areas of descendants to compute a minimum covering area. - * Phase 2 is performed by zeroing_coord(). - */ - r = coord_clean_members_n_compute_area(coord); - if(r != OK) - return ERR; - - coord->flags &= ~COF_DIRTY; - - return OK; -} - -/*! \brief Clean coord_t objects. - */ -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->dirty_coords.num; - if(n_dirty_coords > 0) { - 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++) { - coord = dirty_coords[i]; - if(!(coord->flags & COF_DIRTY)) - continue; - r = clean_coord(rdman, coord); - if(r != OK) - return ERR; - /* These two steps can be avoided for drawing all. */ - add_dirty_area(rdman, coord, &coord->areas[0]); - add_dirty_area(rdman, coord, &coord->areas[1]); - } - } - return OK; -} - -static int clean_rdman_geos(redraw_man_t *rdman) { - int i; - int n_dirty_geos; - geo_t **dirty_geos; - geo_t *visit_geo; - coord_t *coord; - - n_dirty_geos = rdman->dirty_geos.num; - if(n_dirty_geos > 0) { - 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)) - continue; - - clean_shape(visit_geo->shape); - coord = geo_get_coord(visit_geo); - add_dirty_area(rdman, coord, visit_geo->cur_area); - add_dirty_area(rdman, coord, visit_geo->last_area); - } - } - - return OK; -} - /*! \brief Add canvas owner of dirty geos to coord_t::zeroing_coords. * * All possible coords that need a zeroing have at least one dirty geo. @@ -1592,24 +1896,6 @@ } #endif /* UNITTEST */ -static int is_area_in_areas(area_t *area, - int n_areas, - area_t **areas) { - int i; - - for(i = 0; i < n_areas; i++) { - if(areas_are_overlay(area, areas[i])) - return 1; - } - return 0; -} - -static int is_geo_in_areas(geo_t *geo, - int n_areas, - area_t **areas) { - return is_area_in_areas(geo->cur_area, n_areas, areas); -} - static void update_cached_canvas_2_parent(redraw_man_t *rdman, coord_t *coord) { cairo_t *pcanvas, *canvas; @@ -1816,234 +2102,6 @@ * 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() - * - * \section img_cache Image Cache - * It costs time to redraw every component in a complete graphic. - * Image cache try to cache result of prviously rendering, and reusing it - * to avoid wasting CPU time on repeatitive and redundant rendering. - * - * \ref COF_FAST_CACHE and \ref COF_PRECISE_CACHE are used to tag a - * coord that it's - * rendering result is cached in fast way or precise way. With fast cache, - * MB renders descendants of a coord in once, and reuse the result until it - * being dirty. With precise cache, it alike fast cache, but it also - * performs rendering when an ancester of the coord transform it to larger - * size, in width or height. - * - * coord_t::aggr_matrix of a cached coord is computed from aggr_matrix of - * parent. But, it does not use one from parent directly. parent one is - * transformed as - * \code - * cache_scale_x = sqrt(p_matrix[0]**2 + p_matrix[3]**2); - * cache_scale_y = sqrt(p_matrix[1]**2 + p_matrix[4]**2); - * cache_p_matrix[0] = cache_scale_x; - * cache_p_matrix[1] = 0; - * cache_p_matrix[2] = range_shift_x; - * cache_p_matrix[3] = 0; - * cache_p_matrix[4] = cache_scale_y; - * cache_p_matrix[5] = range_shift_y; - * \endcode - * where p_matrix is parent one, and cache_p_matrix is one derived from - * parent one. coord_t::aggr_matrix of a cached coord is - * \code - * aggr_matrix = cache_p_matrix * matrix - * \endcode - * where matrix is the transform being installed on the cached coord. - * range_shift_x and range_shift_y are defined above. - * - * cache_p_matrix rescales sub-graphic to an appropriately size - * (cache_scale_x, cache_scale_y) and aligns left-top of the minimum - * rectangle (range_shift_x, range_shift_y) that cover the area occupied - * by sub-graphic with origin of the space. - * - * The sub-graphic should be rendered on space defined by cache_p_matrix of - * cached one. But rendering result are transformed to the space defined - * by parent with following matrix. - * \code - * draw_matrix = reverse(p_matrix * reverse(cache_p_matrix)) - * \endcode - * With Cairo, draw_matrix is applied on source surface (canvas) - * to draw image to parent's surface (canvas). draw_matrix is a function - * map points from parent space to the space of cached one. - * - * Cached coords are marked for changing transformation of ancestors only if - * following condition is true. - * \code - * cache_scale_x < sqrt(p_matrix[0]**2 + p_matrix[3]**2) || - * cache_scale_y < sqrt(p_matrix[1]**2 + p_matrix[4]**2) - * \endcode - * where p_matrix is latest aggr_matrix of parent after changing - * transformation, and where cache_scale_* are ones mention above and computed - * before changing transformation of ancestors. - * - * Cache_scale_* can be recovered by following instructions. - * \code - * cache_scale_x = aggr_matrix[0] / matrix[0]; - * cache_scale_y = aggr_matrix[4] / matrix[4]; - * \endcode - * - * \section cache_area Area of cached coord - * - *_transform of shapes works as normal - * - areas of descendants of cached coord are in space defined - * by aggr_matrix of cached coord. - * - descendants are marked with \ref COF_ANCESTOR_CACHE - * - * Since *_transform of shapes compute area with aggr_matrix that is - * derived from aggr_matrix of a cached ancestor, area of - * \ref COF_ANCESTOR_CACHE ones should be transformed to device space in - * find_shape_at_pos() with following statement. - * \code - * area_matrix = p_matrix * reverse(cache_p_matrix) - * \endcode - * where cache_p_matrix and p_matrix are corresponding matrix of - * cached ancestor. We can also perform transforming in reversed - * direction to transform point to space defined by aggr_matrix of cached - * coord. - * - * Since it is costly to transform area of \ref COF_ANCESTOR_CACHE ones to - * device space if more than one ancestor are cached, no ancestor of - * cached coord can be set to cached. - * - * \section cached_bounding Bounding box of cached coord and descendants - * Bounding box of a cached coord and it's descendants is the range that - * cached coord and descendants are rendered on canvas. It is also called - * cached-bounding. - * - * range_shift_x and range_shift_y are computed by initailizing cache_p_matrix - * with range_shift_x == range_shift_y == 0 at first. cache_p_matrix is - * used to compute aggr_matrix and cached-bounding in turn. Then, - * range_shift_x and range_shift_y are initialized to negative of - * x-axis and y-axis, repectively, of left-top of cached-bounding. Then, - * aggr_matrix of cached coord and descendants are updated by - * following statements. - * \code - * aggr_matrix[2] += range_shift_x; - * aggr_matrix[5] += range_shift_y; - * \endcode - * The statements shift the spaces to make cached-bounding - * aligned to origin of coordinate system. - * The purpose of range_shift_* is to reduce size of canvas used to cache - * rendering result. The canvas are shrink to size the same as bounding - * box. - * - * \section cache_redraw How cache and redraw work together? - * When a coord and descedants are cached, the coord is flaged with - * COF_FAST_CACHE or COF_PRECISE_CACHE. When a coord is marked dirty, all - * descendants are also marked dirty by rdman except descendants of cached - * ones. But, cached ones are also marked dirty as normal ones. The - * reason to mark cached ones is giving them a chance to update their - * area. - * - * For precise cached descendants, above rule has an exception. They should - * also be marked dirty if cached coord should be rendered in a larger - * resize factor to get better output. - * - * coord_t::aggr_matrix and cached-bounding of cached coord must be computed - * in the way described in \ref cached_bounding. Propagating range_shift_* - * to descendants must skip cached ones and their descendants. - * Range_shift_* are computed after updating descendants. So, procedure - * of clean descendants of a cached one must performed in two phases. - * One for computing areas of descendants and one for propagating - * range_shift_*. - * - * A cached coord or/and descendants are dirty only for cached coord or - * descendants being marked dirty by application. Once a cached coord or - * descendant is marked dirty, all descendants of marked one are also - * marked. redraw_man_t::dirty_areas collects areas, in device space, - * that should be updated. All shapes overlaid with any area in - * redraw_man_t::dirty_areas should be redraw. Since descendants of cached - * coord compute their areas in spaces other than device space. - * Separated lists should be maintained for each cached coord and it's - * descendants. - * - * \section cache_imp Implementation of Cache - * Both cached coords and coords that opacity != 1 need a canvas to - * draw descendants on. Both cases are traded in the same way. - * Every of them own a canvas_info to describe canvas and related - * information. aggr_matrix of descendants must be adjusted to make - * left-top of range just at origin of canvas. It can save space by setting - * just large enough to hold rendering result of descendants. The process - * of adjusting is zeroing. - * - * Following is rules. - * - zeroing on a cached coord is performed by adjust coord_t::aggr_matrix - * of the cached coord and descendnats. - * - Clean coords works just like before without change. - * - in preorder - * - never perform zeroing on root_coord. - * - zeroing on cached coords marked with \ref COF_MUST_ZEROING. - * - when clean a descendant that moves out-side of it's canvas, - * respective cached coord is marked with \ref COF_MUST_ZEROING. - * - zeroing is performed immediately after clean coords. - * - zeroing will not propagate acrossing boundary of cached coord. - * - It will be stopped at descendants which are cached coords. - * - coord_t::cur_area and coord_t::aggr_matrix of cached coords - * must be ajdusted. - * - the area of a cached coord is defined in parent space. - * - areas of descendants are defined in space defined by aggr_matrix of - * cached coord. - * - parent know the area in where cached coord and descendnats will - * be draw. - * - cached coords keep their private dirty area list. - * - private dirty areas of a cached coord are transformed and added to - * parent cached coord. - * - aggregates areas before adding to parent. - * - canvas of a cached coord is updated if - * - descendants are dirty, or - * - it-self is dirty. - * - change of a canvas must copy to canvas of parent space. - * - a cached is updated if canvas of descendant cached coord is updated. - * - updating canvas is performed by redraw dirty areas. - * - since dirty areas of cached ones would be aggregated and added to - * parent, parent cached coord would copy it from cache of descedants. - * - descendant cached coords must be updated before ancestor cached coords. - * - add dirty areas to parent immediately after updating canvas. - * - Making dirty coords is not propagated through cached ones. - * - cached ones are also made dirty, but stop after that. - * - * Steps: - * - SWAP coord_t::cur_area of dirty coords. - * - SWAP geo_t::cur_area of dirty geos. - * - clean coords - * - coord_t::aggr_matrix of cached coord is not the same as non-cached. - * - see \ref img_cache - * - clean geos - * - Add canvas owner of dirty geos to redraw_man_t::zeroing_coords - * - Cached ancestors of redraw_man_t::dirty_geos - * - Cached ancestors of redraw_man_t::dirty_coords - * - Cached ancestors of zeroed ones should also be zeroed. - * - zeroing - * - Add more dirty areas if canvas should be fully redrawed. - * - From leaf to root. - * - add aggregated dirty areas from descendant cached coords to ancestors. - * - Must include old area of cached coords if it is just clean and - * parent cached one is not just clean. - * - Just clean is a coord cleaned in last time of cleaning coords. - * - draw dirty areas - * - areas are rounded to N at first. - * - from leaf to root. - */ - int rdman_redraw_all(redraw_man_t *rdman) { area_t area; #ifndef UNITTEST @@ -2119,41 +2177,6 @@ return r; } -/*! \page dirty Dirty geo, coord, and area. - * - * \section dirty_of_ego Dirty of geo - * A geo is dirty when any of the shape, size or positions is changed. - * It's geo and positions should be recomputed before drawing. So, - * dirty geos are marked as dirty and put into dirty_geos list. - * The list is inspected before drawing to make sure the right shape, - * size, and positions. - * - * \section dirty_of_coord Dirty of coord - * A coord is dirty when it's transformation matrix being changed. - * Dirty coords are marked as dirty and put into dirty_coords list. - * Once a coord is dirty, every member geos of it are also dirty. - * Because, their shape, size and positions will be changed. But, - * they are not marked as dirty and put into dirty_geos list, since - * all these member geos will be recomputed for computing new current - * area of the coord. The changes of a coord also affect child - * coords. Once parent is dirty, all children are also dirty for - * their aggregate matrix out of date. Dirty coords should be - * clean in preorder of tree traversal. The dirty_coords list - * are sorted to keep the order before cleaning. - * Whenever a coord is marked dirty and put into dirty_coords list, - * all it's children should also be marked and put. - * - * The procedure of clean coords comprises recomputing aggregate - * tranform matrix and area where members spreading in. - * - * The list is inspected before drawing to recompute new shape, size, - * and positions of member geos of coords in the list. The drity - * flag of member geos will be clean. - * - * Clean coords should be performed before clean geos, since clean - * coords will also clean member geos. - */ - /*! \page man_obj Manage Objects. * * Shapes and paints should also be managed by redraw manager. Redraw @@ -2176,17 +2199,6 @@ * - rdman_shape_free() */ -/* - * 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. - */ - - /* \defgroup rdman_observer Observer memory management * * Implment factory and strategy functions for observers and subjects.