Mercurial > MadButterfly
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; |