comparison src/redraw_man.c @ 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 6ce68c1f7405
children b90abd31a281
comparison
equal deleted inserted replaced
157:5cd12609a5c7 158:c1cdd3fcd28f
9 #include "observer.h" 9 #include "observer.h"
10 10
11 11
12 /* NOTE: bounding box should also consider width of stroke. 12 /* NOTE: bounding box should also consider width of stroke.
13 */ 13 */
14
15 #define sh_attach_geo(sh, g) \
16 do { \
17 (sh)->geo = g; \
18 (g)->shape = (shape_t *)(sh); \
19 } while(0)
20 #define sh_detach_geo(sh) \
21 do { \
22 (sh)->geo->shape = NULL; \
23 (sh)->geo = NULL; \
24 } while(0)
25 #define sh_get_geo(sh) ((sh)->geo)
26 #define sh_attach_coord(sh, coord) do { (sh)->coord = coord; } while(0)
27 #define sh_detach_coord(sh) do { (sh)->coord = NULL; } while(0)
28 #define rdman_is_dirty(rdman) \
29 ((rdman)->dirty_coords.num != 0 || \
30 (rdman)->dirty_geos.num != 0 || \
31 (rdman)->dirty_areas.num != 0)
14 32
15 #define OK 0 33 #define OK 0
16 #define ERR -1 34 #define ERR -1
17 35
18 #define ARRAY_EXT_SZ 64 36 #define ARRAY_EXT_SZ 64
76 } 94 }
77 elms[j] = elm_i; 95 elms[j] = elm_i;
78 } 96 }
79 } 97 }
80 98
81 static int extend_memblk(void **buf, int o_size, int n_size) { 99 DARRAY_DEFINE(coords, coord_t *);
82 void *new_buf; 100 DARRAY_DEFINE(geos, geo_t *);
83 101 DARRAY_DEFINE(areas, area_t *);
84 new_buf = realloc(*buf, n_size); 102
85 if(new_buf == NULL) 103 /*! Use \brief DARRAY to implement dirty & free lists.
86 return ERR; 104 */
87 105 #define ADD_DATA(sttype, field, v) \
88 *buf = new_buf; 106 int r; \
89 107 r = sttype ## _add(&rdman->field, v); \
90 return OK; 108 return r == 0? OK: ERR;
91 } 109
92 110
93 static int add_dirty_coord(redraw_man_t *rdman, coord_t *coord) { 111 static int add_dirty_coord(redraw_man_t *rdman, coord_t *coord) {
94 int max_dirty_coords;
95 int r;
96
97 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) {
98 /* Max of dirty_coords is not big enough. */
99 max_dirty_coords = rdman->max_dirty_coords + 16;
100
101 r = extend_memblk((void **)&rdman->dirty_coords,
102 sizeof(coord_t *) * rdman->n_dirty_coords,
103 sizeof(coord_t *) * max_dirty_coords);
104 if(r != OK)
105 return ERR;
106 rdman->max_dirty_coords = max_dirty_coords;
107 }
108
109 rdman->dirty_coords[rdman->n_dirty_coords++] = coord;
110 coord->flags |= COF_DIRTY; 112 coord->flags |= COF_DIRTY;
111 return OK; 113 ADD_DATA(coords, dirty_coords, coord);
112 } 114 }
113 115
114 static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) { 116 static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) {
115 int max_dirty_geos; 117 geo->flags |= GEF_DIRTY;
116 int r; 118 ADD_DATA(geos, dirty_geos, geo);
117
118 if(rdman->n_dirty_geos >= rdman->max_dirty_geos) {
119 max_dirty_geos = rdman->max_dirty_geos + ARRAY_EXT_SZ;
120 r = extend_memblk((void **)&rdman->dirty_geos,
121 sizeof(geo_t *) * rdman->n_dirty_geos,
122 sizeof(geo_t *) * max_dirty_geos);
123 if(r != OK)
124 return ERR;
125 rdman->max_dirty_geos = max_dirty_geos;
126 }
127
128 rdman->dirty_geos[rdman->n_dirty_geos++] = geo;
129 return OK;
130 } 119 }
131 120
132 static int add_dirty_area(redraw_man_t *rdman, area_t *area) { 121 static int add_dirty_area(redraw_man_t *rdman, area_t *area) {
133 int max_dirty_areas; 122 ADD_DATA(areas, dirty_areas, area);
134 int r; 123 }
135 124
136 if(rdman->n_dirty_areas >= rdman->max_dirty_areas) { 125 static int add_free_coord(redraw_man_t *rdman, coord_t *coord) {
137 /* every geo object and coord object can contribute 2 areas. 126 ADD_DATA(coords, free_coords, coord);
138 * rdman_draw_area() may also contribute 1 area. 127 }
139 */ 128
140 max_dirty_areas = rdman->max_dirty_areas + ARRAY_EXT_SZ; 129 static int add_free_geo(redraw_man_t *rdman, geo_t *geo) {
141 r = extend_memblk((void **)&rdman->dirty_areas, 130 ADD_DATA(geos, free_geos, geo);
142 sizeof(area_t *) * rdman->n_dirty_areas,
143 sizeof(area_t *) * max_dirty_areas);
144 if(r != OK)
145 return ERR;
146 rdman->max_dirty_areas = max_dirty_areas;
147 }
148
149 rdman->dirty_areas[rdman->n_dirty_areas++] = area;
150 return OK;
151 } 131 }
152 132
153 static void area_to_positions(area_t *area, co_aix (*poses)[2]) { 133 static void area_to_positions(area_t *area, co_aix (*poses)[2]) {
154 poses[0][0] = area->x; 134 poses[0][0] = area->x;
155 poses[0][1] = area->y; 135 poses[0][1] = area->y;
292 return OK; 272 return OK;
293 } 273 }
294 274
295 void redraw_man_destroy(redraw_man_t *rdman) { 275 void redraw_man_destroy(redraw_man_t *rdman) {
296 coord_t *coord, *saved_coord; 276 coord_t *coord, *saved_coord;
277 geo_t *member;
297 278
298 coord = postorder_coord_subtree(rdman->root_coord, NULL); 279 coord = postorder_coord_subtree(rdman->root_coord, NULL);
299 while(coord) { 280 while(coord) {
300 saved_coord = coord; 281 saved_coord = coord;
301 coord = postorder_coord_subtree(rdman->root_coord, coord); 282 coord = postorder_coord_subtree(rdman->root_coord, coord);
283 FORMEMBERS(saved_coord, member) {
284 rdman_remove_shape(rdman, member->shape);
285 }
302 rdman_coord_free(rdman, saved_coord); 286 rdman_coord_free(rdman, saved_coord);
303 } 287 }
288 FORMEMBERS(saved_coord, member) {
289 rdman_remove_shape(rdman, member->shape);
290 }
291 /* Resources of root_coord is free by elmpool_free() or
292 * caller; for canvas
293 */
304 294
305 elmpool_free(rdman->coord_pool); 295 elmpool_free(rdman->coord_pool);
306 elmpool_free(rdman->geo_pool); 296 elmpool_free(rdman->geo_pool);
307 elmpool_free(rdman->shnode_pool); 297 elmpool_free(rdman->shnode_pool);
308 elmpool_free(rdman->observer_pool); 298 elmpool_free(rdman->observer_pool);
309 elmpool_free(rdman->subject_pool); 299 elmpool_free(rdman->subject_pool);
310 elmpool_free(rdman->paint_color_pool); 300 elmpool_free(rdman->paint_color_pool);
311 if(rdman->dirty_coords) 301
312 free(rdman->dirty_coords); 302 DARRAY_DESTROY(&rdman->dirty_coords);
313 if(rdman->dirty_geos) 303 DARRAY_DESTROY(&rdman->dirty_geos);
314 free(rdman->dirty_geos); 304 DARRAY_DESTROY(&rdman->dirty_areas);
315 if(rdman->gen_geos) 305 DARRAY_DESTROY(&rdman->gen_geos);
316 free(rdman->gen_geos); 306 DARRAY_DESTROY(&rdman->free_coords);
307 DARRAY_DESTROY(&rdman->free_geos);
317 } 308 }
318 309
319 310
320 #define ASSERT(x) 311 #define ASSERT(x)
321 /* 312 /*
352 geo->mouse_event = subject_new(&rdman->ob_factory, geo, OBJT_GEO); 343 geo->mouse_event = subject_new(&rdman->ob_factory, geo, OBJT_GEO);
353 344
354 geo_attach_coord(geo, coord); 345 geo_attach_coord(geo, coord);
355 346
356 /* New one should be dirty to recompute it when drawing. */ 347 /* New one should be dirty to recompute it when drawing. */
357 geo->flags |= GEF_DIRTY;
358 r = add_dirty_geo(rdman, geo); 348 r = add_dirty_geo(rdman, geo);
359 if(r != OK) 349 if(r != OK)
360 return ERR; 350 return ERR;
361 351
362 sh_attach_coord(shape, coord); 352 sh_attach_coord(shape, coord);
366 } 356 }
367 357
368 /*! \brief Remove a shape object from redraw manager. 358 /*! \brief Remove a shape object from redraw manager.
369 * 359 *
370 * \note Shapes should be removed after redrawing or when rdman is in clean. 360 * \note Shapes should be removed after redrawing or when rdman is in clean.
361 * \note Removing shapes or coords when a rdman is dirty, removing
362 * is postponsed.
371 * \todo redraw shape objects that overlaid with removed one. 363 * \todo redraw shape objects that overlaid with removed one.
372 * \todo To allow shapes be removed at anytime.
373 */ 364 */
374 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { 365 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) {
375 geo_t *geo; 366 geo_t *geo;
376 coord_t *coord; 367 coord_t *coord;
368 int r;
377 369
378 geo = shape->geo; 370 geo = shape->geo;
379 coord = shape->coord; 371 coord = shape->coord;
372
373 if(rdman_is_dirty(rdman)) {
374 geo->flags |= GEF_FREE | GEF_HIDDEN;
375 if(!(geo->flags & GEF_DIRTY)) {
376 r = add_dirty_geo(rdman, geo);
377 if(r != OK)
378 return ERR;
379 }
380 r = add_free_geo(rdman, geo);
381 if(r != OK)
382 return ERR;
383 return OK;
384 }
385
380 geo_detach_coord(geo, coord); 386 geo_detach_coord(geo, coord);
381 subject_free(&rdman->ob_factory, geo->mouse_event); 387 subject_free(&rdman->ob_factory, geo->mouse_event);
382 sh_detach_geo(shape); 388 sh_detach_geo(shape);
383 elmpool_elm_free(rdman->geo_pool, geo); 389 elmpool_elm_free(rdman->geo_pool, geo);
384 sh_detach_coord(shape); 390 sh_detach_coord(shape);
426 432
427 /*! \brief Free a coord of a redraw_man_t object. 433 /*! \brief Free a coord of a redraw_man_t object.
428 * 434 *
429 * \param coord is a coord_t without children and members. 435 * \param coord is a coord_t without children and members.
430 * \return 0 for successful, -1 for error. 436 * \return 0 for successful, -1 for error.
437 *
438 * \note Removing coords when the rdman is dirty, the removing is postponsed.
431 */ 439 */
432 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { 440 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) {
433 coord_t *parent; 441 coord_t *parent;
442 coord_t *child;
443 geo_t *member;
444 int r;
434 445
435 parent = coord->parent; 446 parent = coord->parent;
436 if(parent == NULL) 447 if(parent == NULL)
437 return ERR; 448 return ERR;
438 449
450 if(rdman_is_dirty(rdman)) {
451 FORCHILDREN(coord, child) {
452 if(!(child->flags & COF_FREE))
453 return ERR;
454 }
455 FORMEMBERS(coord, member) {
456 if(!(member->flags & GEF_FREE))
457 return ERR;
458 }
459 coord->flags |= COF_FREE | COF_HIDDEN;
460 if(!(coord->flags & COF_DIRTY)) {
461 r = add_dirty_coord(rdman, coord);
462 if(r != OK)
463 return ERR;
464 }
465 r = add_free_coord(rdman, coord);
466 if(r != OK)
467 return ERR;
468 return OK;
469 }
470
439 if(FIRST_MEMBER(coord) != NULL) 471 if(FIRST_MEMBER(coord) != NULL)
440 return ERR; 472 return ERR;
441 473
442 if(FIRST_CHILD(coord) != NULL) 474 if(FIRST_CHILD(coord) != NULL)
475 return ERR;
476
477 if(coord->flags & COF_FREE)
443 return ERR; 478 return ERR;
444 479
445 /* Free canvas (\ref redraw) */ 480 /* Free canvas (\ref redraw) */
446 if(coord->flags & COF_OWN_CANVAS) 481 if(coord->flags & COF_OWN_CANVAS)
447 free_canvas(coord->canvas); 482 free_canvas(coord->canvas);
515 return OK; 550 return OK;
516 551
517 r = add_dirty_geo(rdman, geo); 552 r = add_dirty_geo(rdman, geo);
518 if(r == ERR) 553 if(r == ERR)
519 return ERR; 554 return ERR;
520 geo->flags |= GEF_DIRTY;
521 555
522 return OK; 556 return OK;
523 } 557 }
524 558
525 /*! \brief Mark a shape is changed. 559 /*! \brief Mark a shape is changed.
653 coord_t *coord; 687 coord_t *coord;
654 coord_t **dirty_coords; 688 coord_t **dirty_coords;
655 int n_dirty_coords; 689 int n_dirty_coords;
656 int i, r; 690 int i, r;
657 691
658 n_dirty_coords = rdman->n_dirty_coords; 692 n_dirty_coords = rdman->dirty_coords.num;
659 if(n_dirty_coords > 0) { 693 if(n_dirty_coords > 0) {
660 dirty_coords = rdman->dirty_coords; 694 dirty_coords = rdman->dirty_coords.ds;
661 _insert_sort((void **)dirty_coords, n_dirty_coords, 695 _insert_sort((void **)dirty_coords, n_dirty_coords,
662 OFFSET(coord_t, order)); 696 OFFSET(coord_t, order));
663 for(i = 0; i < n_dirty_coords; i++) { 697 for(i = 0; i < n_dirty_coords; i++) {
664 coord = dirty_coords[i]; 698 coord = dirty_coords[i];
665 if(!(coord->flags & COF_DIRTY)) 699 if(!(coord->flags & COF_DIRTY))
669 return ERR; 703 return ERR;
670 /* These two steps can be avoided for drawing all. */ 704 /* These two steps can be avoided for drawing all. */
671 add_dirty_area(rdman, &coord->areas[0]); 705 add_dirty_area(rdman, &coord->areas[0]);
672 add_dirty_area(rdman, &coord->areas[1]); 706 add_dirty_area(rdman, &coord->areas[1]);
673 } 707 }
674 rdman->n_dirty_coords = 0; 708 rdman->dirty_coords.num = 0;
675 } 709 }
676 return OK; 710 return OK;
677 } 711 }
678 712
679 static int clean_rdman_geos(redraw_man_t *rdman) { 713 static int clean_rdman_geos(redraw_man_t *rdman) {
680 int i; 714 int i;
681 int n_dirty_geos; 715 int n_dirty_geos;
682 geo_t **dirty_geos; 716 geo_t **dirty_geos;
683 geo_t *visit_geo; 717 geo_t *visit_geo;
684 718
685 n_dirty_geos = rdman->n_dirty_geos; 719 n_dirty_geos = rdman->dirty_geos.num;
686 if(n_dirty_geos > 0) { 720 if(n_dirty_geos > 0) {
687 dirty_geos = rdman->dirty_geos; 721 dirty_geos = rdman->dirty_geos.ds;
688 for(i = 0; i < n_dirty_geos; i++) { 722 for(i = 0; i < n_dirty_geos; i++) {
689 visit_geo = dirty_geos[i]; 723 visit_geo = dirty_geos[i];
690 if(!(visit_geo->flags & GEF_DIRTY)) 724 if(!(visit_geo->flags & GEF_DIRTY))
691 continue; 725 continue;
692 726
693 SWAP(visit_geo->cur_area, visit_geo->last_area, area_t *); 727 SWAP(visit_geo->cur_area, visit_geo->last_area, area_t *);
694 clean_shape(visit_geo->shape); 728 clean_shape(visit_geo->shape);
695 add_dirty_area(rdman, visit_geo->cur_area); 729 add_dirty_area(rdman, visit_geo->cur_area);
696 add_dirty_area(rdman, visit_geo->last_area); 730 add_dirty_area(rdman, visit_geo->last_area);
697 } 731 }
698 rdman->n_dirty_geos = 0; 732 rdman->dirty_geos.num = 0;
699 } 733 }
700 734
701 return OK; 735 return OK;
702 } 736 }
703 737
950 int n_dirty_areas; 984 int n_dirty_areas;
951 area_t **dirty_areas; 985 area_t **dirty_areas;
952 event_t event; 986 event_t event;
953 ob_factory_t *factory; 987 ob_factory_t *factory;
954 subject_t *redraw; 988 subject_t *redraw;
989 geo_t *geo;
990 coord_t *coord;
991 int i;
955 992
956 r = clean_rdman_dirties(rdman); 993 r = clean_rdman_dirties(rdman);
957 if(r != OK) 994 if(r != OK)
958 return ERR; 995 return ERR;
959 996
960 n_dirty_areas = rdman->n_dirty_areas; 997 n_dirty_areas = rdman->dirty_areas.num;
961 dirty_areas = rdman->dirty_areas; 998 dirty_areas = rdman->dirty_areas.ds;
962 if(n_dirty_areas > 0) { 999 if(n_dirty_areas > 0) {
963 /*! \brief Draw shapes in preorder of coord tree and support opacity 1000 /*! \brief Draw shapes in preorder of coord tree and support opacity
964 * rules. 1001 * rules.
965 */ 1002 */
966 clean_canvas(rdman->cr); 1003 clean_canvas(rdman->cr);
967 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); 1004 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas);
968 copy_cr_2_backend(rdman, rdman->n_dirty_areas, rdman->dirty_areas); 1005 copy_cr_2_backend(rdman, rdman->dirty_areas.num,
969 rdman->n_dirty_areas = 0; 1006 rdman->dirty_areas.ds);
1007 rdman->dirty_areas.num = 0;
970 reset_clip(rdman); 1008 reset_clip(rdman);
971 } 1009 }
972 rdman->n_dirty_areas = 0; 1010 rdman->dirty_areas.num = 0;
1011
1012 /* Free postponsed removing */
1013 for(i = 0; i < rdman->free_geos.num; i++) {
1014 geo = rdman->free_geos.ds[i];
1015 rdman_remove_shape(rdman, geo->shape);
1016 }
1017 DARRAY_CLEAN(&rdman->free_geos);
1018
1019 for(i = 0; i < rdman->free_coords.num; i++) {
1020 coord = rdman->free_coords.ds[i];
1021 rdman_remove_shape(rdman, coord);
1022 }
1023 DARRAY_CLEAN(&rdman->free_coords);
973 1024
974 factory = rdman_get_ob_factory(rdman); 1025 factory = rdman_get_ob_factory(rdman);
975 redraw = rdman_get_redraw_subject(rdman); 1026 redraw = rdman_get_redraw_subject(rdman);
976 event.type = EVT_RDMAN_REDRAW; 1027 event.type = EVT_RDMAN_REDRAW;
977 event.tgt = event.cur_tgt = redraw; 1028 event.tgt = event.cur_tgt = redraw;
1001 * \note Default opacity of a coord is 1. 1052 * \note Default opacity of a coord is 1.
1002 * 1053 *
1003 * \sa 1054 * \sa
1004 * - rdman_redraw_all() 1055 * - rdman_redraw_all()
1005 * - rdman_redraw_changed() 1056 * - rdman_redraw_changed()
1006 * = draw_shapes_in_areas() 1057 * - draw_shapes_in_areas()
1007 */ 1058 */
1008 1059
1009 int rdman_redraw_all(redraw_man_t *rdman) { 1060 int rdman_redraw_all(redraw_man_t *rdman) {
1010 cairo_surface_t *surface; 1061 cairo_surface_t *surface;
1011 area_t area; 1062 area_t area;