Mercurial > MadButterfly
comparison src/redraw_man.c @ 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 | 81c03fdd94d0 |
children | 1695a4b02b14 |
comparison
equal
deleted
inserted
replaced
137:5dcfaafd1a9c | 138:9f4fc9ecfd1f |
---|---|
110 poses[0][1] = area->y; | 110 poses[0][1] = area->y; |
111 poses[1][0] = area->x + area->w; | 111 poses[1][0] = area->x + area->w; |
112 poses[1][1] = area->y + area->h;; | 112 poses[1][1] = area->y + area->h;; |
113 } | 113 } |
114 | 114 |
115 static cairo_t *new_canvas(redraw_man_t *rdman) { | |
116 #ifndef UNITTEST | |
117 cairo_t *cr; | |
118 cairo_surface_t *surface, *cr_surface; | |
119 int w, h; | |
120 | |
121 cr_surface = cairo_get_target(rdman->cr); | |
122 w = cairo_image_surface_get_width(cr_surface); | |
123 h = cairo_image_surface_get_height(cr_surface); | |
124 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, | |
125 w, h); | |
126 cr = cairo_create(surface); | |
127 | |
128 return cr; | |
129 #else | |
130 return NULL; | |
131 #endif | |
132 } | |
133 | |
134 static void free_canvas(cairo_t *canvas) { | |
135 #ifndef UNITTEST | |
136 cairo_destroy(canvas); | |
137 #endif | |
138 } | |
139 | |
115 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend) { | 140 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend) { |
116 extern void redraw_man_destroy(redraw_man_t *rdman); | 141 extern void redraw_man_destroy(redraw_man_t *rdman); |
117 | 142 |
118 memset(rdman, 0, sizeof(redraw_man_t)); | 143 memset(rdman, 0, sizeof(redraw_man_t)); |
119 | 144 |
163 rdman->n_coords = 1; | 188 rdman->n_coords = 1; |
164 coord_init(rdman->root_coord, NULL); | 189 coord_init(rdman->root_coord, NULL); |
165 rdman->root_coord->mouse_event = subject_new(&rdman->ob_factory, | 190 rdman->root_coord->mouse_event = subject_new(&rdman->ob_factory, |
166 rdman->root_coord, | 191 rdman->root_coord, |
167 OBJT_COORD); | 192 OBJT_COORD); |
193 rdman->root_coord->flags |= COF_OWN_CANVAS; | |
194 rdman->root_coord->canvas = cr; | |
195 rdman->root_coord->opacity = 1; | |
168 | 196 |
169 rdman->cr = cr; | 197 rdman->cr = cr; |
170 rdman->backend = backend; | 198 rdman->backend = backend; |
171 | 199 |
172 return OK; | 200 return OK; |
173 } | 201 } |
174 | 202 |
175 void redraw_man_destroy(redraw_man_t *rdman) { | 203 void redraw_man_destroy(redraw_man_t *rdman) { |
204 coord_t *coord, *saved_coord; | |
205 | |
206 coord = postorder_coord_subtree(rdman->root_coord, NULL); | |
207 while(coord) { | |
208 saved_coord = coord; | |
209 coord = postorder_coord_subtree(rdman->root_coord, coord); | |
210 rdman_coord_free(rdman, saved_coord); | |
211 } | |
212 | |
176 elmpool_free(rdman->coord_pool); | 213 elmpool_free(rdman->coord_pool); |
177 elmpool_free(rdman->geo_pool); | 214 elmpool_free(rdman->geo_pool); |
178 elmpool_free(rdman->shnode_pool); | 215 elmpool_free(rdman->shnode_pool); |
179 elmpool_free(rdman->observer_pool); | 216 elmpool_free(rdman->observer_pool); |
180 elmpool_free(rdman->subject_pool); | 217 elmpool_free(rdman->subject_pool); |
319 | 356 |
320 coord_init(coord, parent); | 357 coord_init(coord, parent); |
321 coord->mouse_event = subject_new(&rdman->ob_factory, | 358 coord->mouse_event = subject_new(&rdman->ob_factory, |
322 coord, | 359 coord, |
323 OBJT_COORD); | 360 OBJT_COORD); |
361 /*! \note default opacity == 1 */ | |
362 coord->opacity = 1; | |
363 if(parent) | |
364 coord->canvas = parent->canvas; | |
324 rdman->n_coords++; | 365 rdman->n_coords++; |
325 | 366 |
326 coord->order = ++rdman->next_coord_order; | 367 coord->order = ++rdman->next_coord_order; |
327 if(coord->order == 0) { | 368 if(coord->order == 0) { |
328 rdman->next_coord_order = 0; | 369 rdman->next_coord_order = 0; |
353 if(STAILQ_HEAD(coord->members) != NULL) | 394 if(STAILQ_HEAD(coord->members) != NULL) |
354 return ERR; | 395 return ERR; |
355 | 396 |
356 if(STAILQ_HEAD(coord->children) != NULL) | 397 if(STAILQ_HEAD(coord->children) != NULL) |
357 return ERR; | 398 return ERR; |
399 | |
400 /* Free canvas (\ref redraw) */ | |
401 if(coord->flags & COF_OWN_CANVAS) | |
402 free_canvas(coord->canvas); | |
358 | 403 |
359 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); | 404 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); |
360 subject_free(&rdman->ob_factory, coord->mouse_event); | 405 subject_free(&rdman->ob_factory, coord->mouse_event); |
361 elmpool_elm_free(rdman->coord_pool, coord); | 406 elmpool_elm_free(rdman->coord_pool, coord); |
362 rdman->n_coords--; | 407 rdman->n_coords--; |
479 shape->geo->flags |= GEF_HIDDEN; | 524 shape->geo->flags |= GEF_HIDDEN; |
480 else | 525 else |
481 shape->geo->flags &= ~GEF_HIDDEN; | 526 shape->geo->flags &= ~GEF_HIDDEN; |
482 } | 527 } |
483 | 528 |
484 static int clean_coord(coord_t *coord) { | 529 /*! \brief Setup canvas for the coord. |
530 * | |
531 * Own a canvas or inherit it from parent. | |
532 * \sa | |
533 * - \ref redraw | |
534 */ | |
535 static void setup_canvas(redraw_man_t *rdman, coord_t *coord) { | |
536 if(coord->parent == NULL) | |
537 return; | |
538 | |
539 if(coord->opacity != 1) { | |
540 if(!(coord->flags & COF_OWN_CANVAS)) { | |
541 coord->canvas = new_canvas(rdman); | |
542 coord->flags |= COF_OWN_CANVAS; | |
543 } | |
544 } else { | |
545 if(coord->flags & COF_OWN_CANVAS) { | |
546 free_canvas(coord->canvas); | |
547 coord->flags &= ~COF_OWN_CANVAS; | |
548 } | |
549 coord->canvas = coord->parent->canvas; | |
550 } | |
551 } | |
552 | |
553 static int clean_coord(redraw_man_t *rdman, coord_t *coord) { | |
485 shape_t *shape; | 554 shape_t *shape; |
486 geo_t *geo; | 555 geo_t *geo; |
487 co_aix (*poses)[2]; | 556 co_aix (*poses)[2]; |
488 int cnt, pos_cnt; | 557 int cnt, pos_cnt; |
558 | |
559 setup_canvas(rdman, coord); | |
489 | 560 |
490 compute_aggr_of_coord(coord); | 561 compute_aggr_of_coord(coord); |
491 | 562 |
492 /* Clean member shapes. */ | 563 /* Clean member shapes. */ |
493 cnt = 0; | 564 cnt = 0; |
523 | 594 |
524 return OK; | 595 return OK; |
525 } | 596 } |
526 | 597 |
527 /*! \brief Clean coord_t objects. | 598 /*! \brief Clean coord_t objects. |
528 * | |
529 * \todo Make objects can be addin or remove out of coord tree any time. | |
530 */ | 599 */ |
531 static int clean_rdman_coords(redraw_man_t *rdman) { | 600 static int clean_rdman_coords(redraw_man_t *rdman) { |
532 coord_t *coord; | 601 coord_t *coord; |
533 coord_t **dirty_coords; | 602 coord_t **dirty_coords; |
534 int n_dirty_coords; | 603 int n_dirty_coords; |
541 OFFSET(coord_t, order)); | 610 OFFSET(coord_t, order)); |
542 for(i = 0; i < n_dirty_coords; i++) { | 611 for(i = 0; i < n_dirty_coords; i++) { |
543 coord = dirty_coords[i]; | 612 coord = dirty_coords[i]; |
544 if(!(coord->flags & COF_DIRTY)) | 613 if(!(coord->flags & COF_DIRTY)) |
545 continue; | 614 continue; |
546 r = clean_coord(coord); | 615 r = clean_coord(rdman, coord); |
547 if(r != OK) | 616 if(r != OK) |
548 return ERR; | 617 return ERR; |
549 /* These two steps can be avoided for drawing all. */ | 618 /* These two steps can be avoided for drawing all. */ |
550 add_dirty_area(rdman, &coord->areas[0]); | 619 add_dirty_area(rdman, &coord->areas[0]); |
551 add_dirty_area(rdman, &coord->areas[1]); | 620 add_dirty_area(rdman, &coord->areas[1]); |
627 | 696 |
628 static void stroke_path(redraw_man_t *rdman) { | 697 static void stroke_path(redraw_man_t *rdman) { |
629 } | 698 } |
630 #endif | 699 #endif |
631 | 700 |
632 static void draw_shape(redraw_man_t *rdman, shape_t *shape) { | 701 static void draw_shape(redraw_man_t *rdman, cairo_t *cr, shape_t *shape) { |
633 paint_t *fill, *stroke; | 702 paint_t *fill, *stroke; |
634 | 703 |
635 if(shape->fill || shape->stroke) { | 704 if(shape->fill || shape->stroke) { |
636 switch(shape->sh_type) { | 705 switch(shape->sh_type) { |
637 case SHT_PATH: | 706 case SHT_PATH: |
638 sh_path_draw(shape, rdman->cr); | 707 sh_path_draw(shape, cr); |
639 break; | 708 break; |
640 case SHT_TEXT: | 709 case SHT_TEXT: |
641 sh_text_draw(shape, rdman->cr); | 710 sh_text_draw(shape, cr); |
642 break; | 711 break; |
643 case SHT_RECT: | 712 case SHT_RECT: |
644 sh_rect_draw(shape, rdman->cr); | 713 sh_rect_draw(shape, cr); |
645 break; | 714 break; |
646 #ifdef UNITTEST | 715 #ifdef UNITTEST |
647 default: | 716 default: |
648 sh_dummy_fill(shape, rdman->cr); | 717 sh_dummy_fill(shape, cr); |
649 break; | 718 break; |
650 #endif /* UNITTEST */ | 719 #endif /* UNITTEST */ |
651 } | 720 } |
652 | 721 |
653 fill = shape->fill; | 722 fill = shape->fill; |
654 if(shape->fill) { | 723 if(shape->fill) { |
655 fill->prepare(fill, rdman->cr); | 724 fill->prepare(fill, cr); |
656 if(shape->stroke) | 725 if(shape->stroke) |
657 fill_path_preserve(rdman); | 726 fill_path_preserve(rdman); |
658 else | 727 else |
659 fill_path(rdman); | 728 fill_path(rdman); |
660 } | 729 } |
661 | 730 |
662 stroke = shape->stroke; | 731 stroke = shape->stroke; |
663 if(stroke) { | 732 if(stroke) { |
664 stroke->prepare(stroke, rdman->cr); | 733 stroke->prepare(stroke, cr); |
665 set_shape_stroke_param(shape, rdman->cr); | 734 set_shape_stroke_param(shape, cr); |
666 stroke_path(rdman); | 735 stroke_path(rdman); |
667 } | 736 } |
668 } | 737 } |
669 } | 738 } |
670 | 739 |
671 #ifndef UNITTEST | 740 #ifndef UNITTEST |
672 static void clean_canvas(cairo_t *cr) { | 741 static void clean_canvas(cairo_t *cr) { |
673 /*! \todo clean to background color. */ | 742 /*! \todo clean to background color. */ |
674 cairo_set_source_rgb(cr, 1, 1, 1); | 743 cairo_set_source_rgb(cr, 1, 1, 1); |
744 cairo_paint(cr); | |
745 } | |
746 | |
747 static void clean_canvas_black(cairo_t *cr) { | |
748 /*! \todo clean to background color. */ | |
749 cairo_set_source_rgba(cr, 0, 0, 0, 0); | |
675 cairo_paint(cr); | 750 cairo_paint(cr); |
676 } | 751 } |
677 | 752 |
678 static void make_clip(cairo_t *cr, int n_dirty_areas, | 753 static void make_clip(cairo_t *cr, int n_dirty_areas, |
679 area_t **dirty_areas) { | 754 area_t **dirty_areas) { |
700 } | 775 } |
701 #else /* UNITTEST */ | 776 #else /* UNITTEST */ |
702 static void clean_canvas(cairo_t *cr) { | 777 static void clean_canvas(cairo_t *cr) { |
703 } | 778 } |
704 | 779 |
780 static void clean_canvas_black(cairo_t *cr) { | |
781 } | |
782 | |
705 static void reset_clip(redraw_man_t *rdman) { | 783 static void reset_clip(redraw_man_t *rdman) { |
706 } | 784 } |
707 | 785 |
708 static void copy_cr_2_backend(redraw_man_t *rdman, int n_dirty_areas, | 786 static void copy_cr_2_backend(redraw_man_t *rdman, int n_dirty_areas, |
709 area_t **dirty_areas) { | 787 area_t **dirty_areas) { |
710 } | 788 } |
711 #endif /* UNITTEST */ | 789 #endif /* UNITTEST */ |
790 | |
791 static int is_shape_in_areas(shape_t *shape, | |
792 int n_areas, | |
793 area_t **areas) { | |
794 int i; | |
795 geo_t *geo; | |
796 | |
797 geo = shape->geo; | |
798 for(i = 0; i < n_areas; i++) { | |
799 if(is_overlay(geo->cur_area, areas[i])) | |
800 return 1; | |
801 } | |
802 return 0; | |
803 } | |
804 | |
805 static void update_canvas_2_parent(redraw_man_t *rdman, coord_t *coord) { | |
806 cairo_t *pcanvas, *canvas; | |
807 cairo_surface_t *surface; | |
808 | |
809 if(coord == rdman->root_coord) | |
810 return; | |
811 | |
812 canvas = coord->canvas; | |
813 pcanvas = coord->parent->canvas; | |
814 surface = cairo_get_target(canvas); | |
815 cairo_set_source_surface(pcanvas, surface, 0, 0); | |
816 cairo_paint_with_alpha(pcanvas, coord->opacity); | |
817 } | |
818 | |
819 static int draw_coord_shapes_in_areas(redraw_man_t *rdman, | |
820 coord_t *coord, | |
821 int n_areas, | |
822 area_t **areas) { | |
823 int dirty = 0; | |
824 int r; | |
825 shape_t *member; | |
826 coord_t *child; | |
827 cairo_t *canvas; | |
828 int mem_idx; | |
829 | |
830 canvas = coord->canvas; | |
831 member = STAILQ_HEAD(coord->members); | |
832 mem_idx = 0; | |
833 child = STAILQ_HEAD(coord->children); | |
834 while(child != NULL || member != NULL) { | |
835 if(child && child->before_pmem == mem_idx) { | |
836 r = draw_coord_shapes_in_areas(rdman, child, n_areas, areas); | |
837 dirty |= r; | |
838 child = STAILQ_NEXT(coord_t, sibling, child); | |
839 } else { | |
840 ASSERT(member != NULL); | |
841 if(is_shape_in_areas(member, n_areas, areas)) { | |
842 draw_shape(rdman, canvas, member); | |
843 dirty = 1; | |
844 } | |
845 member = STAILQ_NEXT(shape_t, coord_mem_next, member); | |
846 } | |
847 } | |
848 | |
849 if(dirty && coord->flags & COF_OWN_CANVAS) { | |
850 update_canvas_2_parent(rdman, coord); | |
851 clean_canvas_black(coord->canvas); | |
852 } | |
853 | |
854 return dirty; | |
855 } | |
712 | 856 |
713 static void draw_shapes_in_areas(redraw_man_t *rdman, | 857 static void draw_shapes_in_areas(redraw_man_t *rdman, |
714 int n_areas, | 858 int n_areas, |
715 area_t **areas) { | 859 area_t **areas) { |
716 geo_t *visit_geo; | 860 draw_coord_shapes_in_areas(rdman, rdman->root_coord, n_areas, areas); |
717 int i; | |
718 | |
719 for(visit_geo = STAILQ_HEAD(rdman->all_geos); | |
720 visit_geo != NULL; | |
721 visit_geo = STAILQ_NEXT(geo_t, next, visit_geo)) { | |
722 if(visit_geo->flags & GEF_DIRTY) | |
723 clean_shape(visit_geo->shape); | |
724 if(visit_geo->flags & GEF_HIDDEN) | |
725 continue; | |
726 for(i = 0; i < n_areas; i++) { | |
727 if(is_overlay(visit_geo->cur_area, areas[i])) { | |
728 draw_shape(rdman, visit_geo->shape); | |
729 break; | |
730 } | |
731 } | |
732 } | |
733 } | 861 } |
734 | 862 |
735 | 863 |
736 /*! \page coord_opacity How to support opacity attribute for group (coord)? | 864 /*! \page coord_opacity How to support opacity attribute for group (coord)? |
737 * | 865 * |
808 | 936 |
809 /* NOTE: Before redrawing, the canvas/surface must be cleaned. | 937 /* NOTE: Before redrawing, the canvas/surface must be cleaned. |
810 * NOTE: After redrawing, the content must be copied to the backend surface. | 938 * NOTE: After redrawing, the content must be copied to the backend surface. |
811 */ | 939 */ |
812 | 940 |
941 /*! \page redraw How to Redraw Shapes? | |
942 * | |
943 * Coords are corresponding objects for group tags of SVG files. | |
944 * In conceptional, every SVG group has a canvas, graphics of child shapes | |
945 * are drawed into the canvas, applied filters of group, and blended into | |
946 * canvas of parent of the group. | |
947 * | |
948 * But, we don't need to create actually a surface/canvas for every coord. | |
949 * We only create surface for coords their opacity value are not 1 or they | |
950 * apply filters on background. Child shapes of coords without canvas | |
951 * are drawed on canvas of nearest ancestor which have canvas. It said | |
952 * a coord owns a canvas or inherits from an ancestor. (\ref COF_OWN_CANVAS, | |
953 * clean_coord()) Except, root_coord always owns a canvas. | |
954 * | |
955 * \note Default opacity of a coord is 1. | |
956 * | |
957 * \sa | |
958 * - rdman_redraw_all() | |
959 * - rdman_redraw_changed() | |
960 * = draw_shapes_in_areas() | |
961 */ | |
962 | |
813 int rdman_redraw_all(redraw_man_t *rdman) { | 963 int rdman_redraw_all(redraw_man_t *rdman) { |
814 geo_t *geo; | 964 geo_t *geo; |
965 cairo_surface_t *surface; | |
966 area_t area; | |
815 int r; | 967 int r; |
816 | 968 |
817 r = clean_rdman_dirties(rdman); | 969 area.x = area.y = 0; |
970 #ifndef UNITTEST | |
971 surface = cairo_get_target(rdman->cr); | |
972 area.w = cairo_image_surface_get_width(surface); | |
973 area.h = cairo_image_surface_get_height(surface); | |
974 #else | |
975 area.w = 1024; | |
976 area.h = 1024; | |
977 #endif | |
978 add_dirty_area(rdman, &area); | |
979 | |
980 r = rdman_redraw_changed(rdman); | |
818 if(r != OK) | 981 if(r != OK) |
819 return ERR; | 982 return ERR; |
820 | |
821 clean_canvas(rdman->cr); | |
822 | |
823 for(geo = STAILQ_HEAD(rdman->all_geos); | |
824 geo != NULL; | |
825 geo = STAILQ_NEXT(geo_t, next, geo)) { | |
826 if(geo->flags & GEF_HIDDEN) | |
827 continue; | |
828 draw_shape(rdman, geo->shape); | |
829 } | |
830 copy_cr_2_backend(rdman, 0, NULL); | |
831 rdman->n_dirty_areas = 0; | |
832 | 983 |
833 return OK; | 984 return OK; |
834 } | 985 } |
835 | 986 |
836 int rdman_redraw_area(redraw_man_t *rdman, co_aix x, co_aix y, | 987 int rdman_redraw_area(redraw_man_t *rdman, co_aix x, co_aix y, |