* added GDK_PIXBUF_LIBS in order to create pixbuf.dll
[dia.git] / lib / dialibartrenderer.c
blob235292d6b88e61a30fcd85c56d9e4d85af95a1fa
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.
19 #include <config.h>
21 #include <math.h>
22 #include <string.h> /* strlen */
24 #include "dialibartrenderer.h"
26 #include "message.h"
27 #include "color.h"
28 #include "font.h"
29 #include "intl.h"
30 #include "dia_image.h"
32 #ifdef HAVE_LIBART
34 #ifdef HAVE_FREETYPE
35 #include <pango/pango.h>
36 #include <pango/pangoft2.h>
37 #elif defined G_OS_WIN32
38 /* ugly namespace clashes */
39 #define Rectangle Win32Rectangle
40 #include <pango/pango.h>
41 #include <pango/pangowin32.h>
42 #undef Rectangle
43 #endif
45 #include <libart_lgpl/art_point.h>
46 #include <libart_lgpl/art_misc.h>
47 #include <libart_lgpl/art_affine.h>
48 #include <libart_lgpl/art_svp_vpath.h>
49 #include <libart_lgpl/art_bpath.h>
50 #include <libart_lgpl/art_vpath_bpath.h>
51 #include <libart_lgpl/art_rgb.h>
52 #include <libart_lgpl/art_rgb_svp.h>
53 #include <libart_lgpl/art_rgb_affine.h>
54 #include <libart_lgpl/art_rgb_rgba_affine.h>
55 #include <libart_lgpl/art_rgb_bitmap_affine.h>
56 #include <libart_lgpl/art_filterlevel.h>
58 static inline guint32
59 color_to_abgr(Color *col)
61 int rgba;
63 rgba = 0x0;
64 rgba |= (guint)(0xFF*col->blue) << 16;
65 rgba |= (guint)(0xFF*col->green) << 8;
66 rgba |= (guint)(0xFF*col->red);
68 return rgba;
71 static inline guint32
72 color_to_rgba(Color *col)
74 int rgba;
76 rgba = 0xFF;
77 rgba |= (guint)(0xFF*col->red) << 24;
78 rgba |= (guint)(0xFF*col->green) << 16;
79 rgba |= (guint)(0xFF*col->blue) << 8;
81 return rgba;
84 static int
85 get_width_pixels (DiaRenderer *self)
87 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
89 return renderer->pixel_width;
92 static int
93 get_height_pixels (DiaRenderer *self)
95 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
97 return renderer->pixel_height;
100 static void
101 begin_render(DiaRenderer *self)
103 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
104 #ifdef HAVE_FREETYPE
105 /* pango_ft2_get_context API docs :
106 * ... Use of this function is discouraged, ...
108 * I don't see that at http://developer.gnome.org/doc/API/2.0/pango
109 * -Lars
111 dia_font_push_context(pango_ft2_get_context(10, 10));
112 # define FONT_SCALE (1.0)
113 #elif defined G_OS_WIN32
114 dia_font_push_context(pango_win32_get_context());
115 /* we need to scale but can't as simple as with ft2 */
116 # define FONT_SCALE (1.0 / 22.0)
117 #endif
120 static void
121 end_render(DiaRenderer *self)
123 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
125 dia_font_pop_context();
130 static void
131 set_linewidth(DiaRenderer *self, real linewidth)
132 { /* 0 == hairline **/
133 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
135 renderer->line_width =
136 dia_transform_length(renderer->transform, linewidth);
138 if (renderer->line_width<=0.5)
139 renderer->line_width = 0.5; /* Minimum 0.5 pixel. */
142 static void
143 set_linecaps(DiaRenderer *self, LineCaps mode)
145 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
147 switch(mode) {
148 case LINECAPS_BUTT:
149 renderer->cap_style = ART_PATH_STROKE_CAP_BUTT;
150 break;
151 case LINECAPS_ROUND:
152 renderer->cap_style = ART_PATH_STROKE_CAP_ROUND;
153 break;
154 case LINECAPS_PROJECTING:
155 renderer->cap_style = ART_PATH_STROKE_CAP_SQUARE;
156 break;
160 static void
161 set_linejoin(DiaRenderer *self, LineJoin mode)
163 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
165 switch(mode) {
166 case LINEJOIN_MITER:
167 renderer->cap_style = ART_PATH_STROKE_JOIN_MITER;
168 break;
169 case LINEJOIN_ROUND:
170 renderer->cap_style = ART_PATH_STROKE_JOIN_ROUND;
171 break;
172 case LINEJOIN_BEVEL:
173 renderer->cap_style = ART_PATH_STROKE_JOIN_BEVEL;
174 break;
178 static void
179 set_linestyle(DiaRenderer *self, LineStyle mode)
181 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
182 static double dash[10];
183 double hole_width;
185 renderer->saved_line_style = mode;
186 switch(mode) {
187 case LINESTYLE_SOLID:
188 renderer->dash_enabled = 0;
189 break;
190 case LINESTYLE_DASHED:
191 renderer->dash_enabled = 1;
192 renderer->dash.offset = 0.0;
193 renderer->dash.n_dash = 2;
194 renderer->dash.dash = dash;
195 dash[0] = renderer->dash_length;
196 dash[1] = renderer->dash_length;
197 break;
198 case LINESTYLE_DASH_DOT:
199 renderer->dash_enabled = 1;
200 renderer->dash.offset = 0.0;
201 renderer->dash.n_dash = 4;
202 renderer->dash.dash = dash;
203 hole_width = (renderer->dash_length - renderer->dot_length) / 2.0;
204 if (hole_width<1.0)
205 hole_width = 1.0;
206 dash[0] = renderer->dash_length;
207 dash[1] = hole_width;
208 dash[2] = renderer->dot_length;
209 dash[3] = hole_width;
210 break;
211 case LINESTYLE_DASH_DOT_DOT:
212 renderer->dash_enabled = 1;
213 renderer->dash.offset = 0.0;
214 renderer->dash.n_dash = 6;
215 renderer->dash.dash = dash;
216 hole_width = (renderer->dash_length - 2*renderer->dot_length) / 3;
217 if (hole_width<1.0)
218 hole_width = 1.0;
219 dash[0] = renderer->dash_length;
220 dash[1] = hole_width;
221 dash[2] = renderer->dot_length;
222 dash[3] = hole_width;
223 dash[4] = renderer->dot_length;
224 dash[5] = hole_width;
225 break;
226 case LINESTYLE_DOTTED:
227 renderer->dash_enabled = 1;
228 renderer->dash.offset = 0.0;
229 renderer->dash.n_dash = 2;
230 renderer->dash.dash = dash;
231 dash[0] = renderer->dot_length;
232 dash[1] = renderer->dot_length;
233 break;
237 static void
238 set_dashlength(DiaRenderer *self, real length)
239 { /* dot = 10% of len */
240 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
241 real ddisp_len;
243 ddisp_len =
244 dia_transform_length(renderer->transform, length);
246 renderer->dash_length = ddisp_len;
247 renderer->dot_length = ddisp_len*0.1;
249 if (renderer->dash_length<1.0)
250 renderer->dash_length = 1.0;
251 if (renderer->dash_length>255.0)
252 renderer->dash_length = 255.0;
253 if (renderer->dot_length<1.0)
254 renderer->dot_length = 1.0;
255 if (renderer->dot_length>255.0)
256 renderer->dot_length = 255.0;
257 set_linestyle(self, renderer->saved_line_style);
260 static void
261 set_fillstyle(DiaRenderer *self, FillStyle mode)
263 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
265 switch(mode) {
266 case FILLSTYLE_SOLID:
267 break;
268 default:
269 message_error(_("gdk_renderer: Unsupported fill mode specified!\n"));
273 static void
274 set_font(DiaRenderer *self, DiaFont *font, real height)
276 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
278 renderer->font_height = height * FONT_SCALE;
279 // ddisplay_transform_length(renderer->ddisp, height);
281 if (renderer->font)
282 dia_font_unref(renderer->font);
283 renderer->font = dia_font_ref(font);
286 static void
287 draw_line(DiaRenderer *self,
288 Point *start, Point *end,
289 Color *line_color)
291 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
292 ArtVpath *vpath, *vpath_dashed;
293 ArtSVP *svp;
294 guint32 rgba;
295 double x,y;
297 rgba = color_to_rgba(line_color);
299 vpath = art_new (ArtVpath, 3);
301 dia_transform_coords_double(renderer->transform, start->x, start->y, &x, &y);
302 vpath[0].code = ART_MOVETO;
303 vpath[0].x = x;
304 vpath[0].y = y;
306 dia_transform_coords_double(renderer->transform, end->x, end->y, &x, &y);
307 vpath[1].code = ART_LINETO;
308 vpath[1].x = x;
309 vpath[1].y = y;
311 vpath[2].code = ART_END;
312 vpath[2].x = 0;
313 vpath[2].y = 0;
315 if (renderer->dash_enabled) {
316 vpath_dashed = art_vpath_dash(vpath, &renderer->dash);
317 art_free( vpath );
318 vpath = vpath_dashed;
321 svp = art_svp_vpath_stroke (vpath,
322 renderer->join_style,
323 renderer->cap_style,
324 renderer->line_width,
326 0.25);
328 art_free( vpath );
330 art_rgb_svp_alpha (svp,
331 0, 0,
332 renderer->pixel_width,
333 renderer->pixel_height,
334 rgba,
335 renderer->rgb_buffer, renderer->pixel_width*3,
336 NULL);
338 art_svp_free( svp );
341 static void
342 draw_polyline(DiaRenderer *self,
343 Point *points, int num_points,
344 Color *line_color)
346 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
347 ArtVpath *vpath, *vpath_dashed;
348 ArtSVP *svp;
349 guint32 rgba;
350 double x,y;
351 int i;
353 rgba = color_to_rgba(line_color);
355 vpath = art_new (ArtVpath, num_points+1);
357 for (i=0;i<num_points;i++) {
358 dia_transform_coords_double(renderer->transform,
359 points[i].x, points[i].y,
360 &x, &y);
361 vpath[i].code = (i==0)?ART_MOVETO:ART_LINETO;
362 vpath[i].x = x;
363 vpath[i].y = y;
365 vpath[i].code = ART_END;
366 vpath[i].x = 0;
367 vpath[i].y = 0;
369 if (renderer->dash_enabled) {
370 vpath_dashed = art_vpath_dash(vpath, &renderer->dash);
371 art_free( vpath );
372 vpath = vpath_dashed;
375 svp = art_svp_vpath_stroke (vpath,
376 renderer->join_style,
377 renderer->cap_style,
378 renderer->line_width,
380 0.25);
382 art_free( vpath );
384 art_rgb_svp_alpha (svp,
385 0, 0,
386 renderer->pixel_width,
387 renderer->pixel_height,
388 rgba,
389 renderer->rgb_buffer, renderer->pixel_width*3,
390 NULL);
392 art_svp_free( svp );
395 static void
396 draw_polygon(DiaRenderer *self,
397 Point *points, int num_points,
398 Color *line_color)
400 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
401 ArtVpath *vpath, *vpath_dashed;
402 ArtSVP *svp;
403 guint32 rgba;
404 double x,y;
405 int i;
407 rgba = color_to_rgba(line_color);
409 vpath = art_new (ArtVpath, num_points+2);
411 for (i=0;i<num_points;i++) {
412 dia_transform_coords_double(renderer->transform,
413 points[i].x, points[i].y,
414 &x, &y);
415 vpath[i].code = (i==0)?ART_MOVETO:ART_LINETO;
416 vpath[i].x = x;
417 vpath[i].y = y;
419 dia_transform_coords_double(renderer->transform,
420 points[0].x, points[0].y,
421 &x, &y);
422 vpath[i].code = ART_LINETO;
423 vpath[i].x = x;
424 vpath[i].y = y;
425 vpath[i+1].code = ART_END;
426 vpath[i+1].x = 0;
427 vpath[i+1].y = 0;
429 if (renderer->dash_enabled) {
430 vpath_dashed = art_vpath_dash(vpath, &renderer->dash);
431 art_free( vpath );
432 vpath = vpath_dashed;
435 svp = art_svp_vpath_stroke (vpath,
436 renderer->join_style,
437 renderer->cap_style,
438 renderer->line_width,
440 0.25);
442 art_free( vpath );
444 art_rgb_svp_alpha (svp,
445 0, 0,
446 renderer->pixel_width,
447 renderer->pixel_height,
448 rgba,
449 renderer->rgb_buffer, renderer->pixel_width*3,
450 NULL);
452 art_svp_free( svp );
455 static void
456 fill_polygon(DiaRenderer *self,
457 Point *points, int num_points,
458 Color *color)
460 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
461 ArtVpath *vpath;
462 ArtSVP *svp;
463 guint32 rgba;
464 double x,y;
465 int i;
467 rgba = color_to_rgba(color);
469 vpath = art_new (ArtVpath, num_points+2);
471 for (i=0;i<num_points;i++) {
472 dia_transform_coords_double(renderer->transform,
473 points[i].x, points[i].y,
474 &x, &y);
475 vpath[i].code = (i==0)?ART_MOVETO:ART_LINETO;
476 vpath[i].x = x;
477 vpath[i].y = y;
479 dia_transform_coords_double(renderer->transform,
480 points[0].x, points[0].y,
481 &x, &y);
482 vpath[i].code = ART_LINETO;
483 vpath[i].x = x;
484 vpath[i].y = y;
485 vpath[i+1].code = ART_END;
486 vpath[i+1].x = 0;
487 vpath[i+1].y = 0;
489 svp = art_svp_from_vpath (vpath);
491 art_free( vpath );
493 art_rgb_svp_alpha (svp,
494 0, 0,
495 renderer->pixel_width,
496 renderer->pixel_height,
497 rgba,
498 renderer->rgb_buffer, renderer->pixel_width*3,
499 NULL);
501 art_svp_free( svp );
504 static void
505 draw_rect(DiaRenderer *self,
506 Point *ul_corner, Point *lr_corner,
507 Color *color)
509 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
510 ArtVpath *vpath, *vpath_dashed;
511 ArtSVP *svp;
512 guint32 rgba;
513 double top, bottom, left, right;
515 dia_transform_coords_double(renderer->transform,
516 ul_corner->x, ul_corner->y, &left, &top);
517 dia_transform_coords_double(renderer->transform,
518 lr_corner->x, lr_corner->y, &right, &bottom);
520 if ((left>right) || (top>bottom))
521 return;
523 rgba = color_to_rgba(color);
525 vpath = art_new (ArtVpath, 6);
527 vpath[0].code = ART_MOVETO;
528 vpath[0].x = left;
529 vpath[0].y = top;
530 vpath[1].code = ART_LINETO;
531 vpath[1].x = right;
532 vpath[1].y = top;
533 vpath[2].code = ART_LINETO;
534 vpath[2].x = right;
535 vpath[2].y = bottom;
536 vpath[3].code = ART_LINETO;
537 vpath[3].x = left;
538 vpath[3].y = bottom;
539 vpath[4].code = ART_LINETO;
540 vpath[4].x = left;
541 vpath[4].y = top;
542 vpath[5].code = ART_END;
543 vpath[5].x = 0;
544 vpath[5].y = 0;
546 if (renderer->dash_enabled) {
547 vpath_dashed = art_vpath_dash(vpath, &renderer->dash);
548 art_free( vpath );
549 vpath = vpath_dashed;
552 svp = art_svp_vpath_stroke (vpath,
553 renderer->join_style,
554 renderer->cap_style,
555 renderer->line_width,
557 0.25);
559 art_free( vpath );
561 art_rgb_svp_alpha (svp,
562 0, 0,
563 renderer->pixel_width,
564 renderer->pixel_height,
565 rgba,
566 renderer->rgb_buffer, renderer->pixel_width*3,
567 NULL);
569 art_svp_free( svp );
572 static void
573 fill_rect(DiaRenderer *self,
574 Point *ul_corner, Point *lr_corner,
575 Color *color)
577 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
578 ArtVpath *vpath;
579 ArtSVP *svp;
580 guint32 rgba;
581 double top, bottom, left, right;
583 dia_transform_coords_double(renderer->transform,
584 ul_corner->x, ul_corner->y, &left, &top);
585 dia_transform_coords_double(renderer->transform,
586 lr_corner->x, lr_corner->y, &right, &bottom);
588 if ((left>right) || (top>bottom))
589 return;
591 rgba = color_to_rgba(color);
593 vpath = art_new (ArtVpath, 6);
595 vpath[0].code = ART_MOVETO;
596 vpath[0].x = left;
597 vpath[0].y = top;
598 vpath[1].code = ART_LINETO;
599 vpath[1].x = right;
600 vpath[1].y = top;
601 vpath[2].code = ART_LINETO;
602 vpath[2].x = right;
603 vpath[2].y = bottom;
604 vpath[3].code = ART_LINETO;
605 vpath[3].x = left;
606 vpath[3].y = bottom;
607 vpath[4].code = ART_LINETO;
608 vpath[4].x = left;
609 vpath[4].y = top;
610 vpath[5].code = ART_END;
611 vpath[5].x = 0;
612 vpath[5].y = 0;
614 svp = art_svp_from_vpath (vpath);
616 art_free( vpath );
618 art_rgb_svp_alpha (svp,
619 0, 0,
620 renderer->pixel_width,
621 renderer->pixel_height,
622 rgba,
623 renderer->rgb_buffer, renderer->pixel_width*3,
624 NULL);
626 art_svp_free( svp );
629 static void
630 draw_arc(DiaRenderer *self,
631 Point *center,
632 real width, real height,
633 real angle1, real angle2,
634 Color *line_color)
636 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
637 ArtVpath *vpath, *vpath_dashed;
638 ArtSVP *svp;
639 guint32 rgba;
640 real dangle;
641 real circ;
642 double x,y;
643 int num_points;
644 double theta, dtheta;
645 int i;
647 width = dia_transform_length(renderer->transform, width);
648 height = dia_transform_length(renderer->transform, height);
649 dia_transform_coords_double(renderer->transform,
650 center->x, center->y, &x, &y);
652 if ((width<0.0) || (height<0.0))
653 return;
655 dangle = angle2-angle1;
656 if (dangle<0)
657 dangle += 360.0;
659 /* Over-approximate the circumference */
660 if (width>height)
661 circ = M_PI*width;
662 else
663 circ = M_PI*height;
665 circ *= dangle/360.0;
667 #define LEN_PER_SEGMENT 3.0
669 num_points = circ/LEN_PER_SEGMENT;
670 if (num_points<5) /* Don't be too coarse */
671 num_points = 5;
673 rgba = color_to_rgba(line_color);
675 vpath = art_new (ArtVpath, num_points+1);
677 theta = M_PI*angle1/180.0;
678 dtheta = (M_PI*dangle/180.0)/(num_points-1);
679 for (i=0;i<num_points;i++) {
680 vpath[i].code = (i==0)?ART_MOVETO:ART_LINETO;
681 vpath[i].x = x + width/2.0*cos(theta);
682 vpath[i].y = y - height/2.0*sin(theta);
683 theta += dtheta;
685 vpath[i].code = ART_END;
686 vpath[i].x = 0;
687 vpath[i].y = 0;
689 if (renderer->dash_enabled) {
690 vpath_dashed = art_vpath_dash(vpath, &renderer->dash);
691 art_free( vpath );
692 vpath = vpath_dashed;
695 svp = art_svp_vpath_stroke (vpath,
696 renderer->join_style,
697 renderer->cap_style,
698 renderer->line_width,
700 0.25);
702 art_free( vpath );
704 art_rgb_svp_alpha (svp,
705 0, 0,
706 renderer->pixel_width,
707 renderer->pixel_height,
708 rgba,
709 renderer->rgb_buffer, renderer->pixel_width*3,
710 NULL);
712 art_svp_free( svp );
715 static void
716 fill_arc(DiaRenderer *self,
717 Point *center,
718 real width, real height,
719 real angle1, real angle2,
720 Color *color)
722 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
723 ArtVpath *vpath;
724 ArtSVP *svp;
725 guint32 rgba;
726 real dangle;
727 real circ;
728 double x,y;
729 int num_points;
730 double theta, dtheta;
731 int i;
733 width = dia_transform_length(renderer->transform, width);
734 height = dia_transform_length(renderer->transform, height);
735 dia_transform_coords_double(renderer->transform,
736 center->x, center->y, &x, &y);
738 if ((width<0.0) || (height<0.0))
739 return;
741 dangle = angle2-angle1;
742 if (dangle<0)
743 dangle += 360.0;
745 /* Over-approximate the circumference */
746 if (width>height)
747 circ = M_PI*width;
748 else
749 circ = M_PI*height;
751 circ *= dangle/360.0;
753 #define LEN_PER_SEGMENT 3.0
755 num_points = circ/LEN_PER_SEGMENT;
756 if (num_points<5) /* Don't be too coarse */
757 num_points = 5;
759 rgba = color_to_rgba(color);
761 vpath = art_new (ArtVpath, num_points+2+1);
763 vpath[0].code = ART_MOVETO;
764 vpath[0].x = x;
765 vpath[0].y = y;
766 theta = M_PI*angle1/180.0;
767 dtheta = (M_PI*dangle/180.0)/(num_points-1);
768 for (i=0;i<num_points;i++) {
769 vpath[i+1].code = ART_LINETO;
770 vpath[i+1].x = x + width/2.0*cos(theta);
771 vpath[i+1].y = y - height/2.0*sin(theta);
772 theta += dtheta;
774 vpath[i+1].code = ART_LINETO;
775 vpath[i+1].x = x;
776 vpath[i+1].y = y;
777 vpath[i+2].code = ART_END;
778 vpath[i+2].x = 0;
779 vpath[i+2].y = 0;
781 svp = art_svp_from_vpath (vpath);
783 art_free( vpath );
785 art_rgb_svp_alpha (svp,
786 0, 0,
787 renderer->pixel_width,
788 renderer->pixel_height,
789 rgba,
790 renderer->rgb_buffer, renderer->pixel_width*3,
791 NULL);
793 art_svp_free( svp );
796 static void
797 draw_ellipse(DiaRenderer *self,
798 Point *center,
799 real width, real height,
800 Color *color)
802 draw_arc(self, center, width, height, 0.0, 360.0, color);
805 static void
806 fill_ellipse(DiaRenderer *self,
807 Point *center,
808 real width, real height,
809 Color *color)
811 fill_arc(self, center, width, height, 0.0, 360.0, color);
814 static void
815 draw_bezier(DiaRenderer *self,
816 BezPoint *points,
817 int numpoints,
818 Color *line_color)
820 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
821 ArtVpath *vpath, *vpath_dashed;
822 ArtBpath *bpath;
823 ArtSVP *svp;
824 guint32 rgba;
825 double x,y;
826 int i;
828 rgba = color_to_rgba(line_color);
830 bpath = art_new (ArtBpath, numpoints+1);
832 for (i=0;i<numpoints;i++) {
833 switch(points[i].type) {
834 case BEZ_MOVE_TO:
835 dia_transform_coords_double(renderer->transform,
836 points[i].p1.x, points[i].p1.y,
837 &x, &y);
838 bpath[i].code = ART_MOVETO;
839 bpath[i].x3 = x;
840 bpath[i].y3 = y;
841 break;
842 case BEZ_LINE_TO:
843 dia_transform_coords_double(renderer->transform,
844 points[i].p1.x, points[i].p1.y,
845 &x, &y);
846 bpath[i].code = ART_LINETO;
847 bpath[i].x3 = x;
848 bpath[i].y3 = y;
849 break;
850 case BEZ_CURVE_TO:
851 bpath[i].code = ART_CURVETO;
852 dia_transform_coords_double(renderer->transform,
853 points[i].p1.x, points[i].p1.y,
854 &x, &y);
855 bpath[i].x1 = x;
856 bpath[i].y1 = y;
857 dia_transform_coords_double(renderer->transform,
858 points[i].p2.x, points[i].p2.y,
859 &x, &y);
860 bpath[i].x2 = x;
861 bpath[i].y2 = y;
862 dia_transform_coords_double(renderer->transform,
863 points[i].p3.x, points[i].p3.y,
864 &x, &y);
865 bpath[i].x3 = x;
866 bpath[i].y3 = y;
867 break;
870 bpath[i].code = ART_END;
871 bpath[i].x1 = 0;
872 bpath[i].y1 = 0;
874 vpath = art_bez_path_to_vec(bpath, 0.25);
875 art_free(bpath);
877 if (renderer->dash_enabled) {
878 vpath_dashed = art_vpath_dash(vpath, &renderer->dash);
879 art_free( vpath );
880 vpath = vpath_dashed;
883 svp = art_svp_vpath_stroke (vpath,
884 renderer->join_style,
885 renderer->cap_style,
886 renderer->line_width,
888 0.25);
890 art_free( vpath );
892 art_rgb_svp_alpha (svp,
893 0, 0,
894 renderer->pixel_width,
895 renderer->pixel_height,
896 rgba,
897 renderer->rgb_buffer, renderer->pixel_width*3,
898 NULL);
900 art_svp_free( svp );
903 static void
904 fill_bezier(DiaRenderer *self,
905 BezPoint *points, /* Last point must be same as first point */
906 int numpoints,
907 Color *color)
909 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
910 ArtVpath *vpath;
911 ArtBpath *bpath;
912 ArtSVP *svp;
913 guint32 rgba;
914 double x,y;
915 int i;
917 rgba = color_to_rgba(color);
919 bpath = art_new (ArtBpath, numpoints+1);
921 for (i=0;i<numpoints;i++) {
922 switch(points[i].type) {
923 case BEZ_MOVE_TO:
924 dia_transform_coords_double(renderer->transform,
925 points[i].p1.x, points[i].p1.y,
926 &x, &y);
927 bpath[i].code = ART_MOVETO;
928 bpath[i].x3 = x;
929 bpath[i].y3 = y;
930 break;
931 case BEZ_LINE_TO:
932 dia_transform_coords_double(renderer->transform,
933 points[i].p1.x, points[i].p1.y,
934 &x, &y);
935 bpath[i].code = ART_LINETO;
936 bpath[i].x3 = x;
937 bpath[i].y3 = y;
938 break;
939 case BEZ_CURVE_TO:
940 bpath[i].code = ART_CURVETO;
941 dia_transform_coords_double(renderer->transform,
942 points[i].p1.x, points[i].p1.y,
943 &x, &y);
944 bpath[i].x1 = x;
945 bpath[i].y1 = y;
946 dia_transform_coords_double(renderer->transform,
947 points[i].p2.x, points[i].p2.y,
948 &x, &y);
949 bpath[i].x2 = x;
950 bpath[i].y2 = y;
951 dia_transform_coords_double(renderer->transform,
952 points[i].p3.x, points[i].p3.y,
953 &x, &y);
954 bpath[i].x3 = x;
955 bpath[i].y3 = y;
956 break;
959 bpath[i].code = ART_END;
960 bpath[i].x1 = 0;
961 bpath[i].y1 = 0;
963 vpath = art_bez_path_to_vec(bpath, 0.25);
964 art_free(bpath);
966 svp = art_svp_from_vpath (vpath);
968 art_free( vpath );
970 art_rgb_svp_alpha (svp,
971 0, 0,
972 renderer->pixel_width,
973 renderer->pixel_height,
974 rgba,
975 renderer->rgb_buffer, renderer->pixel_width*3,
976 NULL);
978 art_svp_free( svp );
982 static void
983 draw_string (DiaRenderer *self,
984 const gchar *text,
985 Point *pos, Alignment alignment,
986 Color *color)
988 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
989 /* Not working with Pango */
990 guint8 *bitmap = NULL;
991 double x,y;
992 Point start_pos;
993 PangoLayout* layout;
994 int width, height;
995 int i, j;
996 int iwidth;
997 int len;
998 double affine[6], tmpaffine[6];
999 double xpos, ypos;
1000 guint32 rgba;
1001 int rowstride;
1002 double zoom;
1003 double font_height;
1005 point_copy(&start_pos,pos);
1007 /* Something's screwed up with the zooming for fonts.
1008 It's like it zooms double. Yet removing some of the zooms
1009 don't seem to work, either.
1012 old_zoom = ddisp->zoom_factor;
1013 ddisp->zoom_factor = ddisp->zoom_factor;
1015 switch (alignment) {
1016 case ALIGN_LEFT:
1017 break;
1018 case ALIGN_CENTER:
1019 start_pos.x -= dia_font_scaled_string_width(
1020 text, renderer->font,
1021 renderer->font_height,
1022 dia_transform_length(renderer->transform, 1.0))/2;
1023 break;
1024 case ALIGN_RIGHT:
1025 start_pos.x -= dia_font_scaled_string_width(
1026 text, renderer->font,
1027 renderer->font_height,
1028 dia_transform_length(renderer->transform, 1.0));
1029 break;
1032 font_height = dia_transform_length(renderer->transform, renderer->font_height);
1034 start_pos.y -= dia_font_scaled_ascent(text, renderer->font,
1035 renderer->font_height,
1036 dia_transform_length(renderer->transform, 1.0));
1037 dia_transform_coords_double(renderer->transform,
1038 start_pos.x, start_pos.y, &x, &y);
1040 layout = dia_font_scaled_build_layout(
1041 text, renderer->font, renderer->font_height,
1042 dia_transform_length(renderer->transform, 1.0));
1044 ddisp->zoom_factor = old_zoom;
1047 pango_layout_get_pixel_size(layout, &width, &height);
1048 /* Pango doesn't have a 'render to raw bits' function, so we have
1049 * to render based on what other engines are available.
1051 #define DEPTH 4
1052 #ifdef HAVE_FREETYPE
1053 /* Freetype version */
1055 FT_Bitmap ftbitmap;
1056 guint8 *graybitmap;
1057 FT_Face *face;
1058 PangoFont *font;
1060 rowstride = 32*((width+31)/31);
1062 font = pango_context_load_font(pango_ft2_get_context(10, 10),
1063 renderer->font->pfd);
1064 face = pango_ft2_font_get_face(font);
1066 graybitmap = (guint8*)g_new0(guint8, height*rowstride);
1068 ftbitmap.rows = height;
1069 ftbitmap.width = width;
1070 ftbitmap.pitch = rowstride;
1071 ftbitmap.buffer = graybitmap;
1072 ftbitmap.num_grays = 256;
1073 ftbitmap.pixel_mode = ft_pixel_mode_grays;
1074 ftbitmap.palette_mode = 0;
1075 ftbitmap.palette = 0;
1076 pango_ft2_render_layout(&ftbitmap, layout, 0, 0);
1077 bitmap = (guint8*)g_new0(guint8, height*rowstride*DEPTH);
1078 for (i = 0; i < height; i++) {
1079 for (j = 0; j < width; j++) {
1080 bitmap[DEPTH*(i*rowstride+j)] = color->red;
1081 bitmap[DEPTH*(i*rowstride+j)+1] = color->green;
1082 bitmap[DEPTH*(i*rowstride+j)+2] = color->blue;
1083 bitmap[DEPTH*(i*rowstride+j)+3] = graybitmap[i*rowstride+j];
1085 // bitmap[4*i+3] = graybitmap[i];
1087 g_free(graybitmap);
1089 #elif defined G_OS_WIN32 && defined PANGO_WIN32_FUTURE
1090 /* duplicating from above, please let extending Pango be allowed, bug 94791 */
1092 PangoBitmap graybitmap;
1093 rowstride = 32*((width+31)/31);
1095 graybitmap.rows = height;
1096 graybitmap.width = width;
1097 graybitmap.pitch = rowstride;
1098 graybitmap.buffer = (guint8*)g_new0(guint8, height*rowstride);
1099 graybitmap.num_grays = 256;
1100 g_print("Rendering %s onto bitmap of size %dx%d row %d\n", text, width, height, rowstride);
1101 pango_win32_render_layout_to_bitmap(&graybitmap, layout, 0, 0);
1102 bitmap = (guint8*)g_new0(guint8, height*rowstride*DEPTH);
1103 for (i = 0; i < height; i++) {
1104 for (j = 0; j < width; j++) {
1105 bitmap[DEPTH*(i*rowstride+j)] = color->red;
1106 bitmap[DEPTH*(i*rowstride+j)+1] = color->green;
1107 bitmap[DEPTH*(i*rowstride+j)+2] = color->blue;
1108 bitmap[DEPTH*(i*rowstride+j)+3] = graybitmap.buffer[i*rowstride+j];
1111 g_free(graybitmap.buffer);
1113 #else
1115 static int warned_no_text = 0;
1116 if (!warned_no_text) {
1117 message_warning(_("This Dia version is compiled without libart/text support."));
1118 warned_no_text = 1;
1121 #endif
1123 /* abuse_layout_object(layout,text); */
1125 g_object_unref(G_OBJECT(layout));
1127 rgba = color_to_rgba(color);
1129 art_affine_identity(affine);
1130 art_affine_translate(tmpaffine, x, y);
1131 art_affine_multiply(affine, affine, tmpaffine);
1133 if (bitmap != NULL)
1134 art_rgb_rgba_affine (renderer->rgb_buffer,
1135 0, 0,
1136 renderer->pixel_width,
1137 renderer->pixel_height,
1138 renderer->pixel_width * 3,
1139 bitmap,
1140 width,
1141 height,
1142 rowstride*DEPTH,
1143 //rgba,
1144 affine,
1145 ART_FILTER_NEAREST, NULL);
1147 g_free(bitmap);
1148 #undef DEPTH
1151 static void
1152 draw_image(DiaRenderer *self,
1153 Point *point,
1154 real width, real height,
1155 DiaImage image)
1157 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (self);
1158 double real_width, real_height;
1159 double x,y;
1160 int src_width, src_height;
1161 guint8 *img_data;
1162 guint8 *img_mask;
1163 double affine[6];
1164 int i,j;
1165 int rowstride;
1167 /* Todo: Handle some kind of clipping! */
1169 real_width = dia_transform_length(renderer->transform, width);
1170 real_height = dia_transform_length(renderer->transform, height);
1171 dia_transform_coords_double(renderer->transform,
1172 point->x, point->y, &x, &y);
1174 src_width = dia_image_width(image);
1175 src_height = dia_image_height(image);
1176 rowstride = dia_image_rowstride(image);
1178 affine[0] = real_width/(double)src_width;
1179 affine[1] = 0;
1180 affine[2] = 0;
1181 affine[3] = real_height/(double)src_height;
1182 affine[4] = x;
1183 affine[5] = y;
1185 img_data = dia_image_rgba_data(image);
1187 if (img_data != NULL) {
1188 /* If there is an alpha channel, we can use it directly. */
1189 art_rgb_rgba_affine(renderer->rgb_buffer,
1190 0, 0,
1191 renderer->pixel_width,
1192 renderer->pixel_height,
1193 renderer->pixel_width*3,
1194 img_data, src_width, src_height,
1195 rowstride,
1196 affine, ART_FILTER_NEAREST, NULL);
1197 /* Note that dia_image_rgba_data doesn't copy */
1198 } else {
1199 img_data = dia_image_rgb_data(image);
1201 art_rgb_affine(renderer->rgb_buffer,
1202 0, 0,
1203 renderer->pixel_width,
1204 renderer->pixel_height,
1205 renderer->pixel_width*3,
1206 img_data, src_width, src_height,
1207 rowstride,
1208 affine, ART_FILTER_NEAREST, NULL);
1210 g_free(img_data);
1215 static void
1216 renderer_init (DiaLibartRenderer *renderer, gpointer g_class)
1218 renderer->rgb_buffer = NULL;
1220 renderer->line_width = 1.0;
1221 renderer->cap_style = GDK_CAP_BUTT;
1222 renderer->join_style = GDK_JOIN_MITER;
1224 renderer->saved_line_style = LINESTYLE_SOLID;
1225 renderer->dash_enabled = 0;
1226 renderer->dash_length = 10;
1227 renderer->dot_length = 1;
1229 renderer->font = NULL;
1232 static void dia_libart_renderer_class_init (DiaLibartRendererClass *klass);
1233 static gpointer parent_class = NULL;
1235 static void
1236 renderer_finalize (GObject *object)
1238 DiaLibartRenderer *renderer = DIA_LIBART_RENDERER (object);
1240 if (renderer->rgb_buffer != NULL)
1241 g_free(renderer->rgb_buffer);
1243 if (renderer->font)
1244 dia_font_unref(renderer->font);
1246 G_OBJECT_CLASS (parent_class)->finalize (object);
1249 GType
1250 dia_libart_renderer_get_type (void)
1252 static GType object_type = 0;
1254 if (!object_type)
1256 static const GTypeInfo object_info =
1258 sizeof (DiaLibartRendererClass),
1259 (GBaseInitFunc) NULL,
1260 (GBaseFinalizeFunc) NULL,
1261 (GClassInitFunc) dia_libart_renderer_class_init,
1262 NULL, /* class_finalize */
1263 NULL, /* class_data */
1264 sizeof (DiaLibartRenderer),
1265 0, /* n_preallocs */
1266 (GInstanceInitFunc)renderer_init /* init */
1269 object_type = g_type_register_static (DIA_TYPE_RENDERER,
1270 "DiaLibartRenderer",
1271 &object_info, 0);
1274 return object_type;
1277 static void
1278 dia_libart_renderer_class_init (DiaLibartRendererClass *klass)
1280 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1281 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
1283 /* Here we set the functions that we define for this renderer. */
1284 renderer_class->get_width_pixels = get_width_pixels;
1285 renderer_class->get_height_pixels = get_height_pixels;
1287 renderer_class->begin_render = begin_render;
1288 renderer_class->end_render = end_render;
1290 renderer_class->set_linewidth = set_linewidth;
1291 renderer_class->set_linecaps = set_linecaps;
1292 renderer_class->set_linejoin = set_linejoin;
1293 renderer_class->set_linestyle = set_linestyle;
1294 renderer_class->set_dashlength = set_dashlength;
1295 renderer_class->set_fillstyle = set_fillstyle;
1296 renderer_class->set_font = set_font;
1298 renderer_class->draw_line = draw_line;
1299 renderer_class->draw_polyline = draw_polyline;
1301 renderer_class->draw_polygon = draw_polygon;
1302 renderer_class->fill_polygon = fill_polygon;
1304 renderer_class->draw_rect = draw_rect;
1305 renderer_class->fill_rect = fill_rect;
1307 renderer_class->draw_arc = draw_arc;
1308 renderer_class->fill_arc = fill_arc;
1310 renderer_class->draw_ellipse = draw_ellipse;
1311 renderer_class->fill_ellipse = fill_ellipse;
1313 renderer_class->draw_bezier = draw_bezier;
1314 renderer_class->fill_bezier = fill_bezier;
1316 renderer_class->draw_string = draw_string;
1318 renderer_class->draw_image = draw_image;
1321 #endif