2006-12-03 Dimitris Glezos <dimitris@glezos.com>
[dia.git] / lib / diagdkrenderer.c
blobb0d5cfa3c1f1895c5a4f92c87e89af514c9e49d8
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"
39 #include "object.h"
40 #include "textline.h"
42 #include "time.h"
44 #ifdef HAVE_FREETYPE
45 #include <pango/pango.h>
46 #include <pango/pangoft2.h>
47 #endif
49 static int get_width_pixels (DiaRenderer *);
50 static int get_height_pixels (DiaRenderer *);
52 static void begin_render (DiaRenderer *);
53 static void end_render (DiaRenderer *);
55 static void set_linewidth (DiaRenderer *renderer, real linewidth);
56 static void set_linecaps (DiaRenderer *renderer, LineCaps mode);
57 static void set_linejoin (DiaRenderer *renderer, LineJoin mode);
58 static void set_linestyle (DiaRenderer *renderer, LineStyle mode);
59 static void set_dashlength (DiaRenderer *renderer, real length);
60 static void set_fillstyle (DiaRenderer *renderer, FillStyle mode);
62 static void draw_line (DiaRenderer *renderer,
63 Point *start, Point *end,
64 Color *color);
65 static void fill_polygon (DiaRenderer *renderer,
66 Point *points, int num_points,
67 Color *color);
68 static void draw_arc (DiaRenderer *renderer,
69 Point *center,
70 real width, real height,
71 real angle1, real angle2,
72 Color *color);
73 static void fill_arc (DiaRenderer *renderer,
74 Point *center,
75 real width, real height,
76 real angle1, real angle2,
77 Color *color);
78 static void draw_ellipse (DiaRenderer *renderer,
79 Point *center,
80 real width, real height,
81 Color *color);
82 static void fill_ellipse (DiaRenderer *renderer,
83 Point *center,
84 real width, real height,
85 Color *color);
86 static void draw_string (DiaRenderer *renderer,
87 const gchar *text,
88 Point *pos,
89 Alignment alignment,
90 Color *color);
91 static void draw_text_line (DiaRenderer *renderer,
92 TextLine *text,
93 Point *pos,
94 Color *color);
95 static void draw_image (DiaRenderer *renderer,
96 Point *point,
97 real width, real height,
98 DiaImage image);
100 static void draw_rect (DiaRenderer *renderer,
101 Point *ul_corner, Point *lr_corner,
102 Color *color);
103 static void fill_rect (DiaRenderer *renderer,
104 Point *ul_corner, Point *lr_corner,
105 Color *color);
106 static void draw_fill_rect (DiaGdkRenderer *renderer,
107 Point *ul_corner, Point *lr_corner,
108 Color *color, gboolean fill);
109 static void draw_polyline (DiaRenderer *renderer,
110 Point *points, int num_points,
111 Color *color);
112 static void draw_polygon (DiaRenderer *renderer,
113 Point *points, int num_points,
114 Color *color);
115 static void draw_object (DiaRenderer *renderer, DiaObject *object);
117 static real get_text_width (DiaRenderer *renderer,
118 const gchar *text, int length);
120 static void dia_gdk_renderer_class_init (DiaGdkRendererClass *klass);
121 static void renderer_init (DiaGdkRenderer *renderer, void*);
123 static gpointer parent_class = NULL;
125 /** Get the type object for the GdkRenderer.
126 * @return A static GType object describing GdkRenderers.
128 GType
129 dia_gdk_renderer_get_type(void)
131 static GType object_type = 0;
133 if (!object_type)
135 static const GTypeInfo object_info =
137 sizeof (DiaGdkRendererClass),
138 (GBaseInitFunc) NULL,
139 (GBaseFinalizeFunc) NULL,
140 (GClassInitFunc) dia_gdk_renderer_class_init,
141 NULL, /* class_finalize */
142 NULL, /* class_data */
143 sizeof (DiaGdkRenderer),
144 0, /* n_preallocs */
145 (GInstanceInitFunc)renderer_init /* init */
148 object_type = g_type_register_static (DIA_TYPE_RENDERER,
149 "DiaGdkRenderer",
150 &object_info, 0);
153 return object_type;
156 /** Initialize a renderer object.
157 * @param renderer A renderer object to initialize.
158 * @param p Ignored, purpose unknown.
160 static void
161 renderer_init(DiaGdkRenderer *renderer, void* p)
163 renderer->line_width = 1;
164 renderer->line_style = GDK_LINE_SOLID;
165 renderer->cap_style = GDK_CAP_BUTT;
166 renderer->join_style = GDK_JOIN_ROUND;
168 renderer->saved_line_style = LINESTYLE_SOLID;
169 renderer->dash_length = 10;
170 renderer->dot_length = 2;
172 renderer->highlight_color = NULL;
175 /** Clean up a renderer object after use.
176 * @param object Renderer object to free subobjects from.
178 static void
179 renderer_finalize(GObject *object)
181 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
183 if (renderer->pixmap != NULL)
184 gdk_pixmap_unref(renderer->pixmap);
186 if (renderer->gc != NULL)
187 gdk_gc_unref(renderer->gc);
189 if (renderer->clip_region != NULL)
190 gdk_region_destroy(renderer->clip_region);
192 if (renderer->transform)
193 g_object_unref (renderer->transform);
195 G_OBJECT_CLASS (parent_class)->finalize (object);
198 /** Initialize members of the renderer class object. This sets up a bunch
199 * of functions to call for various render functions.
200 * @param klass The class object to initialize.
202 static void
203 dia_gdk_renderer_class_init(DiaGdkRendererClass *klass)
205 GObjectClass *object_class = G_OBJECT_CLASS (klass);
206 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
208 parent_class = g_type_class_peek_parent (klass);
210 object_class->finalize = renderer_finalize;
212 renderer_class->get_width_pixels = get_width_pixels;
213 renderer_class->get_height_pixels = get_height_pixels;
215 renderer_class->begin_render = begin_render;
216 renderer_class->end_render = end_render;
218 renderer_class->set_linewidth = set_linewidth;
219 renderer_class->set_linecaps = set_linecaps;
220 renderer_class->set_linejoin = set_linejoin;
221 renderer_class->set_linestyle = set_linestyle;
222 renderer_class->set_dashlength = set_dashlength;
223 renderer_class->set_fillstyle = set_fillstyle;
225 renderer_class->draw_line = draw_line;
226 renderer_class->fill_polygon = fill_polygon;
227 renderer_class->draw_rect = draw_rect;
228 renderer_class->fill_rect = fill_rect;
229 renderer_class->draw_arc = draw_arc;
230 renderer_class->fill_arc = fill_arc;
231 renderer_class->draw_ellipse = draw_ellipse;
232 renderer_class->fill_ellipse = fill_ellipse;
234 /* use <draw|fill>_bezier from DiaRenderer */
236 renderer_class->draw_string = draw_string;
237 renderer_class->draw_text_line = draw_text_line;
238 renderer_class->draw_image = draw_image;
240 /* medium level functions */
241 renderer_class->draw_rect = draw_rect;
242 renderer_class->draw_polyline = draw_polyline;
243 renderer_class->draw_polygon = draw_polygon;
244 renderer_class->draw_object = draw_object;
246 /* Interactive functions */
247 renderer_class->get_text_width = get_text_width;
250 /** Convert Dia color objects into GDK color objects.
251 * If the highlight color is set, that will be used instead. This allows
252 * rendering of an object to do highlight rendering.
253 * @param renderer The renderer to check for highlight color.
254 * @param col A color object to convert.
255 * @param gdk_col Resulting GDK convert.
257 static void
258 renderer_color_convert(DiaGdkRenderer *renderer,
259 Color *col, GdkColor *gdk_col)
261 if (renderer->highlight_color != NULL) {
262 color_convert(renderer->highlight_color, gdk_col);
263 } else {
264 color_convert(col, gdk_col);
268 static void
269 begin_render (DiaRenderer *object)
273 static void
274 end_render (DiaRenderer *object)
278 static void
279 set_linewidth (DiaRenderer *object, real linewidth)
281 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
283 if (renderer->highlight_color != NULL) {
284 /* 6 pixels wide -> 3 pixels beyond normal obj */
285 real border = dia_untransform_length(renderer->transform, 6);
286 linewidth += border;
289 /* 0 == hairline **/
290 renderer->line_width =
291 dia_transform_length(renderer->transform, linewidth);
293 if (renderer->line_width<=0)
294 renderer->line_width = 1; /* Minimum 1 pixel. */
296 gdk_gc_set_line_attributes(renderer->gc,
297 renderer->line_width,
298 renderer->line_style,
299 renderer->cap_style,
300 renderer->join_style);
303 static void
304 set_linecaps (DiaRenderer *object, LineCaps mode)
306 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
308 if (renderer->highlight_color != NULL) {
309 renderer->cap_style = GDK_CAP_ROUND;
310 } else {
311 switch(mode) {
312 case LINECAPS_BUTT:
313 renderer->cap_style = GDK_CAP_BUTT;
314 break;
315 case LINECAPS_ROUND:
316 renderer->cap_style = GDK_CAP_ROUND;
317 break;
318 case LINECAPS_PROJECTING:
319 renderer->cap_style = GDK_CAP_PROJECTING;
320 break;
324 gdk_gc_set_line_attributes(renderer->gc,
325 renderer->line_width,
326 renderer->line_style,
327 renderer->cap_style,
328 renderer->join_style);
331 static void
332 set_linejoin (DiaRenderer *object, LineJoin mode)
334 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
336 if (renderer->highlight_color != NULL) {
337 renderer->join_style = GDK_JOIN_ROUND;
338 } else {
339 switch(mode) {
340 case LINEJOIN_MITER:
341 renderer->join_style = GDK_JOIN_MITER;
342 break;
343 case LINEJOIN_ROUND:
344 renderer->join_style = GDK_JOIN_ROUND;
345 break;
346 case LINEJOIN_BEVEL:
347 renderer->join_style = GDK_JOIN_BEVEL;
348 break;
349 default :
350 /* invalid mode, just here to set a breakpoint */
351 renderer->join_style = GDK_JOIN_ROUND;
352 break;
356 gdk_gc_set_line_attributes(renderer->gc,
357 renderer->line_width,
358 renderer->line_style,
359 renderer->cap_style,
360 renderer->join_style);
363 /** Set the dashes for this renderer.
364 * offset determines where in the pattern the dashes will start.
365 * It is used by the grid in particular to make the grid dashes line up.
367 void
368 dia_gdk_renderer_set_dashes(DiaGdkRenderer *renderer, int offset)
370 gint8 dash_list[6];
371 int hole_width;
372 int pattern_length;
374 switch(renderer->saved_line_style) {
375 case LINESTYLE_SOLID:
376 break;
377 case LINESTYLE_DASHED:
378 dash_list[0] = renderer->dash_length;
379 dash_list[1] = renderer->dash_length;
380 pattern_length = renderer->dash_length*2;
381 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2);
382 break;
383 case LINESTYLE_DASH_DOT:
384 hole_width = (renderer->dash_length - renderer->dot_length) / 2;
385 if (hole_width==0)
386 hole_width = 1;
387 dash_list[0] = renderer->dash_length;
388 dash_list[1] = hole_width;
389 dash_list[2] = renderer->dot_length;
390 dash_list[3] = hole_width;
391 pattern_length = renderer->dash_length+renderer->dot_length+2*hole_width;
392 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 4);
393 break;
394 case LINESTYLE_DASH_DOT_DOT:
395 hole_width = (renderer->dash_length - 2*renderer->dot_length) / 3;
396 if (hole_width==0)
397 hole_width = 1;
398 dash_list[0] = renderer->dash_length;
399 dash_list[1] = hole_width;
400 dash_list[2] = renderer->dot_length;
401 dash_list[3] = hole_width;
402 dash_list[4] = renderer->dot_length;
403 dash_list[5] = hole_width;
404 pattern_length = renderer->dash_length+2*renderer->dot_length+3*hole_width;
405 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 6);
406 break;
407 case LINESTYLE_DOTTED:
408 dash_list[0] = renderer->dot_length;
409 dash_list[1] = renderer->dot_length;
410 pattern_length = renderer->dot_length;
411 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2);
412 break;
417 static void
418 set_linestyle (DiaRenderer *object, LineStyle mode)
420 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
422 renderer->saved_line_style = mode;
423 switch(mode) {
424 case LINESTYLE_SOLID:
425 renderer->line_style = GDK_LINE_SOLID;
426 break;
427 case LINESTYLE_DASHED:
428 renderer->line_style = GDK_LINE_ON_OFF_DASH;
429 dia_gdk_renderer_set_dashes(renderer, 0);
430 break;
431 case LINESTYLE_DASH_DOT:
432 renderer->line_style = GDK_LINE_ON_OFF_DASH;
433 dia_gdk_renderer_set_dashes(renderer, 0);
434 break;
435 case LINESTYLE_DASH_DOT_DOT:
436 renderer->line_style = GDK_LINE_ON_OFF_DASH;
437 dia_gdk_renderer_set_dashes(renderer, 0);
438 break;
439 case LINESTYLE_DOTTED:
440 renderer->line_style = GDK_LINE_ON_OFF_DASH;
441 dia_gdk_renderer_set_dashes(renderer, 0);
442 break;
444 gdk_gc_set_line_attributes(renderer->gc,
445 renderer->line_width,
446 renderer->line_style,
447 renderer->cap_style,
448 renderer->join_style);
451 static void
452 set_dashlength (DiaRenderer *object, real length)
454 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
455 /* dot = 10% of len */
456 real ddisp_len;
458 ddisp_len =
459 dia_transform_length(renderer->transform, length);
461 renderer->dash_length = (int)floor(ddisp_len+0.5);
462 renderer->dot_length = (int)floor(ddisp_len*0.1+0.5);
464 if (renderer->dash_length<=0)
465 renderer->dash_length = 1;
466 if (renderer->dash_length>255)
467 renderer->dash_length = 255;
468 if (renderer->dot_length<=0)
469 renderer->dot_length = 1;
470 if (renderer->dot_length>255)
471 renderer->dot_length = 255;
472 set_linestyle(object, renderer->saved_line_style);
475 static void
476 set_fillstyle (DiaRenderer *object, FillStyle mode)
478 switch(mode) {
479 case FILLSTYLE_SOLID:
480 break;
481 default:
482 message_error("gdk_renderer: Unsupported fill mode specified!\n");
486 static void
487 draw_line (DiaRenderer *object, Point *start, Point *end, Color *line_color)
489 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
491 GdkGC *gc = renderer->gc;
492 GdkColor color;
493 int x1,y1,x2,y2;
495 dia_transform_coords(renderer->transform, start->x, start->y, &x1, &y1);
496 dia_transform_coords(renderer->transform, end->x, end->y, &x2, &y2);
498 renderer_color_convert(renderer, line_color, &color);
499 gdk_gc_set_foreground(gc, &color);
501 gdk_draw_line(renderer->pixmap, gc,
502 x1, y1, x2, y2);
505 static void
506 fill_polygon (DiaRenderer *object, Point *points, int num_points, Color *line_color)
508 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
509 GdkGC *gc = renderer->gc;
510 GdkColor color;
511 GdkPoint *gdk_points;
512 int i,x,y;
514 gdk_points = g_new(GdkPoint, num_points);
516 for (i=0;i<num_points;i++) {
517 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
518 gdk_points[i].x = x;
519 gdk_points[i].y = y;
522 renderer_color_convert(renderer, line_color, &color);
523 gdk_gc_set_foreground(gc, &color);
525 gdk_draw_polygon(renderer->pixmap, gc, TRUE, gdk_points, num_points);
526 g_free(gdk_points);
529 static void
530 draw_fill_arc (DiaRenderer *object,
531 Point *center,
532 real width, real height,
533 real angle1, real angle2,
534 Color *color,
535 gboolean fill)
537 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
538 GdkGC *gc = renderer->gc;
539 GdkColor gdkcolor;
540 gint top, left, bottom, right;
541 real dangle;
543 dia_transform_coords(renderer->transform,
544 center->x - width/2, center->y - height/2,
545 &left, &top);
546 dia_transform_coords(renderer->transform,
547 center->x + width/2, center->y + height/2,
548 &right, &bottom);
550 if ((left>right) || (top>bottom))
551 return;
553 renderer_color_convert(renderer, color, &gdkcolor);
554 gdk_gc_set_foreground(gc, &gdkcolor);
556 dangle = angle2-angle1;
557 if (dangle<0)
558 dangle += 360.0;
560 gdk_draw_arc(renderer->pixmap,
561 gc, fill,
562 left, top, right-left+(fill?1:0), bottom-top+(fill?1:0),
563 (int) (angle1*64.0), (int) (dangle*64.0));
565 static void
566 draw_arc (DiaRenderer *object,
567 Point *center,
568 real width, real height,
569 real angle1, real angle2,
570 Color *color)
572 draw_fill_arc (object, center, width, height, angle1, angle2, color, FALSE);
575 static void
576 fill_arc (DiaRenderer *object, Point *center,
577 real width, real height, real angle1, real angle2,
578 Color *color)
580 draw_fill_arc (object, center, width, height, angle1, angle2, color, TRUE);
583 static void
584 draw_ellipse (DiaRenderer *object, Point *center,
585 real width, real height,
586 Color *color)
588 draw_arc(object, center, width, height, 0.0, 360.0, color);
591 static void
592 fill_ellipse (DiaRenderer *object, Point *center,
593 real width, real height, Color *color)
595 fill_arc(object, center, width, height, 0.0, 360.0, color);
598 /* Draw a highlighted version of a string.
600 static void
601 draw_highlighted_string(DiaGdkRenderer *renderer,
602 PangoLayout *layout,
603 int x, int y,
604 GdkColor *color)
606 gint width, height;
608 pango_layout_get_pixel_size(layout, &width, &height);
610 gdk_gc_set_foreground(renderer->gc, color);
612 gdk_draw_rectangle (renderer->pixmap,
613 renderer->gc, TRUE,
614 x-3, y-3,
615 width+6, height+6);
618 static void
619 draw_string (DiaRenderer *object,
620 const gchar *text, Point *pos, Alignment alignment,
621 Color *color)
623 TextLine *text_line = text_line_new(text, object->font, object->font_height);
624 Point realigned_pos = *pos;
625 realigned_pos.x -= text_line_get_alignment_adjustment(text_line, alignment);
626 draw_text_line(object, text_line, &realigned_pos, color);
629 #ifdef HAVE_FREETYPE
630 static void
631 initialize_ft_bitmap(FT_Bitmap *ftbitmap, int width, int height)
633 int rowstride = 32*((width+31)/31);
634 guint8 *graybitmap = (guint8*)g_new0(guint8, height*rowstride);
636 ftbitmap->rows = height;
637 ftbitmap->width = width;
638 ftbitmap->pitch = rowstride;
639 ftbitmap->buffer = graybitmap;
640 ftbitmap->num_grays = 256;
641 ftbitmap->pixel_mode = ft_pixel_mode_grays;
642 ftbitmap->palette_mode = 0;
643 ftbitmap->palette = 0;
646 typedef struct _FreetypeCacheData {
647 int x;
648 int y;
649 int width;
650 int height;
651 GdkPixbuf *rgba;
652 } FreetypeCacheData;
654 static void
655 free_freetype_cache_data(gpointer data) {
656 FreetypeCacheData *ftdata = (FreetypeCacheData*) data;
658 g_object_unref(ftdata->rgba);
659 g_free(ftdata);
661 #endif
663 /** Draw a TextLine object.
664 * @param object The renderer object to use for transform and output
665 * @param text_line The TextLine to render, including font and height.
666 * @param pos The position to render it at.
667 * @param color The color to render it with.
669 static void
670 draw_text_line (DiaRenderer *object, TextLine *text_line,
671 Point *pos, Color *color)
673 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
674 GdkColor gdkcolor;
675 int x,y;
676 Point start_pos;
677 PangoLayout* layout = NULL;
678 const gchar *text = text_line_get_string(text_line);
679 int height_pixels;
680 real font_height = text_line_get_height(text_line);
681 real scale = dia_transform_length(renderer->transform, 1.0);
683 if (text == NULL || *text == '\0') return; /* Don't render empty strings. */
685 point_copy(&start_pos,pos);
687 renderer_color_convert(renderer, color, &gdkcolor);
689 height_pixels = dia_transform_length(renderer->transform, font_height);
690 if (height_pixels < 2) { /* "Greeking" instead of making tiny font */
691 int width_pixels = dia_transform_length(renderer->transform,
692 text_line_get_width(text_line));
693 gdk_gc_set_foreground(renderer->gc, &gdkcolor);
694 gdk_gc_set_dashes(renderer->gc, 0, "\1\2", 2);
695 dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y);
696 gdk_draw_line(renderer->pixmap, renderer->gc, x, y, x + width_pixels, y);
697 return;
698 } else {
699 real adjust = 0.0;
701 adjust = text_line_get_ascent(text_line);
702 start_pos.y -= adjust;
704 dia_transform_coords(renderer->transform,
705 start_pos.x, start_pos.y, &x, &y);
707 layout = dia_font_build_layout(text, text_line->font,
708 dia_transform_length(renderer->transform, text_line->height)/20.0);
710 text_line_adjust_layout_line(text_line, pango_layout_get_line(layout, 0),
711 scale/20.0);
712 if (renderer->highlight_color != NULL) {
713 draw_highlighted_string(renderer, layout, x, y, &gdkcolor);
714 } else {
715 #if defined HAVE_FREETYPE
717 FT_Bitmap ftbitmap;
718 int width, height;
719 GdkPixbuf *rgba = NULL;
721 width = dia_transform_length(renderer->transform,
722 text_line_get_width(text_line));
723 height = dia_transform_length(renderer->transform,
724 text_line_get_height(text_line));
726 if (width > 0) {
727 int stride;
728 guchar* pixels;
729 int i,j;
730 guint8 *graybitmap;
731 FreetypeCacheData *cache;
733 initialize_ft_bitmap(&ftbitmap, width, height);
734 pango_ft2_render_layout(&ftbitmap, layout, 0, 0);
736 graybitmap = ftbitmap.buffer;
738 rgba = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
739 stride = gdk_pixbuf_get_rowstride(rgba);
740 pixels = gdk_pixbuf_get_pixels(rgba);
741 for (i = 0; i < height; i++) {
742 for (j = 0; j < width; j++) {
743 pixels[i*stride+j*4] = gdkcolor.red>>8;
744 pixels[i*stride+j*4+1] = gdkcolor.green>>8;
745 pixels[i*stride+j*4+2] = gdkcolor.blue>>8;
746 pixels[i*stride+j*4+3] = graybitmap[i*ftbitmap.pitch+j];
749 g_free(graybitmap);
751 gdk_draw_pixbuf(renderer->pixmap, renderer->gc, rgba, 0, 0, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0);
753 g_object_unref(G_OBJECT(rgba));
756 #else
757 gdk_gc_set_foreground(renderer->gc, &gdkcolor);
759 gdk_draw_layout(renderer->pixmap, renderer->gc, x, y, layout);
760 #endif
761 g_object_unref(G_OBJECT(layout));
766 /* Get the width of the given text in cm */
767 static real
768 get_text_width(DiaRenderer *object,
769 const gchar *text, int length)
771 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
772 real result;
773 TextLine *text_line;
775 if (length != strlen(text)) {
776 char *othertx;
777 int ulen;
778 /* A couple UTF8-chars: æblegrød Š Ť Ž ę ć ń уфхцНОПРЄ є Ґ Њ Ћ Џ */
779 ulen = g_utf8_offset_to_pointer(text, length)-text;
780 if (!g_utf8_validate(text, ulen, NULL)) {
781 g_warning ("Text at char %d not valid\n", length);
783 othertx = g_strndup(text, ulen);
784 text_line = text_line_new(othertx, object->font, object->font_height);
785 } else {
786 text_line = text_line_new(text, object->font, object->font_height);
788 result = text_line_get_width(text_line);
789 text_line_destroy(text_line);
790 return result;
793 static void
794 draw_image (DiaRenderer *object,
795 Point *point,
796 real width, real height,
797 DiaImage image)
799 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
800 if (renderer->highlight_color != NULL) {
801 Point lr;
802 DiaRendererClass *self_class = DIA_RENDERER_GET_CLASS (object);
804 lr = *point;
805 lr.x += width;
806 lr.y += height;
807 self_class->fill_rect(object, point, &lr, renderer->highlight_color);
808 } else {
809 int real_width, real_height, real_x, real_y;
811 real_width = dia_transform_length(renderer->transform, width);
812 real_height = dia_transform_length(renderer->transform, height);
813 dia_transform_coords(renderer->transform, point->x, point->y,
814 &real_x, &real_y);
816 dia_image_draw(image, renderer->pixmap, real_x, real_y,
817 real_width, real_height);
822 * medium level functions
824 static void
825 draw_fill_rect (DiaGdkRenderer *renderer,
826 Point *ul_corner, Point *lr_corner,
827 Color *color, gboolean fill)
829 GdkGC *gc = renderer->gc;
830 GdkColor gdkcolor;
831 gint top, bottom, left, right;
833 dia_transform_coords(renderer->transform,
834 ul_corner->x, ul_corner->y, &left, &top);
835 dia_transform_coords(renderer->transform,
836 lr_corner->x, lr_corner->y, &right, &bottom);
838 if ((left>right) || (top>bottom))
839 return;
841 renderer_color_convert(renderer, color, &gdkcolor);
842 gdk_gc_set_foreground(gc, &gdkcolor);
844 gdk_draw_rectangle (renderer->pixmap,
845 gc, fill,
846 left, top,
847 right-left,
848 bottom-top);
851 static void
852 draw_rect (DiaRenderer *object,
853 Point *ul_corner, Point *lr_corner,
854 Color *color)
856 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
858 draw_fill_rect (renderer, ul_corner, lr_corner, color, FALSE);
861 static void
862 fill_rect (DiaRenderer *object,
863 Point *ul_corner, Point *lr_corner,
864 Color *color)
866 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
868 draw_fill_rect (renderer, ul_corner, lr_corner, color, TRUE);
871 static void
872 draw_polyline (DiaRenderer *self,
873 Point *points, int num_points,
874 Color *line_color)
876 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
877 GdkGC *gc = renderer->gc;
878 GdkColor color;
879 GdkPoint *gdk_points;
880 int i,x,y;
882 gdk_points = g_new(GdkPoint, num_points);
884 for (i=0;i<num_points;i++) {
885 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
886 gdk_points[i].x = x;
887 gdk_points[i].y = y;
890 renderer_color_convert(renderer, line_color, &color);
891 gdk_gc_set_foreground(gc, &color);
893 gdk_draw_lines(renderer->pixmap, gc, gdk_points, num_points);
894 g_free(gdk_points);
897 static void
898 draw_polygon (DiaRenderer *self,
899 Point *points, int num_points,
900 Color *line_color)
902 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
903 GdkGC *gc = renderer->gc;
904 GdkColor color;
905 GdkPoint *gdk_points;
906 int i,x,y;
908 gdk_points = g_new(GdkPoint, num_points);
910 for (i=0;i<num_points;i++) {
911 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
912 gdk_points[i].x = x;
913 gdk_points[i].y = y;
916 renderer_color_convert(renderer, line_color, &color);
917 gdk_gc_set_foreground(gc, &color);
919 gdk_draw_polygon(renderer->pixmap, gc, FALSE, gdk_points, num_points);
920 g_free(gdk_points);
923 static void
924 draw_object (DiaRenderer *renderer, DiaObject *object)
926 if (renderer->is_interactive &&
927 object->highlight_color != NULL) {
928 DiaGdkRenderer *gdk_rend = DIA_GDK_RENDERER(renderer);
929 gdk_rend->highlight_color = object->highlight_color;
930 object->ops->draw(object, renderer);
931 gdk_rend->highlight_color = NULL;
933 object->ops->draw(object, renderer);
936 static int
937 get_width_pixels (DiaRenderer *object)
939 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
940 int width = 0;
942 if (renderer->pixmap)
943 gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &width, NULL);
945 return width;
948 static int
949 get_height_pixels (DiaRenderer *object)
951 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
952 int height = 0;
954 if (renderer->pixmap)
955 gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), NULL, &height);
957 return height;