1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <string.h> /* strlen */
24 #include "dialibartrenderer.h"
30 #include "dia_image.h"
37 #include <pango/pango.h>
38 #include <pango/pangoft2.h>
39 #elif defined G_OS_WIN32
40 /* ugly namespace clashes */
41 #define Rectangle Win32Rectangle
42 #include <pango/pango.h>
45 #include <pango/pango.h>
49 #include <libart_lgpl/art_point.h>
50 #include <libart_lgpl/art_misc.h>
51 #include <libart_lgpl/art_affine.h>
52 #include <libart_lgpl/art_svp_vpath.h>
53 #include <libart_lgpl/art_bpath.h>
54 #include <libart_lgpl/art_vpath_bpath.h>
55 #include <libart_lgpl/art_rgb.h>
56 #include <libart_lgpl/art_rgb_svp.h>
57 #include <libart_lgpl/art_rgb_affine.h>
58 #include <libart_lgpl/art_rgb_rgba_affine.h>
59 #include <libart_lgpl/art_rgb_bitmap_affine.h>
60 #include <libart_lgpl/art_filterlevel.h>
61 #include <libart_lgpl/art_svp_intersect.h>
64 color_to_abgr(Color
*col
)
69 rgba
|= (guint
)(0xFF*col
->blue
) << 16;
70 rgba
|= (guint
)(0xFF*col
->green
) << 8;
71 rgba
|= (guint
)(0xFF*col
->red
);
77 color_to_rgba(DiaLibartRenderer
*renderer
, Color
*col
)
81 if (renderer
->highlight_color
!= NULL
) {
83 rgba
|= (guint
)(0xFF*renderer
->highlight_color
->red
) << 24;
84 rgba
|= (guint
)(0xFF*renderer
->highlight_color
->green
) << 16;
85 rgba
|= (guint
)(0xFF*renderer
->highlight_color
->blue
) << 8;
88 rgba
|= (guint
)(0xFF*col
->red
) << 24;
89 rgba
|= (guint
)(0xFF*col
->green
) << 16;
90 rgba
|= (guint
)(0xFF*col
->blue
) << 8;
97 get_width_pixels (DiaRenderer
*self
)
99 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
101 return renderer
->pixel_width
;
105 get_height_pixels (DiaRenderer
*self
)
107 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
109 return renderer
->pixel_height
;
113 begin_render(DiaRenderer
*self
)
116 /* pango_ft2_get_context API docs :
117 * ... Use of this function is discouraged, ...
119 * I've tried using the proper font_map stuff, but it kills font size:(
121 dia_font_push_context(pango_ft2_get_context(75, 75));
122 # define FONT_SCALE (1.0)
123 #elif defined G_OS_WIN32
124 dia_font_push_context(gdk_pango_context_get());
125 /* I shall never claim again to have understood Dias/Pangos font size
126 * relations ;). This was (1.0/22.0) but nowadays 1.0 seems to be
127 * fine with Pango/win32, too. --hb
129 # define FONT_SCALE (1.0)
131 dia_font_push_context (gdk_pango_context_get ());
132 # define FONT_SCALE (0.8)
137 end_render(DiaRenderer
*self
)
139 dia_font_pop_context();
145 set_linewidth(DiaRenderer
*self
, real linewidth
)
146 { /* 0 == hairline **/
147 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
149 if (renderer
->highlight_color
!= NULL
) {
150 /* 6 pixels wide -> 3 pixels beyond normal obj */
151 real border
= dia_untransform_length(renderer
->transform
, 6);
154 renderer
->line_width
=
155 dia_transform_length(renderer
->transform
, linewidth
);
156 if (renderer
->line_width
<=0.5)
157 renderer
->line_width
= 0.5; /* Minimum 0.5 pixel. */
161 set_linecaps(DiaRenderer
*self
, LineCaps mode
)
163 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
165 if (renderer
->highlight_color
!= NULL
) {
166 /* Can't tell that this does anything:( -LC */
167 renderer
->cap_style
= ART_PATH_STROKE_CAP_ROUND
;
171 renderer
->cap_style
= ART_PATH_STROKE_CAP_BUTT
;
174 renderer
->cap_style
= ART_PATH_STROKE_CAP_ROUND
;
176 case LINECAPS_PROJECTING
:
177 renderer
->cap_style
= ART_PATH_STROKE_CAP_SQUARE
;
184 set_linejoin(DiaRenderer
*self
, LineJoin mode
)
186 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
188 if (renderer
->highlight_color
!= NULL
) {
189 /* Can't tell that this does anything:( -LC */
190 renderer
->join_style
= ART_PATH_STROKE_JOIN_ROUND
;
194 renderer
->join_style
= ART_PATH_STROKE_JOIN_MITER
;
197 renderer
->join_style
= ART_PATH_STROKE_JOIN_ROUND
;
200 renderer
->join_style
= ART_PATH_STROKE_JOIN_BEVEL
;
207 set_linestyle(DiaRenderer
*self
, LineStyle mode
)
209 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
210 static double dash
[10];
213 renderer
->saved_line_style
= mode
;
215 case LINESTYLE_SOLID
:
216 renderer
->dash_enabled
= 0;
218 case LINESTYLE_DASHED
:
219 renderer
->dash_enabled
= 1;
220 renderer
->dash
.offset
= 0.0;
221 renderer
->dash
.n_dash
= 2;
222 renderer
->dash
.dash
= dash
;
223 dash
[0] = renderer
->dash_length
;
224 dash
[1] = renderer
->dash_length
;
226 case LINESTYLE_DASH_DOT
:
227 renderer
->dash_enabled
= 1;
228 renderer
->dash
.offset
= 0.0;
229 renderer
->dash
.n_dash
= 4;
230 renderer
->dash
.dash
= dash
;
231 hole_width
= (renderer
->dash_length
- renderer
->dot_length
) / 2.0;
234 dash
[0] = renderer
->dash_length
;
235 dash
[1] = hole_width
;
236 dash
[2] = renderer
->dot_length
;
237 dash
[3] = hole_width
;
239 case LINESTYLE_DASH_DOT_DOT
:
240 renderer
->dash_enabled
= 1;
241 renderer
->dash
.offset
= 0.0;
242 renderer
->dash
.n_dash
= 6;
243 renderer
->dash
.dash
= dash
;
244 hole_width
= (renderer
->dash_length
- 2*renderer
->dot_length
) / 3;
247 dash
[0] = renderer
->dash_length
;
248 dash
[1] = hole_width
;
249 dash
[2] = renderer
->dot_length
;
250 dash
[3] = hole_width
;
251 dash
[4] = renderer
->dot_length
;
252 dash
[5] = hole_width
;
254 case LINESTYLE_DOTTED
:
255 renderer
->dash_enabled
= 1;
256 renderer
->dash
.offset
= 0.0;
257 renderer
->dash
.n_dash
= 2;
258 renderer
->dash
.dash
= dash
;
259 dash
[0] = renderer
->dot_length
;
260 dash
[1] = renderer
->dot_length
;
266 set_dashlength(DiaRenderer
*self
, real length
)
267 { /* dot = 10% of len */
268 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
272 dia_transform_length(renderer
->transform
, length
);
274 renderer
->dash_length
= ddisp_len
;
275 renderer
->dot_length
= ddisp_len
*0.1;
277 if (renderer
->dash_length
<1.0)
278 renderer
->dash_length
= 1.0;
279 if (renderer
->dash_length
>255.0)
280 renderer
->dash_length
= 255.0;
281 if (renderer
->dot_length
<1.0)
282 renderer
->dot_length
= 1.0;
283 if (renderer
->dot_length
>255.0)
284 renderer
->dot_length
= 255.0;
285 set_linestyle(self
, renderer
->saved_line_style
);
289 set_fillstyle(DiaRenderer
*self
, FillStyle mode
)
292 case FILLSTYLE_SOLID
:
295 message_error(_("gdk_renderer: Unsupported fill mode specified!\n"));
300 set_font(DiaRenderer
*self
, DiaFont
*font
, real height
)
302 self
->font_height
= height
* FONT_SCALE
;
306 dia_font_unref(self
->font
);
311 draw_line(DiaRenderer
*self
,
312 Point
*start
, Point
*end
,
315 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
316 ArtVpath
*vpath
, *vpath_dashed
;
321 rgba
= color_to_rgba(renderer
, line_color
);
323 vpath
= art_new (ArtVpath
, 3);
325 dia_transform_coords_double(renderer
->transform
, start
->x
, start
->y
, &x
, &y
);
326 vpath
[0].code
= ART_MOVETO
;
330 dia_transform_coords_double(renderer
->transform
, end
->x
, end
->y
, &x
, &y
);
331 vpath
[1].code
= ART_LINETO
;
335 vpath
[2].code
= ART_END
;
339 if (renderer
->dash_enabled
) {
340 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
342 vpath
= vpath_dashed
;
345 svp
= art_svp_vpath_stroke (vpath
,
346 renderer
->join_style
,
348 renderer
->line_width
,
354 art_rgb_svp_alpha (svp
,
356 renderer
->pixel_width
,
357 renderer
->pixel_height
,
359 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
366 draw_polyline(DiaRenderer
*self
,
367 Point
*points
, int num_points
,
370 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
371 ArtVpath
*vpath
, *vpath_dashed
;
377 rgba
= color_to_rgba(renderer
, line_color
);
379 vpath
= art_new (ArtVpath
, num_points
+1);
381 for (i
=0;i
<num_points
;i
++) {
382 dia_transform_coords_double(renderer
->transform
,
383 points
[i
].x
, points
[i
].y
,
385 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
389 vpath
[i
].code
= ART_END
;
393 if (renderer
->dash_enabled
) {
394 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
396 vpath
= vpath_dashed
;
399 svp
= art_svp_vpath_stroke (vpath
,
400 renderer
->join_style
,
402 renderer
->line_width
,
408 art_rgb_svp_alpha (svp
,
410 renderer
->pixel_width
,
411 renderer
->pixel_height
,
413 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
420 draw_polygon(DiaRenderer
*self
,
421 Point
*points
, int num_points
,
424 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
425 ArtVpath
*vpath
, *vpath_dashed
;
431 rgba
= color_to_rgba(renderer
, line_color
);
433 vpath
= art_new (ArtVpath
, num_points
+2);
435 for (i
=0;i
<num_points
;i
++) {
436 dia_transform_coords_double(renderer
->transform
,
437 points
[i
].x
, points
[i
].y
,
439 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
443 dia_transform_coords_double(renderer
->transform
,
444 points
[0].x
, points
[0].y
,
446 vpath
[i
].code
= ART_LINETO
;
449 vpath
[i
+1].code
= ART_END
;
453 if (renderer
->dash_enabled
) {
454 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
456 vpath
= vpath_dashed
;
459 svp
= art_svp_vpath_stroke (vpath
,
460 renderer
->join_style
,
462 renderer
->line_width
,
468 art_rgb_svp_alpha (svp
,
470 renderer
->pixel_width
,
471 renderer
->pixel_height
,
473 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
480 fill_polygon(DiaRenderer
*self
,
481 Point
*points
, int num_points
,
484 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
492 rgba
= color_to_rgba(renderer
, color
);
494 vpath
= art_new (ArtVpath
, num_points
+2);
496 for (i
=0;i
<num_points
;i
++) {
497 dia_transform_coords_double(renderer
->transform
,
498 points
[i
].x
, points
[i
].y
,
500 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
504 dia_transform_coords_double(renderer
->transform
,
505 points
[0].x
, points
[0].y
,
507 vpath
[i
].code
= ART_LINETO
;
510 vpath
[i
+1].code
= ART_END
;
514 temp
= art_svp_from_vpath (vpath
);
518 /** We always use odd-even wind rule */
519 swr
= art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN
);
521 art_svp_intersector(temp
, swr
);
522 svp
= art_svp_writer_rewind_reap(swr
);
525 art_rgb_svp_alpha (svp
,
527 renderer
->pixel_width
,
528 renderer
->pixel_height
,
530 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
537 draw_rect(DiaRenderer
*self
,
538 Point
*ul_corner
, Point
*lr_corner
,
541 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
542 ArtVpath
*vpath
, *vpath_dashed
;
545 double top
, bottom
, left
, right
;
547 dia_transform_coords_double(renderer
->transform
,
548 ul_corner
->x
, ul_corner
->y
, &left
, &top
);
549 dia_transform_coords_double(renderer
->transform
,
550 lr_corner
->x
, lr_corner
->y
, &right
, &bottom
);
552 if ((left
>right
) || (top
>bottom
))
555 rgba
= color_to_rgba(renderer
, color
);
557 vpath
= art_new (ArtVpath
, 6);
559 vpath
[0].code
= ART_MOVETO
;
562 vpath
[1].code
= ART_LINETO
;
565 vpath
[2].code
= ART_LINETO
;
568 vpath
[3].code
= ART_LINETO
;
571 vpath
[4].code
= ART_LINETO
;
574 vpath
[5].code
= ART_END
;
578 if (renderer
->dash_enabled
) {
579 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
581 vpath
= vpath_dashed
;
584 svp
= art_svp_vpath_stroke (vpath
,
585 renderer
->join_style
,
587 renderer
->line_width
,
593 art_rgb_svp_alpha (svp
,
595 renderer
->pixel_width
,
596 renderer
->pixel_height
,
598 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
605 fill_rect(DiaRenderer
*self
,
606 Point
*ul_corner
, Point
*lr_corner
,
609 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
613 double top
, bottom
, left
, right
;
615 dia_transform_coords_double(renderer
->transform
,
616 ul_corner
->x
, ul_corner
->y
, &left
, &top
);
617 dia_transform_coords_double(renderer
->transform
,
618 lr_corner
->x
, lr_corner
->y
, &right
, &bottom
);
620 if ((left
>right
) || (top
>bottom
))
623 rgba
= color_to_rgba(renderer
, color
);
625 vpath
= art_new (ArtVpath
, 6);
627 vpath
[0].code
= ART_MOVETO
;
630 vpath
[1].code
= ART_LINETO
;
633 vpath
[2].code
= ART_LINETO
;
636 vpath
[3].code
= ART_LINETO
;
639 vpath
[4].code
= ART_LINETO
;
642 vpath
[5].code
= ART_END
;
646 svp
= art_svp_from_vpath (vpath
);
650 art_rgb_svp_alpha (svp
,
652 renderer
->pixel_width
,
653 renderer
->pixel_height
,
655 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
662 draw_arc(DiaRenderer
*self
,
664 real width
, real height
,
665 real angle1
, real angle2
,
668 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
669 ArtVpath
*vpath
, *vpath_dashed
;
676 double theta
, dtheta
;
679 width
= dia_transform_length(renderer
->transform
, width
);
680 height
= dia_transform_length(renderer
->transform
, height
);
681 dia_transform_coords_double(renderer
->transform
,
682 center
->x
, center
->y
, &x
, &y
);
684 if ((width
<0.0) || (height
<0.0))
687 dangle
= angle2
-angle1
;
691 /* Over-approximate the circumference */
697 circ
*= dangle
/360.0;
699 #define LEN_PER_SEGMENT 3.0
701 num_points
= circ
/LEN_PER_SEGMENT
;
702 if (num_points
<5) /* Don't be too coarse */
705 rgba
= color_to_rgba(renderer
, line_color
);
707 vpath
= art_new (ArtVpath
, num_points
+1);
709 theta
= M_PI
*angle1
/180.0;
710 dtheta
= (M_PI
*dangle
/180.0)/(num_points
-1);
711 for (i
=0;i
<num_points
;i
++) {
712 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
713 vpath
[i
].x
= x
+ width
/2.0*cos(theta
);
714 vpath
[i
].y
= y
- height
/2.0*sin(theta
);
717 vpath
[i
].code
= ART_END
;
721 if (renderer
->dash_enabled
) {
722 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
724 vpath
= vpath_dashed
;
727 svp
= art_svp_vpath_stroke (vpath
,
728 renderer
->join_style
,
730 renderer
->line_width
,
736 art_rgb_svp_alpha (svp
,
738 renderer
->pixel_width
,
739 renderer
->pixel_height
,
741 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
748 fill_arc(DiaRenderer
*self
,
750 real width
, real height
,
751 real angle1
, real angle2
,
754 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
762 double theta
, dtheta
;
765 width
= dia_transform_length(renderer
->transform
, width
);
766 height
= dia_transform_length(renderer
->transform
, height
);
767 dia_transform_coords_double(renderer
->transform
,
768 center
->x
, center
->y
, &x
, &y
);
770 if ((width
<0.0) || (height
<0.0))
773 dangle
= angle2
-angle1
;
777 /* Over-approximate the circumference */
783 circ
*= dangle
/360.0;
785 #define LEN_PER_SEGMENT 3.0
787 num_points
= circ
/LEN_PER_SEGMENT
;
788 if (num_points
<5) /* Don't be too coarse */
791 rgba
= color_to_rgba(renderer
, color
);
793 vpath
= art_new (ArtVpath
, num_points
+2+1);
795 vpath
[0].code
= ART_MOVETO
;
798 theta
= M_PI
*angle1
/180.0;
799 dtheta
= (M_PI
*dangle
/180.0)/(num_points
-1);
800 for (i
=0;i
<num_points
;i
++) {
801 vpath
[i
+1].code
= ART_LINETO
;
802 vpath
[i
+1].x
= x
+ width
/2.0*cos(theta
);
803 vpath
[i
+1].y
= y
- height
/2.0*sin(theta
);
806 vpath
[i
+1].code
= ART_LINETO
;
809 vpath
[i
+2].code
= ART_END
;
813 svp
= art_svp_from_vpath (vpath
);
817 art_rgb_svp_alpha (svp
,
819 renderer
->pixel_width
,
820 renderer
->pixel_height
,
822 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
829 draw_ellipse(DiaRenderer
*self
,
831 real width
, real height
,
834 draw_arc(self
, center
, width
, height
, 0.0, 360.0, color
);
838 fill_ellipse(DiaRenderer
*self
,
840 real width
, real height
,
843 fill_arc(self
, center
, width
, height
, 0.0, 360.0, color
);
847 draw_bezier(DiaRenderer
*self
,
852 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
853 ArtVpath
*vpath
, *vpath_dashed
;
860 rgba
= color_to_rgba(renderer
, line_color
);
862 bpath
= art_new (ArtBpath
, numpoints
+1);
864 for (i
=0;i
<numpoints
;i
++) {
865 switch(points
[i
].type
) {
867 dia_transform_coords_double(renderer
->transform
,
868 points
[i
].p1
.x
, points
[i
].p1
.y
,
870 bpath
[i
].code
= ART_MOVETO
;
875 dia_transform_coords_double(renderer
->transform
,
876 points
[i
].p1
.x
, points
[i
].p1
.y
,
878 bpath
[i
].code
= ART_LINETO
;
883 bpath
[i
].code
= ART_CURVETO
;
884 dia_transform_coords_double(renderer
->transform
,
885 points
[i
].p1
.x
, points
[i
].p1
.y
,
889 dia_transform_coords_double(renderer
->transform
,
890 points
[i
].p2
.x
, points
[i
].p2
.y
,
894 dia_transform_coords_double(renderer
->transform
,
895 points
[i
].p3
.x
, points
[i
].p3
.y
,
902 bpath
[i
].code
= ART_END
;
906 vpath
= art_bez_path_to_vec(bpath
, 0.25);
909 if (renderer
->dash_enabled
) {
910 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
912 vpath
= vpath_dashed
;
915 svp
= art_svp_vpath_stroke (vpath
,
916 renderer
->join_style
,
918 renderer
->line_width
,
924 art_rgb_svp_alpha (svp
,
926 renderer
->pixel_width
,
927 renderer
->pixel_height
,
929 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
936 fill_bezier(DiaRenderer
*self
,
937 BezPoint
*points
, /* Last point must be same as first point */
941 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
949 rgba
= color_to_rgba(renderer
, color
);
951 bpath
= art_new (ArtBpath
, numpoints
+1);
953 for (i
=0;i
<numpoints
;i
++) {
954 switch(points
[i
].type
) {
956 dia_transform_coords_double(renderer
->transform
,
957 points
[i
].p1
.x
, points
[i
].p1
.y
,
959 bpath
[i
].code
= ART_MOVETO
;
964 dia_transform_coords_double(renderer
->transform
,
965 points
[i
].p1
.x
, points
[i
].p1
.y
,
967 bpath
[i
].code
= ART_LINETO
;
972 bpath
[i
].code
= ART_CURVETO
;
973 dia_transform_coords_double(renderer
->transform
,
974 points
[i
].p1
.x
, points
[i
].p1
.y
,
978 dia_transform_coords_double(renderer
->transform
,
979 points
[i
].p2
.x
, points
[i
].p2
.y
,
983 dia_transform_coords_double(renderer
->transform
,
984 points
[i
].p3
.x
, points
[i
].p3
.y
,
991 bpath
[i
].code
= ART_END
;
995 vpath
= art_bez_path_to_vec(bpath
, 0.25);
998 svp
= art_svp_from_vpath (vpath
);
1002 art_rgb_svp_alpha (svp
,
1004 renderer
->pixel_width
,
1005 renderer
->pixel_height
,
1007 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
1010 art_svp_free( svp
);
1014 /* Draw a highlighted version of a string.
1017 draw_highlighted_string(DiaLibartRenderer
*renderer
,
1018 PangoLayout
*layout
,
1025 double top
, bottom
, left
, right
;
1027 pango_layout_get_pixel_size(layout
, &width
, &height
);
1028 dia_transform_coords_double(renderer
->transform
,
1031 right
= left
+width
+6;
1032 bottom
= top
+height
;
1034 if ((left
>right
) || (top
>bottom
))
1037 vpath
= art_new (ArtVpath
, 6);
1039 vpath
[0].code
= ART_MOVETO
;
1042 vpath
[1].code
= ART_LINETO
;
1045 vpath
[2].code
= ART_LINETO
;
1047 vpath
[2].y
= bottom
;
1048 vpath
[3].code
= ART_LINETO
;
1050 vpath
[3].y
= bottom
;
1051 vpath
[4].code
= ART_LINETO
;
1054 vpath
[5].code
= ART_END
;
1058 svp
= art_svp_from_vpath (vpath
);
1062 art_rgb_svp_alpha (svp
,
1064 renderer
->pixel_width
,
1065 renderer
->pixel_height
,
1067 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
1070 art_svp_free( svp
);
1074 draw_text_line(DiaRenderer
*self
, TextLine
*text_line
,
1075 Point
*pos
, Color
*color
)
1077 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
1078 /* Not working with Pango */
1079 guint8
*bitmap
= NULL
;
1082 PangoLayout
* layout
;
1085 double affine
[6], tmpaffine
[6];
1088 gchar
*text
= text_line_get_string(text_line
);
1089 real scale
= dia_transform_length(renderer
->transform
, 1.0);
1091 point_copy(&start_pos
,pos
);
1093 rgba
= color_to_rgba(renderer
, color
);
1095 /* Something's screwed up with the zooming for fonts.
1096 It's like it zooms double. Yet removing some of the zooms
1097 don't seem to work, either.
1100 old_zoom = ddisp->zoom_factor;
1101 ddisp->zoom_factor = ddisp->zoom_factor;
1104 start_pos
.y
-= text_line_get_ascent(text_line
);
1106 dia_transform_coords_double(renderer
->transform
,
1107 start_pos
.x
, start_pos
.y
, &x
, &y
);
1109 layout
= dia_font_build_layout(text
, text_line
->font
,
1110 dia_transform_length(renderer
->transform
,
1111 text_line_get_height(text_line
)) / 20.0);
1113 text_line_adjust_layout_line(text_line
, pango_layout_get_line(layout
, 0),
1116 if (renderer
->highlight_color
!= NULL
) {
1117 draw_highlighted_string(renderer
, layout
, start_pos
.x
, start_pos
.y
, rgba
);
1118 g_object_unref(G_OBJECT(layout
));
1123 ddisp->zoom_factor = old_zoom;
1125 pango_layout_get_pixel_size(layout
, &width
, &height
);
1126 /* Pango doesn't have a 'render to raw bits' function, so we have
1127 * to render based on what other engines are available.
1130 #ifdef HAVE_FREETYPE
1131 /* Freetype version */
1136 rowstride
= 32*((width
+31)/31);
1138 graybitmap
= (guint8
*)g_new0(guint8
, height
*rowstride
);
1140 ftbitmap
.rows
= height
;
1141 ftbitmap
.width
= width
;
1142 ftbitmap
.pitch
= rowstride
;
1143 ftbitmap
.buffer
= graybitmap
;
1144 ftbitmap
.num_grays
= 256;
1145 ftbitmap
.pixel_mode
= ft_pixel_mode_grays
;
1146 ftbitmap
.palette_mode
= 0;
1147 ftbitmap
.palette
= 0;
1148 pango_ft2_render_layout(&ftbitmap
, layout
, 0, 0);
1149 bitmap
= (guint8
*)g_new0(guint8
, height
*rowstride
*DEPTH
);
1150 for (i
= 0; i
< height
; i
++) {
1151 for (j
= 0; j
< width
; j
++) {
1152 bitmap
[DEPTH
*(i
*rowstride
+j
)] = color
->red
*255;
1153 bitmap
[DEPTH
*(i
*rowstride
+j
)+1] = color
->green
*255;
1154 bitmap
[DEPTH
*(i
*rowstride
+j
)+2] = color
->blue
*255;
1155 bitmap
[DEPTH
*(i
*rowstride
+j
)+3] = graybitmap
[i
*rowstride
+j
];
1161 /* gdk does not like 0x0 sized (it does not make much sense with the others as well,
1162 * but they don't complain ;) */
1163 if (width
* height
> 0)
1165 GdkPixmap
*pixmap
= gdk_pixmap_new (NULL
, width
, height
, 24);
1166 GdkGC
*gc
= gdk_gc_new (pixmap
);
1169 rowstride
= 32*((width
+31)/31);
1170 #if 1 /* with 8 bit pixmap we would probably need to set the whole gray palette */
1171 gdk_gc_set_foreground (gc
, &color_gdk_black
);
1172 gdk_gc_set_background (gc
, &color_gdk_white
);
1173 gdk_draw_rectangle (GDK_DRAWABLE (pixmap
), gc
, TRUE
, 0, 0, width
, height
);
1175 gdk_gc_set_foreground (gc
, &color_gdk_white
);
1176 gdk_gc_set_background (gc
, &color_gdk_black
);
1177 gdk_draw_layout (GDK_DRAWABLE (pixmap
), gc
, 0, 0, layout
);
1178 image
= gdk_drawable_get_image (GDK_DRAWABLE (pixmap
), 0, 0, width
, height
);
1179 g_object_unref (G_OBJECT (gc
));
1180 g_object_unref (G_OBJECT (pixmap
));
1181 bitmap
= (guint8
*)g_new0(guint8
, height
*rowstride
*DEPTH
);
1182 for (i
= 0; i
< height
; i
++) {
1183 for (j
= 0; j
< width
; j
++) {
1184 bitmap
[DEPTH
*(i
*rowstride
+j
)] = color
->red
*255;
1185 bitmap
[DEPTH
*(i
*rowstride
+j
)+1] = color
->green
*255;
1186 bitmap
[DEPTH
*(i
*rowstride
+j
)+2] = color
->blue
*255;
1187 bitmap
[DEPTH
*(i
*rowstride
+j
)+3] = gdk_image_get_pixel (image
, j
, i
) & 0xFF;
1190 g_object_unref (G_OBJECT (image
));
1194 /* abuse_layout_object(layout,text); */
1196 g_object_unref(G_OBJECT(layout
));
1198 art_affine_identity(affine
);
1199 art_affine_translate(tmpaffine
, x
, y
);
1200 art_affine_multiply(affine
, affine
, tmpaffine
);
1203 art_rgb_rgba_affine (renderer
->rgb_buffer
,
1205 renderer
->pixel_width
,
1206 renderer
->pixel_height
,
1207 renderer
->pixel_width
* 3,
1213 ART_FILTER_NEAREST
, NULL
);
1220 draw_string (DiaRenderer
*self
,
1222 Point
*pos
, Alignment alignment
,
1225 TextLine
*text_line
= text_line_new(text
, self
->font
, self
->font_height
);
1226 Point realigned_pos
= *pos
;
1227 realigned_pos
.x
-= text_line_get_alignment_adjustment(text_line
, alignment
);
1228 draw_text_line(self
, text_line
, &realigned_pos
, color
);
1232 /* Get the width of the given text in cm */
1234 get_text_width(DiaRenderer
*object
,
1235 const gchar
*text
, int length
)
1237 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (object
);
1239 TextLine
*text_line
;
1241 if (length
!= strlen(text
)) {
1244 /* A couple UTF8-chars: æblegrød ŠŤ Ž Ä™ ć Å„ уфхцÐ?ОПРЄ Ñ” Ò? Њ Ћ Ð? */
1245 ulen
= g_utf8_offset_to_pointer(text
, length
)-text
;
1246 if (!g_utf8_validate(text
, ulen
, NULL
)) {
1247 g_warning ("Text at char %d not valid\n", length
);
1249 othertx
= g_strndup(text
, ulen
);
1250 text_line
= text_line_new(othertx
, object
->font
, object
->font_height
);
1252 text_line
= text_line_new(text
, object
->font
, object
->font_height
);
1254 result
= text_line_get_width(text_line
);
1255 text_line_destroy(text_line
);
1261 draw_image(DiaRenderer
*self
,
1263 real width
, real height
,
1266 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
1268 /* Todo: Handle some kind of clipping! */
1270 if (renderer
->highlight_color
!= NULL
) {
1272 DiaRendererClass
*self_class
= DIA_RENDERER_GET_CLASS (self
);
1277 self_class
->fill_rect(self
, point
, &lr
, renderer
->highlight_color
);
1279 double real_width
, real_height
;
1281 int src_width
, src_height
;
1284 real_width
= dia_transform_length(renderer
->transform
, width
);
1285 real_height
= dia_transform_length(renderer
->transform
, height
);
1286 dia_transform_coords_double(renderer
->transform
,
1287 point
->x
, point
->y
, &x
, &y
);
1289 src_width
= dia_image_width(image
);
1290 src_height
= dia_image_height(image
);
1291 rowstride
= dia_image_rowstride(image
);
1293 affine
[0] = real_width
/(double)src_width
;
1296 affine
[3] = real_height
/(double)src_height
;
1300 if (dia_image_rgba_data(image
)) {
1301 /* If there is an alpha channel, we can use it directly. */
1302 const guint8
*img_data
= dia_image_rgba_data(image
);
1303 art_rgb_rgba_affine(renderer
->rgb_buffer
,
1305 renderer
->pixel_width
,
1306 renderer
->pixel_height
,
1307 renderer
->pixel_width
*3,
1308 img_data
, src_width
, src_height
,
1310 affine
, ART_FILTER_NEAREST
, NULL
);
1311 /* Note that dia_image_rgba_data doesn't copy */
1313 guint8
*img_data
= dia_image_rgb_data(image
);
1315 art_rgb_affine(renderer
->rgb_buffer
,
1317 renderer
->pixel_width
,
1318 renderer
->pixel_height
,
1319 renderer
->pixel_width
*3,
1320 img_data
, src_width
, src_height
,
1322 affine
, ART_FILTER_NEAREST
, NULL
);
1331 draw_object (DiaRenderer
*renderer
, DiaObject
*object
)
1333 if (renderer
->is_interactive
&&
1334 object
->highlight_color
!= NULL
) {
1335 DiaLibartRenderer
*libart_rend
= DIA_LIBART_RENDERER(renderer
);
1336 libart_rend
->highlight_color
= object
->highlight_color
;
1337 object
->ops
->draw(object
, renderer
);
1338 libart_rend
->highlight_color
= NULL
;
1340 object
->ops
->draw(object
, renderer
);
1344 renderer_init (DiaLibartRenderer
*renderer
, gpointer g_class
)
1346 renderer
->rgb_buffer
= NULL
;
1348 renderer
->line_width
= 1.0;
1349 renderer
->cap_style
= ART_PATH_STROKE_CAP_BUTT
;
1350 renderer
->join_style
= ART_PATH_STROKE_JOIN_MITER
;
1352 renderer
->saved_line_style
= LINESTYLE_SOLID
;
1353 renderer
->dash_enabled
= 0;
1354 renderer
->dash_length
= 10;
1355 renderer
->dot_length
= 1;
1357 renderer
->highlight_color
= NULL
;
1359 renderer
->parent_instance
.font
= NULL
;
1362 static void dia_libart_renderer_class_init (DiaLibartRendererClass
*klass
);
1363 static gpointer parent_class
= NULL
;
1366 renderer_finalize (GObject
*object
)
1368 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (object
);
1370 if (renderer
->rgb_buffer
!= NULL
)
1371 g_free(renderer
->rgb_buffer
);
1373 G_OBJECT_CLASS (parent_class
)->finalize (object
);
1377 dia_libart_renderer_get_type (void)
1379 static GType object_type
= 0;
1383 static const GTypeInfo object_info
=
1385 sizeof (DiaLibartRendererClass
),
1386 (GBaseInitFunc
) NULL
,
1387 (GBaseFinalizeFunc
) NULL
,
1388 (GClassInitFunc
) dia_libart_renderer_class_init
,
1389 NULL
, /* class_finalize */
1390 NULL
, /* class_data */
1391 sizeof (DiaLibartRenderer
),
1392 0, /* n_preallocs */
1393 (GInstanceInitFunc
)renderer_init
/* init */
1396 object_type
= g_type_register_static (DIA_TYPE_RENDERER
,
1397 "DiaLibartRenderer",
1405 dia_libart_renderer_class_init (DiaLibartRendererClass
*klass
)
1407 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1408 DiaRendererClass
*renderer_class
= DIA_RENDERER_CLASS (klass
);
1410 parent_class
= g_type_class_peek_parent (klass
);
1412 gobject_class
->finalize
= renderer_finalize
;
1414 /* Here we set the functions that we define for this renderer. */
1415 renderer_class
->get_width_pixels
= get_width_pixels
;
1416 renderer_class
->get_height_pixels
= get_height_pixels
;
1418 renderer_class
->begin_render
= begin_render
;
1419 renderer_class
->end_render
= end_render
;
1421 renderer_class
->set_linewidth
= set_linewidth
;
1422 renderer_class
->set_linecaps
= set_linecaps
;
1423 renderer_class
->set_linejoin
= set_linejoin
;
1424 renderer_class
->set_linestyle
= set_linestyle
;
1425 renderer_class
->set_dashlength
= set_dashlength
;
1426 renderer_class
->set_fillstyle
= set_fillstyle
;
1427 renderer_class
->set_font
= set_font
;
1429 renderer_class
->draw_line
= draw_line
;
1430 renderer_class
->draw_polyline
= draw_polyline
;
1432 renderer_class
->draw_polygon
= draw_polygon
;
1433 renderer_class
->fill_polygon
= fill_polygon
;
1435 renderer_class
->draw_rect
= draw_rect
;
1436 renderer_class
->fill_rect
= fill_rect
;
1438 renderer_class
->draw_arc
= draw_arc
;
1439 renderer_class
->fill_arc
= fill_arc
;
1441 renderer_class
->draw_ellipse
= draw_ellipse
;
1442 renderer_class
->fill_ellipse
= fill_ellipse
;
1444 renderer_class
->draw_bezier
= draw_bezier
;
1445 renderer_class
->fill_bezier
= fill_bezier
;
1447 renderer_class
->draw_string
= draw_string
;
1448 renderer_class
->draw_text_line
= draw_text_line
;
1450 renderer_class
->draw_image
= draw_image
;
1452 renderer_class
->draw_object
= draw_object
;
1454 /* Interactive functions */
1455 renderer_class
->get_text_width
= get_text_width
;