Signal patch
[dia.git] / lib / diagdkrenderer.c
blob51d25d649aaeee199a790a8eb18e13607076e95f
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * diagdkrenderer.c - refactoring of the render to gdk facility
5 * Copyright (C) 2002 Hans Breuer
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <config.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <gdk/gdk.h>
29 #define PANGO_ENABLE_ENGINE
30 #include <pango/pango-engine.h>
31 #include <pango/pango.h>
33 #include "diagdkrenderer.h"
34 #include "dia_image.h"
35 #include "message.h"
36 #include "color.h"
37 #include "font.h"
38 #include "text.h"
40 #include "time.h"
42 #ifdef HAVE_FREETYPE
43 #include <pango/pango.h>
44 #include <pango/pangoft2.h>
45 #endif
47 static int get_width_pixels (DiaRenderer *);
48 static int get_height_pixels (DiaRenderer *);
50 static void begin_render (DiaRenderer *);
51 static void end_render (DiaRenderer *);
53 static void set_linewidth (DiaRenderer *renderer, real linewidth);
54 static void set_linecaps (DiaRenderer *renderer, LineCaps mode);
55 static void set_linejoin (DiaRenderer *renderer, LineJoin mode);
56 static void set_linestyle (DiaRenderer *renderer, LineStyle mode);
57 static void set_dashlength (DiaRenderer *renderer, real length);
58 static void set_fillstyle (DiaRenderer *renderer, FillStyle mode);
60 static void draw_line (DiaRenderer *renderer,
61 Point *start, Point *end,
62 Color *color);
63 static void fill_polygon (DiaRenderer *renderer,
64 Point *points, int num_points,
65 Color *color);
66 static void draw_arc (DiaRenderer *renderer,
67 Point *center,
68 real width, real height,
69 real angle1, real angle2,
70 Color *color);
71 static void fill_arc (DiaRenderer *renderer,
72 Point *center,
73 real width, real height,
74 real angle1, real angle2,
75 Color *color);
76 static void draw_ellipse (DiaRenderer *renderer,
77 Point *center,
78 real width, real height,
79 Color *color);
80 static void fill_ellipse (DiaRenderer *renderer,
81 Point *center,
82 real width, real height,
83 Color *color);
84 static void draw_string (DiaRenderer *renderer,
85 const gchar *text,
86 Point *pos,
87 Alignment alignment,
88 Color *color);
89 static void draw_text (DiaRenderer *renderer,
90 Text *text);
91 static void draw_image (DiaRenderer *renderer,
92 Point *point,
93 real width, real height,
94 DiaImage image);
96 static void draw_rect (DiaRenderer *renderer,
97 Point *ul_corner, Point *lr_corner,
98 Color *color);
99 static void fill_rect (DiaRenderer *renderer,
100 Point *ul_corner, Point *lr_corner,
101 Color *color);
102 static void draw_fill_rect (DiaGdkRenderer *renderer,
103 Point *ul_corner, Point *lr_corner,
104 Color *color, gboolean fill);
105 static void draw_polyline (DiaRenderer *renderer,
106 Point *points, int num_points,
107 Color *color);
108 static void draw_polygon (DiaRenderer *renderer,
109 Point *points, int num_points,
110 Color *color);
111 static void draw_object (DiaRenderer *renderer, DiaObject *object);
113 static real get_text_width (DiaRenderer *renderer,
114 const gchar *text, int length);
116 static void dia_gdk_renderer_class_init (DiaGdkRendererClass *klass);
117 static void renderer_init (DiaGdkRenderer *renderer, void*);
119 static gpointer parent_class = NULL;
121 /** Get the type object for the GdkRenderer.
122 * @return A static GType object describing GdkRenderers.
124 GType
125 dia_gdk_renderer_get_type(void)
127 static GType object_type = 0;
129 if (!object_type)
131 static const GTypeInfo object_info =
133 sizeof (DiaGdkRendererClass),
134 (GBaseInitFunc) NULL,
135 (GBaseFinalizeFunc) NULL,
136 (GClassInitFunc) dia_gdk_renderer_class_init,
137 NULL, /* class_finalize */
138 NULL, /* class_data */
139 sizeof (DiaGdkRenderer),
140 0, /* n_preallocs */
141 (GInstanceInitFunc)renderer_init /* init */
144 object_type = g_type_register_static (DIA_TYPE_RENDERER,
145 "DiaGdkRenderer",
146 &object_info, 0);
149 return object_type;
152 /** Initialize a renderer object.
153 * @param renderer A renderer object to initialize.
154 * @param p Ignored, purpose unknown.
156 static void
157 renderer_init(DiaGdkRenderer *renderer, void* p)
159 renderer->line_width = 1;
160 renderer->line_style = GDK_LINE_SOLID;
161 renderer->cap_style = GDK_CAP_BUTT;
162 renderer->join_style = GDK_JOIN_ROUND;
164 renderer->saved_line_style = LINESTYLE_SOLID;
165 renderer->dash_length = 10;
166 renderer->dot_length = 2;
168 renderer->highlight_color = NULL;
171 /** Clean up a renderer object after use.
172 * @param object Renderer object to free subobjects from.
174 static void
175 renderer_finalize(GObject *object)
177 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
179 if (renderer->pixmap != NULL)
180 gdk_pixmap_unref(renderer->pixmap);
182 if (renderer->gc != NULL)
183 gdk_gc_unref(renderer->gc);
185 if (renderer->clip_region != NULL)
186 gdk_region_destroy(renderer->clip_region);
188 if (renderer->transform)
189 g_object_unref (renderer->transform);
191 G_OBJECT_CLASS (parent_class)->finalize (object);
194 /** Initialize members of the renderer class object. This sets up a bunch
195 * of functions to call for various render functions.
196 * @param klass The class object to initialize.
198 static void
199 dia_gdk_renderer_class_init(DiaGdkRendererClass *klass)
201 GObjectClass *object_class = G_OBJECT_CLASS (klass);
202 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
204 parent_class = g_type_class_peek_parent (klass);
206 object_class->finalize = renderer_finalize;
208 renderer_class->get_width_pixels = get_width_pixels;
209 renderer_class->get_height_pixels = get_height_pixels;
211 renderer_class->begin_render = begin_render;
212 renderer_class->end_render = end_render;
214 renderer_class->set_linewidth = set_linewidth;
215 renderer_class->set_linecaps = set_linecaps;
216 renderer_class->set_linejoin = set_linejoin;
217 renderer_class->set_linestyle = set_linestyle;
218 renderer_class->set_dashlength = set_dashlength;
219 renderer_class->set_fillstyle = set_fillstyle;
221 renderer_class->draw_line = draw_line;
222 renderer_class->fill_polygon = fill_polygon;
223 renderer_class->draw_rect = draw_rect;
224 renderer_class->fill_rect = fill_rect;
225 renderer_class->draw_arc = draw_arc;
226 renderer_class->fill_arc = fill_arc;
227 renderer_class->draw_ellipse = draw_ellipse;
228 renderer_class->fill_ellipse = fill_ellipse;
230 /* use <draw|fill>_bezier from DiaRenderer */
232 renderer_class->draw_string = draw_string;
233 renderer_class->draw_text = draw_text;
234 renderer_class->draw_image = draw_image;
236 /* medium level functions */
237 renderer_class->draw_rect = draw_rect;
238 renderer_class->draw_polyline = draw_polyline;
239 renderer_class->draw_polygon = draw_polygon;
240 renderer_class->draw_object = draw_object;
242 /* Interactive functions */
243 renderer_class->get_text_width = get_text_width;
246 /** Convert Dia color objects into GDK color objects.
247 * If the highlight color is set, that will be used instead. This allows
248 * rendering of an object to do highlight rendering.
249 * @param renderer The renderer to check for highlight color.
250 * @param col A color object to convert.
251 * @param gdk_col Resulting GDK convert.
253 static void
254 renderer_color_convert(DiaGdkRenderer *renderer,
255 Color *col, GdkColor *gdk_col)
257 if (renderer->highlight_color != NULL) {
258 color_convert(renderer->highlight_color, gdk_col);
259 } else {
260 color_convert(col, gdk_col);
264 static void
265 begin_render (DiaRenderer *object)
269 static void
270 end_render (DiaRenderer *object)
274 static void
275 set_linewidth (DiaRenderer *object, real linewidth)
277 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
279 if (renderer->highlight_color != NULL) {
280 /* 6 pixels wide -> 3 pixels beyond normal obj */
281 real border = dia_untransform_length(renderer->transform, 6);
282 linewidth += border;
285 /* 0 == hairline **/
286 renderer->line_width =
287 dia_transform_length(renderer->transform, linewidth);
289 if (renderer->line_width<=0)
290 renderer->line_width = 1; /* Minimum 1 pixel. */
292 gdk_gc_set_line_attributes(renderer->gc,
293 renderer->line_width,
294 renderer->line_style,
295 renderer->cap_style,
296 renderer->join_style);
299 static void
300 set_linecaps (DiaRenderer *object, LineCaps mode)
302 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
304 if (renderer->highlight_color != NULL) {
305 renderer->cap_style = GDK_CAP_ROUND;
306 } else {
307 switch(mode) {
308 case LINECAPS_BUTT:
309 renderer->cap_style = GDK_CAP_BUTT;
310 break;
311 case LINECAPS_ROUND:
312 renderer->cap_style = GDK_CAP_ROUND;
313 break;
314 case LINECAPS_PROJECTING:
315 renderer->cap_style = GDK_CAP_PROJECTING;
316 break;
320 gdk_gc_set_line_attributes(renderer->gc,
321 renderer->line_width,
322 renderer->line_style,
323 renderer->cap_style,
324 renderer->join_style);
327 static void
328 set_linejoin (DiaRenderer *object, LineJoin mode)
330 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
332 if (renderer->highlight_color != NULL) {
333 renderer->join_style = GDK_JOIN_ROUND;
334 } else {
335 switch(mode) {
336 case LINEJOIN_MITER:
337 renderer->join_style = GDK_JOIN_MITER;
338 break;
339 case LINEJOIN_ROUND:
340 renderer->join_style = GDK_JOIN_ROUND;
341 break;
342 case LINEJOIN_BEVEL:
343 renderer->join_style = GDK_JOIN_BEVEL;
344 break;
348 gdk_gc_set_line_attributes(renderer->gc,
349 renderer->line_width,
350 renderer->line_style,
351 renderer->cap_style,
352 renderer->join_style);
355 /** Set the dashes for this renderer.
356 * offset determines where in the pattern the dashes will start.
357 * It is used by the grid in particular to make the grid dashes line up.
359 void
360 dia_gdk_renderer_set_dashes(DiaGdkRenderer *renderer, int offset)
362 gint8 dash_list[6];
363 int hole_width;
364 int pattern_length;
366 switch(renderer->saved_line_style) {
367 case LINESTYLE_SOLID:
368 break;
369 case LINESTYLE_DASHED:
370 dash_list[0] = renderer->dash_length;
371 dash_list[1] = renderer->dash_length;
372 pattern_length = renderer->dash_length*2;
373 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2);
374 break;
375 case LINESTYLE_DASH_DOT:
376 hole_width = (renderer->dash_length - renderer->dot_length) / 2;
377 if (hole_width==0)
378 hole_width = 1;
379 dash_list[0] = renderer->dash_length;
380 dash_list[1] = hole_width;
381 dash_list[2] = renderer->dot_length;
382 dash_list[3] = hole_width;
383 pattern_length = renderer->dash_length+renderer->dot_length+2*hole_width;
384 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 4);
385 break;
386 case LINESTYLE_DASH_DOT_DOT:
387 hole_width = (renderer->dash_length - 2*renderer->dot_length) / 3;
388 if (hole_width==0)
389 hole_width = 1;
390 dash_list[0] = renderer->dash_length;
391 dash_list[1] = hole_width;
392 dash_list[2] = renderer->dot_length;
393 dash_list[3] = hole_width;
394 dash_list[4] = renderer->dot_length;
395 dash_list[5] = hole_width;
396 pattern_length = renderer->dash_length+2*renderer->dot_length+3*hole_width;
397 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 6);
398 break;
399 case LINESTYLE_DOTTED:
400 dash_list[0] = renderer->dot_length;
401 dash_list[1] = renderer->dot_length;
402 pattern_length = renderer->dot_length;
403 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2);
404 break;
409 static void
410 set_linestyle (DiaRenderer *object, LineStyle mode)
412 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
414 renderer->saved_line_style = mode;
415 switch(mode) {
416 case LINESTYLE_SOLID:
417 renderer->line_style = GDK_LINE_SOLID;
418 break;
419 case LINESTYLE_DASHED:
420 renderer->line_style = GDK_LINE_ON_OFF_DASH;
421 dia_gdk_renderer_set_dashes(renderer, 0);
422 break;
423 case LINESTYLE_DASH_DOT:
424 renderer->line_style = GDK_LINE_ON_OFF_DASH;
425 dia_gdk_renderer_set_dashes(renderer, 0);
426 break;
427 case LINESTYLE_DASH_DOT_DOT:
428 renderer->line_style = GDK_LINE_ON_OFF_DASH;
429 dia_gdk_renderer_set_dashes(renderer, 0);
430 break;
431 case LINESTYLE_DOTTED:
432 renderer->line_style = GDK_LINE_ON_OFF_DASH;
433 dia_gdk_renderer_set_dashes(renderer, 0);
434 break;
436 gdk_gc_set_line_attributes(renderer->gc,
437 renderer->line_width,
438 renderer->line_style,
439 renderer->cap_style,
440 renderer->join_style);
443 static void
444 set_dashlength (DiaRenderer *object, real length)
446 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
447 /* dot = 10% of len */
448 real ddisp_len;
450 ddisp_len =
451 dia_transform_length(renderer->transform, length);
453 renderer->dash_length = (int)floor(ddisp_len+0.5);
454 renderer->dot_length = (int)floor(ddisp_len*0.1+0.5);
456 if (renderer->dash_length<=0)
457 renderer->dash_length = 1;
458 if (renderer->dash_length>255)
459 renderer->dash_length = 255;
460 if (renderer->dot_length<=0)
461 renderer->dot_length = 1;
462 if (renderer->dot_length>255)
463 renderer->dot_length = 255;
464 set_linestyle(object, renderer->saved_line_style);
467 static void
468 set_fillstyle (DiaRenderer *object, FillStyle mode)
470 switch(mode) {
471 case FILLSTYLE_SOLID:
472 break;
473 default:
474 message_error("gdk_renderer: Unsupported fill mode specified!\n");
478 static void
479 draw_line (DiaRenderer *object, Point *start, Point *end, Color *line_color)
481 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
483 GdkGC *gc = renderer->gc;
484 GdkColor color;
485 int x1,y1,x2,y2;
487 dia_transform_coords(renderer->transform, start->x, start->y, &x1, &y1);
488 dia_transform_coords(renderer->transform, end->x, end->y, &x2, &y2);
490 renderer_color_convert(renderer, line_color, &color);
491 gdk_gc_set_foreground(gc, &color);
493 gdk_draw_line(renderer->pixmap, gc,
494 x1, y1, x2, y2);
497 static void
498 fill_polygon (DiaRenderer *object, Point *points, int num_points, Color *line_color)
500 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
501 GdkGC *gc = renderer->gc;
502 GdkColor color;
503 GdkPoint *gdk_points;
504 int i,x,y;
506 gdk_points = g_new(GdkPoint, num_points);
508 for (i=0;i<num_points;i++) {
509 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
510 gdk_points[i].x = x;
511 gdk_points[i].y = y;
514 renderer_color_convert(renderer, line_color, &color);
515 gdk_gc_set_foreground(gc, &color);
517 gdk_draw_polygon(renderer->pixmap, gc, TRUE, gdk_points, num_points);
518 g_free(gdk_points);
521 static void
522 draw_fill_arc (DiaRenderer *object,
523 Point *center,
524 real width, real height,
525 real angle1, real angle2,
526 Color *color,
527 gboolean fill)
529 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
530 GdkGC *gc = renderer->gc;
531 GdkColor gdkcolor;
532 gint top, left, bottom, right;
533 real dangle;
535 dia_transform_coords(renderer->transform,
536 center->x - width/2, center->y - height/2,
537 &left, &top);
538 dia_transform_coords(renderer->transform,
539 center->x + width/2, center->y + height/2,
540 &right, &bottom);
542 if ((left>right) || (top>bottom))
543 return;
545 renderer_color_convert(renderer, color, &gdkcolor);
546 gdk_gc_set_foreground(gc, &gdkcolor);
548 dangle = angle2-angle1;
549 if (dangle<0)
550 dangle += 360.0;
552 gdk_draw_arc(renderer->pixmap,
553 gc, fill,
554 left, top, right-left+(fill?1:0), bottom-top+(fill?1:0),
555 (int) (angle1*64.0), (int) (dangle*64.0));
557 static void
558 draw_arc (DiaRenderer *object,
559 Point *center,
560 real width, real height,
561 real angle1, real angle2,
562 Color *color)
564 draw_fill_arc (object, center, width, height, angle1, angle2, color, FALSE);
567 static void
568 fill_arc (DiaRenderer *object, Point *center,
569 real width, real height, real angle1, real angle2,
570 Color *color)
572 draw_fill_arc (object, center, width, height, angle1, angle2, color, TRUE);
575 static void
576 draw_ellipse (DiaRenderer *object, Point *center,
577 real width, real height,
578 Color *color)
580 draw_arc(object, center, width, height, 0.0, 360.0, color);
583 static void
584 fill_ellipse (DiaRenderer *object, Point *center,
585 real width, real height, Color *color)
587 fill_arc(object, center, width, height, 0.0, 360.0, color);
590 static gint
591 get_layout_first_baseline(PangoLayout* layout)
593 PangoLayoutIter* iter = pango_layout_get_iter(layout);
594 gint result = pango_layout_iter_get_baseline(iter) / PANGO_SCALE;
595 pango_layout_iter_free(iter);
596 return result;
599 /** Return the x adjustment needed for this text and alignment */
600 static real
601 get_alignment_adjustment(DiaRenderer *object,
602 const gchar *text,
603 Alignment alignment)
605 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
607 switch (alignment) {
608 case ALIGN_LEFT:
609 return 0.0;
610 case ALIGN_CENTER:
611 return
612 dia_font_scaled_string_width(text, object->font,
613 object->font_height,
614 dia_transform_length(renderer->transform, 10.0)/10.0)/2;
615 break;
616 case ALIGN_RIGHT:
617 return
618 dia_font_scaled_string_width(text, object->font,
619 object->font_height,
620 dia_transform_length(renderer->transform, 10.0)/10.0);
621 break;
623 return 0.0;
626 /* Draw a highlighted version of a string.
628 static void
629 draw_highlighted_string(DiaGdkRenderer *renderer,
630 PangoLayout *layout,
631 int x, int y,
632 GdkColor *color)
634 gint width, height;
636 pango_layout_get_pixel_size(layout, &width, &height);
638 gdk_gc_set_foreground(renderer->gc, color);
640 gdk_draw_rectangle (renderer->pixmap,
641 renderer->gc, TRUE,
642 x-3, y-3,
643 width+6, height+6);
646 static void
647 draw_string (DiaRenderer *object,
648 const gchar *text, Point *pos, Alignment alignment,
649 Color *color)
651 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
652 GdkColor gdkcolor;
654 int x,y;
655 Point start_pos;
656 PangoLayout* layout = NULL;
658 if (text == NULL || *text == '\0') return; /* Don't render empty strings. */
660 point_copy(&start_pos,pos);
662 renderer_color_convert(renderer, color, &gdkcolor);
664 start_pos.x -= get_alignment_adjustment(object, text, alignment);
667 int height_pixels = dia_transform_length(renderer->transform, object->font_height);
668 if (height_pixels < 2) { /* "Greeking" instead of making tiny font */
669 int width_pixels = dia_transform_length(
670 renderer->transform,
671 dia_font_string_width(text, object->font, object->font_height));
672 gdk_gc_set_foreground(renderer->gc, &gdkcolor);
673 gdk_gc_set_dashes(renderer->gc, 0, "\1\2", 2);
674 dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y);
675 gdk_draw_line(renderer->pixmap, renderer->gc, x, y, x + width_pixels, y);
676 return;
680 /* My apologies for adding more #hell, but the alternative is an abhorrent
681 * kludge.
683 #if defined HAVE_FREETYPE
685 FT_Bitmap ftbitmap;
686 guint8 *graybitmap;
687 int width, height;
688 int rowstride;
689 GdkPixbuf *rgba = NULL;
692 start_pos.y -=
693 dia_font_scaled_ascent(text, object->font,
694 object->font_height,
695 dia_transform_length(renderer->transform, 1.0));
697 dia_transform_coords(renderer->transform,
698 start_pos.x, start_pos.y, &x, &y);
700 layout = dia_font_scaled_build_layout(text, object->font,
701 object->font_height,
702 dia_transform_length(renderer->transform, 1.0));
703 if (renderer->highlight_color != NULL) {
704 draw_highlighted_string(renderer, layout, x, y, &gdkcolor);
705 } else {
706 /* y -= get_layout_first_baseline(layout); */
707 pango_layout_get_pixel_size(layout, &width, &height);
709 if (width > 0) {
710 rowstride = 32*((width+31)/31);
712 graybitmap = (guint8*)g_new0(guint8, height*rowstride);
714 ftbitmap.rows = height;
715 ftbitmap.width = width;
716 ftbitmap.pitch = rowstride;
717 ftbitmap.buffer = graybitmap;
718 ftbitmap.num_grays = 256;
719 ftbitmap.pixel_mode = ft_pixel_mode_grays;
720 ftbitmap.palette_mode = 0;
721 ftbitmap.palette = 0;
722 pango_ft2_render_layout(&ftbitmap, layout, 0, 0);
725 int stride;
726 guchar* pixels;
727 int i,j;
728 rgba = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
729 stride = gdk_pixbuf_get_rowstride(rgba);
730 pixels = gdk_pixbuf_get_pixels(rgba);
731 for (i = 0; i < height; i++) {
732 for (j = 0; j < width; j++) {
733 pixels[i*stride+j*4] = gdkcolor.red>>8;
734 pixels[i*stride+j*4+1] = gdkcolor.green>>8;
735 pixels[i*stride+j*4+2] = gdkcolor.blue>>8;
736 pixels[i*stride+j*4+3] = graybitmap[i*rowstride+j];
739 g_free(graybitmap);
742 if (rgba != NULL) { /* Non-null width */
743 gdk_draw_pixbuf(renderer->pixmap, renderer->gc, rgba, 0, 0, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0);
744 g_object_unref(G_OBJECT(rgba));
747 gdk_gc_set_function(gc, GDK_COPY_INVERT);
748 gdk_draw_gray_image(renderer->pixmap, gc, x, y, width, height,
749 GDK_RGB_DITHER_NONE, graybitmap, rowstride);
750 gdk_gc_set_function(gc, GDK_COPY);
754 #else
756 GdkGC *gc = renderer->gc;
757 gdk_gc_set_foreground(gc, &gdkcolor);
758 dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y);
760 layout = dia_font_scaled_build_layout(
761 text, object->font,
762 object->font_height,
763 dia_transform_length (renderer->transform, 10.0) / 10.0);
764 y -= get_layout_first_baseline(layout);
765 if (renderer->highlight_color != NULL) {
766 draw_highlighted_string(renderer, layout, x, y, &gdkcolor);
767 } else {
768 gdk_draw_layout(renderer->pixmap,gc,x,y,layout);
771 #endif
773 /* abuse_layout_object(layout,text); */
775 g_object_unref(G_OBJECT(layout));
778 /** Caching Pango renderer */
779 static void
780 draw_text(DiaRenderer *renderer, Text *text) {
781 Point pos;
782 int i;
784 DIA_RENDERER_GET_CLASS(renderer)->set_font(renderer, text->font, text->height);
785 pos = text->position;
787 for (i=0;i<text->numlines;i++) {
788 DIA_RENDERER_GET_CLASS(renderer)->draw_string(renderer,
789 text->line[i],
790 &pos, text->alignment,
791 &text->color);
792 pos.y += text->height;
797 /* Get the width of the given text in cm */
798 static real
799 get_text_width(DiaRenderer *object,
800 const gchar *text, int length)
802 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
803 real result;
805 if (length != strlen(text)) {
806 char *othertx;
807 int ulen;
808 /* A couple UTF8-chars: æblegrød Š Ť Ž ę ć ń уфхцНОПРЄ є Ґ Њ Ћ Џ */
809 ulen = g_utf8_offset_to_pointer(text, length)-text;
810 if (!g_utf8_validate(text, ulen, NULL)) {
811 g_warning ("Text at char %d not valid\n", length);
813 othertx = g_strndup(text, ulen);
814 result = dia_font_scaled_string_width(
815 othertx,object->font,
816 object->font_height,
817 dia_transform_length (renderer->transform, 10.0) / 10.0);
818 g_free(othertx);
819 } else {
820 result =
821 dia_font_scaled_string_width(
822 text,object->font,
823 object->font_height,
824 dia_transform_length (renderer->transform, 10.0) / 10.0);
826 return result;
829 static void
830 draw_image (DiaRenderer *object,
831 Point *point,
832 real width, real height,
833 DiaImage image)
835 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
836 if (renderer->highlight_color != NULL) {
837 Point lr;
838 DiaRendererClass *self_class = DIA_RENDERER_GET_CLASS (object);
840 lr = *point;
841 lr.x += width;
842 lr.y += height;
843 self_class->fill_rect(object, point, &lr, renderer->highlight_color);
844 } else {
845 int real_width, real_height, real_x, real_y;
847 real_width = dia_transform_length(renderer->transform, width);
848 real_height = dia_transform_length(renderer->transform, height);
849 dia_transform_coords(renderer->transform, point->x, point->y,
850 &real_x, &real_y);
852 dia_image_draw(image, renderer->pixmap, real_x, real_y,
853 real_width, real_height);
858 * medium level functions
860 static void
861 draw_fill_rect (DiaGdkRenderer *renderer,
862 Point *ul_corner, Point *lr_corner,
863 Color *color, gboolean fill)
865 GdkGC *gc = renderer->gc;
866 GdkColor gdkcolor;
867 gint top, bottom, left, right;
869 dia_transform_coords(renderer->transform,
870 ul_corner->x, ul_corner->y, &left, &top);
871 dia_transform_coords(renderer->transform,
872 lr_corner->x, lr_corner->y, &right, &bottom);
874 if ((left>right) || (top>bottom))
875 return;
877 renderer_color_convert(renderer, color, &gdkcolor);
878 gdk_gc_set_foreground(gc, &gdkcolor);
880 gdk_draw_rectangle (renderer->pixmap,
881 gc, fill,
882 left, top,
883 right-left,
884 bottom-top);
887 static void
888 draw_rect (DiaRenderer *object,
889 Point *ul_corner, Point *lr_corner,
890 Color *color)
892 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
894 draw_fill_rect (renderer, ul_corner, lr_corner, color, FALSE);
897 static void
898 fill_rect (DiaRenderer *object,
899 Point *ul_corner, Point *lr_corner,
900 Color *color)
902 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
904 draw_fill_rect (renderer, ul_corner, lr_corner, color, TRUE);
907 static void
908 draw_polyline (DiaRenderer *self,
909 Point *points, int num_points,
910 Color *line_color)
912 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
913 GdkGC *gc = renderer->gc;
914 GdkColor color;
915 GdkPoint *gdk_points;
916 int i,x,y;
918 gdk_points = g_new(GdkPoint, num_points);
920 for (i=0;i<num_points;i++) {
921 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
922 gdk_points[i].x = x;
923 gdk_points[i].y = y;
926 renderer_color_convert(renderer, line_color, &color);
927 gdk_gc_set_foreground(gc, &color);
929 gdk_draw_lines(renderer->pixmap, gc, gdk_points, num_points);
930 g_free(gdk_points);
933 static void
934 draw_polygon (DiaRenderer *self,
935 Point *points, int num_points,
936 Color *line_color)
938 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
939 GdkGC *gc = renderer->gc;
940 GdkColor color;
941 GdkPoint *gdk_points;
942 int i,x,y;
944 gdk_points = g_new(GdkPoint, num_points);
946 for (i=0;i<num_points;i++) {
947 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
948 gdk_points[i].x = x;
949 gdk_points[i].y = y;
952 renderer_color_convert(renderer, line_color, &color);
953 gdk_gc_set_foreground(gc, &color);
955 gdk_draw_polygon(renderer->pixmap, gc, FALSE, gdk_points, num_points);
956 g_free(gdk_points);
959 static void
960 draw_object (DiaRenderer *renderer, DiaObject *object)
962 if (object->highlight_color != NULL) {
963 DiaGdkRenderer *gdk_rend = DIA_GDK_RENDERER(renderer);
964 gdk_rend->highlight_color = object->highlight_color;
965 object->ops->draw(object, renderer);
966 gdk_rend->highlight_color = NULL;
968 object->ops->draw(object, renderer);
971 static int
972 get_width_pixels (DiaRenderer *object)
974 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
975 int width = 0;
977 if (renderer->pixmap)
978 gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &width, NULL);
980 return width;
983 static int
984 get_height_pixels (DiaRenderer *object)
986 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
987 int height = 0;
989 if (renderer->pixmap)
990 gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), NULL, &height);
992 return height;