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,