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>
63 color_to_abgr(Color
*col
)
68 rgba
|= (guint
)(0xFF*col
->blue
) << 16;
69 rgba
|= (guint
)(0xFF*col
->green
) << 8;
70 rgba
|= (guint
)(0xFF*col
->red
);
76 color_to_rgba(DiaLibartRenderer
*renderer
, Color
*col
)
80 if (renderer
->highlight_color
!= NULL
) {
82 rgba
|= (guint
)(0xFF*renderer
->highlight_color
->red
) << 24;
83 rgba
|= (guint
)(0xFF*renderer
->highlight_color
->green
) << 16;
84 rgba
|= (guint
)(0xFF*renderer
->highlight_color
->blue
) << 8;
87 rgba
|= (guint
)(0xFF*col
->red
) << 24;
88 rgba
|= (guint
)(0xFF*col
->green
) << 16;
89 rgba
|= (guint
)(0xFF*col
->blue
) << 8;
96 get_width_pixels (DiaRenderer
*self
)
98 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
100 return renderer
->pixel_width
;
104 get_height_pixels (DiaRenderer
*self
)
106 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
108 return renderer
->pixel_height
;
112 begin_render(DiaRenderer
*self
)
115 /* pango_ft2_get_context API docs :
116 * ... Use of this function is discouraged, ...
118 * I've tried using the proper font_map stuff, but it kills font size:(
120 dia_font_push_context(pango_ft2_get_context(75, 75));
121 # define FONT_SCALE (1.0)
122 #elif defined G_OS_WIN32
123 dia_font_push_context(gdk_pango_context_get());
124 /* I shall never claim again to have understood Dias/Pangos font size
125 * relations ;). This was (1.0/22.0) but nowadays 1.0 seems to be
126 * fine with Pango/win32, too. --hb
128 # define FONT_SCALE (1.0)
130 dia_font_push_context (gdk_pango_context_get ());
131 # define FONT_SCALE (0.8)
136 end_render(DiaRenderer
*self
)
138 dia_font_pop_context();
144 set_linewidth(DiaRenderer
*self
, real linewidth
)
145 { /* 0 == hairline **/
146 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
148 if (renderer
->highlight_color
!= NULL
) {
149 /* 6 pixels wide -> 3 pixels beyond normal obj */
150 real border
= dia_untransform_length(renderer
->transform
, 6);
153 renderer
->line_width
=
154 dia_transform_length(renderer
->transform
, linewidth
);
155 if (renderer
->line_width
<=0.5)
156 renderer
->line_width
= 0.5; /* Minimum 0.5 pixel. */
160 set_linecaps(DiaRenderer
*self
, LineCaps mode
)
162 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
164 if (renderer
->highlight_color
!= NULL
) {
165 /* Can't tell that this does anything:( -LC */
166 renderer
->cap_style
= ART_PATH_STROKE_CAP_ROUND
;
170 renderer
->cap_style
= ART_PATH_STROKE_CAP_BUTT
;
173 renderer
->cap_style
= ART_PATH_STROKE_CAP_ROUND
;
175 case LINECAPS_PROJECTING
:
176 renderer
->cap_style
= ART_PATH_STROKE_CAP_SQUARE
;
183 set_linejoin(DiaRenderer
*self
, LineJoin mode
)
185 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
187 if (renderer
->highlight_color
!= NULL
) {
188 /* Can't tell that this does anything:( -LC */
189 renderer
->join_style
= ART_PATH_STROKE_JOIN_ROUND
;
193 renderer
->join_style
= ART_PATH_STROKE_JOIN_MITER
;
196 renderer
->join_style
= ART_PATH_STROKE_JOIN_ROUND
;
199 renderer
->join_style
= ART_PATH_STROKE_JOIN_BEVEL
;
206 set_linestyle(DiaRenderer
*self
, LineStyle mode
)
208 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
209 static double dash
[10];
212 renderer
->saved_line_style
= mode
;
214 case LINESTYLE_SOLID
:
215 renderer
->dash_enabled
= 0;
217 case LINESTYLE_DASHED
:
218 renderer
->dash_enabled
= 1;
219 renderer
->dash
.offset
= 0.0;
220 renderer
->dash
.n_dash
= 2;
221 renderer
->dash
.dash
= dash
;
222 dash
[0] = renderer
->dash_length
;
223 dash
[1] = renderer
->dash_length
;
225 case LINESTYLE_DASH_DOT
:
226 renderer
->dash_enabled
= 1;
227 renderer
->dash
.offset
= 0.0;
228 renderer
->dash
.n_dash
= 4;
229 renderer
->dash
.dash
= dash
;
230 hole_width
= (renderer
->dash_length
- renderer
->dot_length
) / 2.0;
233 dash
[0] = renderer
->dash_length
;
234 dash
[1] = hole_width
;
235 dash
[2] = renderer
->dot_length
;
236 dash
[3] = hole_width
;
238 case LINESTYLE_DASH_DOT_DOT
:
239 renderer
->dash_enabled
= 1;
240 renderer
->dash
.offset
= 0.0;
241 renderer
->dash
.n_dash
= 6;
242 renderer
->dash
.dash
= dash
;
243 hole_width
= (renderer
->dash_length
- 2*renderer
->dot_length
) / 3;
246 dash
[0] = renderer
->dash_length
;
247 dash
[1] = hole_width
;
248 dash
[2] = renderer
->dot_length
;
249 dash
[3] = hole_width
;
250 dash
[4] = renderer
->dot_length
;
251 dash
[5] = hole_width
;
253 case LINESTYLE_DOTTED
:
254 renderer
->dash_enabled
= 1;
255 renderer
->dash
.offset
= 0.0;
256 renderer
->dash
.n_dash
= 2;
257 renderer
->dash
.dash
= dash
;
258 dash
[0] = renderer
->dot_length
;
259 dash
[1] = renderer
->dot_length
;
265 set_dashlength(DiaRenderer
*self
, real length
)
266 { /* dot = 10% of len */
267 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
271 dia_transform_length(renderer
->transform
, length
);
273 renderer
->dash_length
= ddisp_len
;
274 renderer
->dot_length
= ddisp_len
*0.1;
276 if (renderer
->dash_length
<1.0)
277 renderer
->dash_length
= 1.0;
278 if (renderer
->dash_length
>255.0)
279 renderer
->dash_length
= 255.0;
280 if (renderer
->dot_length
<1.0)
281 renderer
->dot_length
= 1.0;
282 if (renderer
->dot_length
>255.0)
283 renderer
->dot_length
= 255.0;
284 set_linestyle(self
, renderer
->saved_line_style
);
288 set_fillstyle(DiaRenderer
*self
, FillStyle mode
)
291 case FILLSTYLE_SOLID
:
294 message_error(_("gdk_renderer: Unsupported fill mode specified!\n"));
299 set_font(DiaRenderer
*self
, DiaFont
*font
, real height
)
301 self
->font_height
= height
* FONT_SCALE
;
305 dia_font_unref(self
->font
);
310 draw_line(DiaRenderer
*self
,
311 Point
*start
, Point
*end
,
314 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
315 ArtVpath
*vpath
, *vpath_dashed
;
320 rgba
= color_to_rgba(renderer
, line_color
);
322 vpath
= art_new (ArtVpath
, 3);
324 dia_transform_coords_double(renderer
->transform
, start
->x
, start
->y
, &x
, &y
);
325 vpath
[0].code
= ART_MOVETO
;
329 dia_transform_coords_double(renderer
->transform
, end
->x
, end
->y
, &x
, &y
);
330 vpath
[1].code
= ART_LINETO
;
334 vpath
[2].code
= ART_END
;
338 if (renderer
->dash_enabled
) {
339 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
341 vpath
= vpath_dashed
;
344 svp
= art_svp_vpath_stroke (vpath
,
345 renderer
->join_style
,
347 renderer
->line_width
,
353 art_rgb_svp_alpha (svp
,
355 renderer
->pixel_width
,
356 renderer
->pixel_height
,
358 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
365 draw_polyline(DiaRenderer
*self
,
366 Point
*points
, int num_points
,
369 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
370 ArtVpath
*vpath
, *vpath_dashed
;
376 rgba
= color_to_rgba(renderer
, line_color
);
378 vpath
= art_new (ArtVpath
, num_points
+1);
380 for (i
=0;i
<num_points
;i
++) {
381 dia_transform_coords_double(renderer
->transform
,
382 points
[i
].x
, points
[i
].y
,
384 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
388 vpath
[i
].code
= ART_END
;
392 if (renderer
->dash_enabled
) {
393 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
395 vpath
= vpath_dashed
;
398 svp
= art_svp_vpath_stroke (vpath
,
399 renderer
->join_style
,
401 renderer
->line_width
,
407 art_rgb_svp_alpha (svp
,
409 renderer
->pixel_width
,
410 renderer
->pixel_height
,
412 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
419 draw_polygon(DiaRenderer
*self
,
420 Point
*points
, int num_points
,
423 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
424 ArtVpath
*vpath
, *vpath_dashed
;
430 rgba
= color_to_rgba(renderer
, line_color
);
432 vpath
= art_new (ArtVpath
, num_points
+2);
434 for (i
=0;i
<num_points
;i
++) {
435 dia_transform_coords_double(renderer
->transform
,
436 points
[i
].x
, points
[i
].y
,
438 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
442 dia_transform_coords_double(renderer
->transform
,
443 points
[0].x
, points
[0].y
,
445 vpath
[i
].code
= ART_LINETO
;
448 vpath
[i
+1].code
= ART_END
;
452 if (renderer
->dash_enabled
) {
453 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
455 vpath
= vpath_dashed
;
458 svp
= art_svp_vpath_stroke (vpath
,
459 renderer
->join_style
,
461 renderer
->line_width
,
467 art_rgb_svp_alpha (svp
,
469 renderer
->pixel_width
,
470 renderer
->pixel_height
,
472 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
479 fill_polygon(DiaRenderer
*self
,
480 Point
*points
, int num_points
,
483 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
490 rgba
= color_to_rgba(renderer
, color
);
492 vpath
= art_new (ArtVpath
, num_points
+2);
494 for (i
=0;i
<num_points
;i
++) {
495 dia_transform_coords_double(renderer
->transform
,
496 points
[i
].x
, points
[i
].y
,
498 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
502 dia_transform_coords_double(renderer
->transform
,
503 points
[0].x
, points
[0].y
,
505 vpath
[i
].code
= ART_LINETO
;
508 vpath
[i
+1].code
= ART_END
;
512 svp
= art_svp_from_vpath (vpath
);
516 art_rgb_svp_alpha (svp
,
518 renderer
->pixel_width
,
519 renderer
->pixel_height
,
521 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
528 draw_rect(DiaRenderer
*self
,
529 Point
*ul_corner
, Point
*lr_corner
,
532 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
533 ArtVpath
*vpath
, *vpath_dashed
;
536 double top
, bottom
, left
, right
;
538 dia_transform_coords_double(renderer
->transform
,
539 ul_corner
->x
, ul_corner
->y
, &left
, &top
);
540 dia_transform_coords_double(renderer
->transform
,
541 lr_corner
->x
, lr_corner
->y
, &right
, &bottom
);
543 if ((left
>right
) || (top
>bottom
))
546 rgba
= color_to_rgba(renderer
, color
);
548 vpath
= art_new (ArtVpath
, 6);
550 vpath
[0].code
= ART_MOVETO
;
553 vpath
[1].code
= ART_LINETO
;
556 vpath
[2].code
= ART_LINETO
;
559 vpath
[3].code
= ART_LINETO
;
562 vpath
[4].code
= ART_LINETO
;
565 vpath
[5].code
= ART_END
;
569 if (renderer
->dash_enabled
) {
570 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
572 vpath
= vpath_dashed
;
575 svp
= art_svp_vpath_stroke (vpath
,
576 renderer
->join_style
,
578 renderer
->line_width
,
584 art_rgb_svp_alpha (svp
,
586 renderer
->pixel_width
,
587 renderer
->pixel_height
,
589 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
596 fill_rect(DiaRenderer
*self
,
597 Point
*ul_corner
, Point
*lr_corner
,
600 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
604 double top
, bottom
, left
, right
;
606 dia_transform_coords_double(renderer
->transform
,
607 ul_corner
->x
, ul_corner
->y
, &left
, &top
);
608 dia_transform_coords_double(renderer
->transform
,
609 lr_corner
->x
, lr_corner
->y
, &right
, &bottom
);
611 if ((left
>right
) || (top
>bottom
))
614 rgba
= color_to_rgba(renderer
, color
);
616 vpath
= art_new (ArtVpath
, 6);
618 vpath
[0].code
= ART_MOVETO
;
621 vpath
[1].code
= ART_LINETO
;
624 vpath
[2].code
= ART_LINETO
;
627 vpath
[3].code
= ART_LINETO
;
630 vpath
[4].code
= ART_LINETO
;
633 vpath
[5].code
= ART_END
;
637 svp
= art_svp_from_vpath (vpath
);
641 art_rgb_svp_alpha (svp
,
643 renderer
->pixel_width
,
644 renderer
->pixel_height
,
646 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
653 draw_arc(DiaRenderer
*self
,
655 real width
, real height
,
656 real angle1
, real angle2
,
659 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
660 ArtVpath
*vpath
, *vpath_dashed
;
667 double theta
, dtheta
;
670 width
= dia_transform_length(renderer
->transform
, width
);
671 height
= dia_transform_length(renderer
->transform
, height
);
672 dia_transform_coords_double(renderer
->transform
,
673 center
->x
, center
->y
, &x
, &y
);
675 if ((width
<0.0) || (height
<0.0))
678 dangle
= angle2
-angle1
;
682 /* Over-approximate the circumference */
688 circ
*= dangle
/360.0;
690 #define LEN_PER_SEGMENT 3.0
692 num_points
= circ
/LEN_PER_SEGMENT
;
693 if (num_points
<5) /* Don't be too coarse */
696 rgba
= color_to_rgba(renderer
, line_color
);
698 vpath
= art_new (ArtVpath
, num_points
+1);
700 theta
= M_PI
*angle1
/180.0;
701 dtheta
= (M_PI
*dangle
/180.0)/(num_points
-1);
702 for (i
=0;i
<num_points
;i
++) {
703 vpath
[i
].code
= (i
==0)?ART_MOVETO
:ART_LINETO
;
704 vpath
[i
].x
= x
+ width
/2.0*cos(theta
);
705 vpath
[i
].y
= y
- height
/2.0*sin(theta
);
708 vpath
[i
].code
= ART_END
;
712 if (renderer
->dash_enabled
) {
713 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
715 vpath
= vpath_dashed
;
718 svp
= art_svp_vpath_stroke (vpath
,
719 renderer
->join_style
,
721 renderer
->line_width
,
727 art_rgb_svp_alpha (svp
,
729 renderer
->pixel_width
,
730 renderer
->pixel_height
,
732 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
739 fill_arc(DiaRenderer
*self
,
741 real width
, real height
,
742 real angle1
, real angle2
,
745 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
753 double theta
, dtheta
;
756 width
= dia_transform_length(renderer
->transform
, width
);
757 height
= dia_transform_length(renderer
->transform
, height
);
758 dia_transform_coords_double(renderer
->transform
,
759 center
->x
, center
->y
, &x
, &y
);
761 if ((width
<0.0) || (height
<0.0))
764 dangle
= angle2
-angle1
;
768 /* Over-approximate the circumference */
774 circ
*= dangle
/360.0;
776 #define LEN_PER_SEGMENT 3.0
778 num_points
= circ
/LEN_PER_SEGMENT
;
779 if (num_points
<5) /* Don't be too coarse */
782 rgba
= color_to_rgba(renderer
, color
);
784 vpath
= art_new (ArtVpath
, num_points
+2+1);
786 vpath
[0].code
= ART_MOVETO
;
789 theta
= M_PI
*angle1
/180.0;
790 dtheta
= (M_PI
*dangle
/180.0)/(num_points
-1);
791 for (i
=0;i
<num_points
;i
++) {
792 vpath
[i
+1].code
= ART_LINETO
;
793 vpath
[i
+1].x
= x
+ width
/2.0*cos(theta
);
794 vpath
[i
+1].y
= y
- height
/2.0*sin(theta
);
797 vpath
[i
+1].code
= ART_LINETO
;
800 vpath
[i
+2].code
= ART_END
;
804 svp
= art_svp_from_vpath (vpath
);
808 art_rgb_svp_alpha (svp
,
810 renderer
->pixel_width
,
811 renderer
->pixel_height
,
813 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
820 draw_ellipse(DiaRenderer
*self
,
822 real width
, real height
,
825 draw_arc(self
, center
, width
, height
, 0.0, 360.0, color
);
829 fill_ellipse(DiaRenderer
*self
,
831 real width
, real height
,
834 fill_arc(self
, center
, width
, height
, 0.0, 360.0, color
);
838 draw_bezier(DiaRenderer
*self
,
843 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
844 ArtVpath
*vpath
, *vpath_dashed
;
851 rgba
= color_to_rgba(renderer
, line_color
);
853 bpath
= art_new (ArtBpath
, numpoints
+1);
855 for (i
=0;i
<numpoints
;i
++) {
856 switch(points
[i
].type
) {
858 dia_transform_coords_double(renderer
->transform
,
859 points
[i
].p1
.x
, points
[i
].p1
.y
,
861 bpath
[i
].code
= ART_MOVETO
;
866 dia_transform_coords_double(renderer
->transform
,
867 points
[i
].p1
.x
, points
[i
].p1
.y
,
869 bpath
[i
].code
= ART_LINETO
;
874 bpath
[i
].code
= ART_CURVETO
;
875 dia_transform_coords_double(renderer
->transform
,
876 points
[i
].p1
.x
, points
[i
].p1
.y
,
880 dia_transform_coords_double(renderer
->transform
,
881 points
[i
].p2
.x
, points
[i
].p2
.y
,
885 dia_transform_coords_double(renderer
->transform
,
886 points
[i
].p3
.x
, points
[i
].p3
.y
,
893 bpath
[i
].code
= ART_END
;
897 vpath
= art_bez_path_to_vec(bpath
, 0.25);
900 if (renderer
->dash_enabled
) {
901 vpath_dashed
= art_vpath_dash(vpath
, &renderer
->dash
);
903 vpath
= vpath_dashed
;
906 svp
= art_svp_vpath_stroke (vpath
,
907 renderer
->join_style
,
909 renderer
->line_width
,
915 art_rgb_svp_alpha (svp
,
917 renderer
->pixel_width
,
918 renderer
->pixel_height
,
920 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
927 fill_bezier(DiaRenderer
*self
,
928 BezPoint
*points
, /* Last point must be same as first point */
932 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
940 rgba
= color_to_rgba(renderer
, color
);
942 bpath
= art_new (ArtBpath
, numpoints
+1);
944 for (i
=0;i
<numpoints
;i
++) {
945 switch(points
[i
].type
) {
947 dia_transform_coords_double(renderer
->transform
,
948 points
[i
].p1
.x
, points
[i
].p1
.y
,
950 bpath
[i
].code
= ART_MOVETO
;
955 dia_transform_coords_double(renderer
->transform
,
956 points
[i
].p1
.x
, points
[i
].p1
.y
,
958 bpath
[i
].code
= ART_LINETO
;
963 bpath
[i
].code
= ART_CURVETO
;
964 dia_transform_coords_double(renderer
->transform
,
965 points
[i
].p1
.x
, points
[i
].p1
.y
,
969 dia_transform_coords_double(renderer
->transform
,
970 points
[i
].p2
.x
, points
[i
].p2
.y
,
974 dia_transform_coords_double(renderer
->transform
,
975 points
[i
].p3
.x
, points
[i
].p3
.y
,
982 bpath
[i
].code
= ART_END
;
986 vpath
= art_bez_path_to_vec(bpath
, 0.25);
989 svp
= art_svp_from_vpath (vpath
);
993 art_rgb_svp_alpha (svp
,
995 renderer
->pixel_width
,
996 renderer
->pixel_height
,
998 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
1001 art_svp_free( svp
);
1005 /* Draw a highlighted version of a string.
1008 draw_highlighted_string(DiaLibartRenderer
*renderer
,
1009 PangoLayout
*layout
,
1016 double top
, bottom
, left
, right
;
1018 pango_layout_get_pixel_size(layout
, &width
, &height
);
1019 dia_transform_coords_double(renderer
->transform
,
1022 right
= left
+width
+6;
1023 bottom
= top
+height
;
1025 if ((left
>right
) || (top
>bottom
))
1028 vpath
= art_new (ArtVpath
, 6);
1030 vpath
[0].code
= ART_MOVETO
;
1033 vpath
[1].code
= ART_LINETO
;
1036 vpath
[2].code
= ART_LINETO
;
1038 vpath
[2].y
= bottom
;
1039 vpath
[3].code
= ART_LINETO
;
1041 vpath
[3].y
= bottom
;
1042 vpath
[4].code
= ART_LINETO
;
1045 vpath
[5].code
= ART_END
;
1049 svp
= art_svp_from_vpath (vpath
);
1053 art_rgb_svp_alpha (svp
,
1055 renderer
->pixel_width
,
1056 renderer
->pixel_height
,
1058 renderer
->rgb_buffer
, renderer
->pixel_width
*3,
1061 art_svp_free( svp
);
1065 draw_text_line(DiaRenderer
*self
, TextLine
*text_line
,
1066 Point
*pos
, Color
*color
)
1068 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
1069 /* Not working with Pango */
1070 guint8
*bitmap
= NULL
;
1073 PangoLayout
* layout
;
1076 double affine
[6], tmpaffine
[6];
1079 gchar
*text
= text_line_get_string(text_line
);
1080 real scale
= dia_transform_length(renderer
->transform
, 1.0);
1082 point_copy(&start_pos
,pos
);
1084 rgba
= color_to_rgba(renderer
, color
);
1086 /* Something's screwed up with the zooming for fonts.
1087 It's like it zooms double. Yet removing some of the zooms
1088 don't seem to work, either.
1091 old_zoom = ddisp->zoom_factor;
1092 ddisp->zoom_factor = ddisp->zoom_factor;
1095 start_pos
.y
-= text_line_get_ascent(text_line
);
1097 dia_transform_coords_double(renderer
->transform
,
1098 start_pos
.x
, start_pos
.y
, &x
, &y
);
1100 layout
= dia_font_build_layout(text
, text_line
->font
,
1101 dia_transform_length(renderer
->transform
,
1102 text_line_get_height(text_line
)) / 20.0);
1104 text_line_adjust_layout_line(text_line
, pango_layout_get_line(layout
, 0),
1107 if (renderer
->highlight_color
!= NULL
) {
1108 draw_highlighted_string(renderer
, layout
, start_pos
.x
, start_pos
.y
, rgba
);
1109 g_object_unref(G_OBJECT(layout
));
1114 ddisp->zoom_factor = old_zoom;
1116 pango_layout_get_pixel_size(layout
, &width
, &height
);
1117 /* Pango doesn't have a 'render to raw bits' function, so we have
1118 * to render based on what other engines are available.
1121 #ifdef HAVE_FREETYPE
1122 /* Freetype version */
1127 rowstride
= 32*((width
+31)/31);
1129 graybitmap
= (guint8
*)g_new0(guint8
, height
*rowstride
);
1131 ftbitmap
.rows
= height
;
1132 ftbitmap
.width
= width
;
1133 ftbitmap
.pitch
= rowstride
;
1134 ftbitmap
.buffer
= graybitmap
;
1135 ftbitmap
.num_grays
= 256;
1136 ftbitmap
.pixel_mode
= ft_pixel_mode_grays
;
1137 ftbitmap
.palette_mode
= 0;
1138 ftbitmap
.palette
= 0;
1139 pango_ft2_render_layout(&ftbitmap
, layout
, 0, 0);
1140 bitmap
= (guint8
*)g_new0(guint8
, height
*rowstride
*DEPTH
);
1141 for (i
= 0; i
< height
; i
++) {
1142 for (j
= 0; j
< width
; j
++) {
1143 bitmap
[DEPTH
*(i
*rowstride
+j
)] = color
->red
*255;
1144 bitmap
[DEPTH
*(i
*rowstride
+j
)+1] = color
->green
*255;
1145 bitmap
[DEPTH
*(i
*rowstride
+j
)+2] = color
->blue
*255;
1146 bitmap
[DEPTH
*(i
*rowstride
+j
)+3] = graybitmap
[i
*rowstride
+j
];
1152 /* gdk does not like 0x0 sized (it does not make much sense with the others as well,
1153 * but they don't complain ;) */
1154 if (width
* height
> 0)
1156 GdkPixmap
*pixmap
= gdk_pixmap_new (NULL
, width
, height
, 24);
1157 GdkGC
*gc
= gdk_gc_new (pixmap
);
1160 rowstride
= 32*((width
+31)/31);
1161 #if 1 /* with 8 bit pixmap we would probably need to set the whole gray palette */
1162 gdk_gc_set_foreground (gc
, &color_gdk_black
);
1163 gdk_gc_set_background (gc
, &color_gdk_white
);
1164 gdk_draw_rectangle (GDK_DRAWABLE (pixmap
), gc
, TRUE
, 0, 0, width
, height
);
1166 gdk_gc_set_foreground (gc
, &color_gdk_white
);
1167 gdk_gc_set_background (gc
, &color_gdk_black
);
1168 gdk_draw_layout (GDK_DRAWABLE (pixmap
), gc
, 0, 0, layout
);
1169 image
= gdk_drawable_get_image (GDK_DRAWABLE (pixmap
), 0, 0, width
, height
);
1170 g_object_unref (G_OBJECT (gc
));
1171 g_object_unref (G_OBJECT (pixmap
));
1172 bitmap
= (guint8
*)g_new0(guint8
, height
*rowstride
*DEPTH
);
1173 for (i
= 0; i
< height
; i
++) {
1174 for (j
= 0; j
< width
; j
++) {
1175 bitmap
[DEPTH
*(i
*rowstride
+j
)] = color
->red
*255;
1176 bitmap
[DEPTH
*(i
*rowstride
+j
)+1] = color
->green
*255;
1177 bitmap
[DEPTH
*(i
*rowstride
+j
)+2] = color
->blue
*255;
1178 bitmap
[DEPTH
*(i
*rowstride
+j
)+3] = gdk_image_get_pixel (image
, j
, i
) & 0xFF;
1181 g_object_unref (G_OBJECT (image
));
1185 /* abuse_layout_object(layout,text); */
1187 g_object_unref(G_OBJECT(layout
));
1189 art_affine_identity(affine
);
1190 art_affine_translate(tmpaffine
, x
, y
);
1191 art_affine_multiply(affine
, affine
, tmpaffine
);
1194 art_rgb_rgba_affine (renderer
->rgb_buffer
,
1196 renderer
->pixel_width
,
1197 renderer
->pixel_height
,
1198 renderer
->pixel_width
* 3,
1204 ART_FILTER_NEAREST
, NULL
);
1211 draw_string (DiaRenderer
*self
,
1213 Point
*pos
, Alignment alignment
,
1216 TextLine
*text_line
= text_line_new(text
, self
->font
, self
->font_height
);
1217 Point realigned_pos
= *pos
;
1218 realigned_pos
.x
-= text_line_get_alignment_adjustment(text_line
, alignment
);
1219 draw_text_line(self
, text_line
, &realigned_pos
, color
);
1223 /* Get the width of the given text in cm */
1225 get_text_width(DiaRenderer
*object
,
1226 const gchar
*text
, int length
)
1228 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (object
);
1230 TextLine
*text_line
;
1232 if (length
!= strlen(text
)) {
1235 /* A couple UTF8-chars: æblegrød ŠŤ Ž Ä™ ć Å„ уфхцÐ?ОПРЄ Ñ” Ò? Њ Ћ Ð? */
1236 ulen
= g_utf8_offset_to_pointer(text
, length
)-text
;
1237 if (!g_utf8_validate(text
, ulen
, NULL
)) {
1238 g_warning ("Text at char %d not valid\n", length
);
1240 othertx
= g_strndup(text
, ulen
);
1241 text_line
= text_line_new(othertx
, object
->font
, object
->font_height
);
1243 text_line
= text_line_new(text
, object
->font
, object
->font_height
);
1245 result
= text_line_get_width(text_line
);
1246 text_line_destroy(text_line
);
1252 draw_image(DiaRenderer
*self
,
1254 real width
, real height
,
1257 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
1259 /* Todo: Handle some kind of clipping! */
1261 if (renderer
->highlight_color
!= NULL
) {
1263 DiaRendererClass
*self_class
= DIA_RENDERER_GET_CLASS (self
);
1268 self_class
->fill_rect(self
, point
, &lr
, renderer
->highlight_color
);
1270 double real_width
, real_height
;
1272 int src_width
, src_height
;
1275 real_width
= dia_transform_length(renderer
->transform
, width
);
1276 real_height
= dia_transform_length(renderer
->transform
, height
);
1277 dia_transform_coords_double(renderer
->transform
,
1278 point
->x
, point
->y
, &x
, &y
);
1280 src_width
= dia_image_width(image
);
1281 src_height
= dia_image_height(image
);
1282 rowstride
= dia_image_rowstride(image
);
1284 affine
[0] = real_width
/(double)src_width
;
1287 affine
[3] = real_height
/(double)src_height
;
1291 if (dia_image_rgba_data(image
)) {
1292 /* If there is an alpha channel, we can use it directly. */
1293 const guint8
*img_data
= dia_image_rgba_data(image
);
1294 art_rgb_rgba_affine(renderer
->rgb_buffer
,
1296 renderer
->pixel_width
,
1297 renderer
->pixel_height
,
1298 renderer
->pixel_width
*3,
1299 img_data
, src_width
, src_height
,
1301 affine
, ART_FILTER_NEAREST
, NULL
);
1302 /* Note that dia_image_rgba_data doesn't copy */
1304 guint8
*img_data
= dia_image_rgb_data(image
);
1306 art_rgb_affine(renderer
->rgb_buffer
,
1308 renderer
->pixel_width
,
1309 renderer
->pixel_height
,
1310 renderer
->pixel_width
*3,
1311 img_data
, src_width
, src_height
,
1313 affine
, ART_FILTER_NEAREST
, NULL
);
1322 draw_object (DiaRenderer
*renderer
, DiaObject
*object
)
1324 if (renderer
->is_interactive
&&
1325 object
->highlight_color
!= NULL
) {
1326 DiaLibartRenderer
*libart_rend
= DIA_LIBART_RENDERER(renderer
);
1327 libart_rend
->highlight_color
= object
->highlight_color
;
1328 object
->ops
->draw(object
, renderer
);
1329 libart_rend
->highlight_color
= NULL
;
1331 object
->ops
->draw(object
, renderer
);
1335 renderer_init (DiaLibartRenderer
*renderer
, gpointer g_class
)
1337 renderer
->rgb_buffer
= NULL
;
1339 renderer
->line_width
= 1.0;
1340 renderer
->cap_style
= ART_PATH_STROKE_CAP_BUTT
;
1341 renderer
->join_style
= ART_PATH_STROKE_JOIN_MITER
;
1343 renderer
->saved_line_style
= LINESTYLE_SOLID
;
1344 renderer
->dash_enabled
= 0;
1345 renderer
->dash_length
= 10;
1346 renderer
->dot_length
= 1;
1348 renderer
->highlight_color
= NULL
;
1350 renderer
->parent_instance
.font
= NULL
;
1353 static void dia_libart_renderer_class_init (DiaLibartRendererClass
*klass
);
1354 static gpointer parent_class
= NULL
;
1357 renderer_finalize (GObject
*object
)
1359 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (object
);
1361 if (renderer
->rgb_buffer
!= NULL
)
1362 g_free(renderer
->rgb_buffer
);
1364 G_OBJECT_CLASS (parent_class
)->finalize (object
);
1368 dia_libart_renderer_get_type (void)
1370 static GType object_type
= 0;
1374 static const GTypeInfo object_info
=
1376 sizeof (DiaLibartRendererClass
),
1377 (GBaseInitFunc
) NULL
,
1378 (GBaseFinalizeFunc
) NULL
,
1379 (GClassInitFunc
) dia_libart_renderer_class_init
,
1380 NULL
, /* class_finalize */
1381 NULL
, /* class_data */
1382 sizeof (DiaLibartRenderer
),
1383 0, /* n_preallocs */
1384 (GInstanceInitFunc
)renderer_init
/* init */
1387 object_type
= g_type_register_static (DIA_TYPE_RENDERER
,
1388 "DiaLibartRenderer",
1396 dia_libart_renderer_class_init (DiaLibartRendererClass
*klass
)
1398 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1399 DiaRendererClass
*renderer_class
= DIA_RENDERER_CLASS (klass
);
1401 parent_class
= g_type_class_peek_parent (klass
);
1403 gobject_class
->finalize
= renderer_finalize
;
1405 /* Here we set the functions that we define for this renderer. */
1406 renderer_class
->get_width_pixels
= get_width_pixels
;
1407 renderer_class
->get_height_pixels
= get_height_pixels
;
1409 renderer_class
->begin_render
= begin_render
;
1410 renderer_class
->end_render
= end_render
;
1412 renderer_class
->set_linewidth
= set_linewidth
;
1413 renderer_class
->set_linecaps
= set_linecaps
;
1414 renderer_class
->set_linejoin
= set_linejoin
;
1415 renderer_class
->set_linestyle
= set_linestyle
;
1416 renderer_class
->set_dashlength
= set_dashlength
;
1417 renderer_class
->set_fillstyle
= set_fillstyle
;
1418 renderer_class
->set_font
= set_font
;
1420 renderer_class
->draw_line
= draw_line
;
1421 renderer_class
->draw_polyline
= draw_polyline
;
1423 renderer_class
->draw_polygon
= draw_polygon
;
1424 renderer_class
->fill_polygon
= fill_polygon
;
1426 renderer_class
->draw_rect
= draw_rect
;
1427 renderer_class
->fill_rect
= fill_rect
;
1429 renderer_class
->draw_arc
= draw_arc
;
1430 renderer_class
->fill_arc
= fill_arc
;
1432 renderer_class
->draw_ellipse
= draw_ellipse
;
1433 renderer_class
->fill_ellipse
= fill_ellipse
;
1435 renderer_class
->draw_bezier
= draw_bezier
;
1436 renderer_class
->fill_bezier
= fill_bezier
;
1438 renderer_class
->draw_string
= draw_string
;
1439 renderer_class
->draw_text_line
= draw_text_line
;
1441 renderer_class
->draw_image
= draw_image
;
1443 renderer_class
->draw_object
= draw_object
;
1445 /* Interactive functions */
1446 renderer_class
->get_text_width
= get_text_width
;