* lib/text.h: Added text_get_line() declaration
[dia.git] / lib / diagdkrenderer.c
blob8ffd3b780a2803dc1c79c3381ee6badddb2d523a
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 #include <sys/time.h>
31 #define PANGO_ENABLE_ENGINE
32 #include <pango/pango-engine.h>
33 #include <pango/pango.h>
35 #include "diagdkrenderer.h"
36 #include "dia_image.h"
37 #include "message.h"
38 #include "color.h"
39 #include "font.h"
40 #include "text.h"
41 #include "object.h"
42 #include "textline.h"
44 #include "time.h"
46 #ifdef HAVE_FREETYPE
47 #include <pango/pango.h>
48 #include <pango/pangoft2.h>
49 #endif
51 static int get_width_pixels (DiaRenderer *);
52 static int get_height_pixels (DiaRenderer *);
54 static void begin_render (DiaRenderer *);
55 static void end_render (DiaRenderer *);
57 static void set_linewidth (DiaRenderer *renderer, real linewidth);
58 static void set_linecaps (DiaRenderer *renderer, LineCaps mode);
59 static void set_linejoin (DiaRenderer *renderer, LineJoin mode);
60 static void set_linestyle (DiaRenderer *renderer, LineStyle mode);
61 static void set_dashlength (DiaRenderer *renderer, real length);
62 static void set_fillstyle (DiaRenderer *renderer, FillStyle mode);
64 static void draw_line (DiaRenderer *renderer,
65 Point *start, Point *end,
66 Color *color);
67 static void fill_polygon (DiaRenderer *renderer,
68 Point *points, int num_points,
69 Color *color);
70 static void draw_arc (DiaRenderer *renderer,
71 Point *center,
72 real width, real height,
73 real angle1, real angle2,
74 Color *color);
75 static void fill_arc (DiaRenderer *renderer,
76 Point *center,
77 real width, real height,
78 real angle1, real angle2,
79 Color *color);
80 static void draw_ellipse (DiaRenderer *renderer,
81 Point *center,
82 real width, real height,
83 Color *color);
84 static void fill_ellipse (DiaRenderer *renderer,
85 Point *center,
86 real width, real height,
87 Color *color);
88 static void draw_string (DiaRenderer *renderer,
89 const gchar *text,
90 Point *pos,
91 Alignment alignment,
92 Color *color);
93 static void draw_text_line (DiaRenderer *renderer,
94 TextLine *text,
95 Point *pos,
96 Color *color);
97 static void draw_image (DiaRenderer *renderer,
98 Point *point,
99 real width, real height,
100 DiaImage image);
102 static void draw_rect (DiaRenderer *renderer,
103 Point *ul_corner, Point *lr_corner,
104 Color *color);
105 static void fill_rect (DiaRenderer *renderer,
106 Point *ul_corner, Point *lr_corner,
107 Color *color);
108 static void draw_fill_rect (DiaGdkRenderer *renderer,
109 Point *ul_corner, Point *lr_corner,
110 Color *color, gboolean fill);
111 static void draw_polyline (DiaRenderer *renderer,
112 Point *points, int num_points,
113 Color *color);
114 static void draw_polygon (DiaRenderer *renderer,
115 Point *points, int num_points,
116 Color *color);
117 static void draw_object (DiaRenderer *renderer, DiaObject *object);
119 static real get_text_width (DiaRenderer *renderer,
120 const gchar *text, int length);
122 static void dia_gdk_renderer_class_init (DiaGdkRendererClass *klass);
123 static void renderer_init (DiaGdkRenderer *renderer, void*);
125 static gpointer parent_class = NULL;
127 /** Get the type object for the GdkRenderer.
128 * @return A static GType object describing GdkRenderers.
130 GType
131 dia_gdk_renderer_get_type(void)
133 static GType object_type = 0;
135 if (!object_type)
137 static const GTypeInfo object_info =
139 sizeof (DiaGdkRendererClass),
140 (GBaseInitFunc) NULL,
141 (GBaseFinalizeFunc) NULL,
142 (GClassInitFunc) dia_gdk_renderer_class_init,
143 NULL, /* class_finalize */
144 NULL, /* class_data */
145 sizeof (DiaGdkRenderer),
146 0, /* n_preallocs */
147 (GInstanceInitFunc)renderer_init /* init */
150 object_type = g_type_register_static (DIA_TYPE_RENDERER,
151 "DiaGdkRenderer",
152 &object_info, 0);
155 return object_type;
158 /** Initialize a renderer object.
159 * @param renderer A renderer object to initialize.
160 * @param p Ignored, purpose unknown.
162 static void
163 renderer_init(DiaGdkRenderer *renderer, void* p)
165 renderer->line_width = 1;
166 renderer->line_style = GDK_LINE_SOLID;
167 renderer->cap_style = GDK_CAP_BUTT;
168 renderer->join_style = GDK_JOIN_ROUND;
170 renderer->saved_line_style = LINESTYLE_SOLID;
171 renderer->dash_length = 10;
172 renderer->dot_length = 2;
174 renderer->highlight_color = NULL;
177 /** Clean up a renderer object after use.
178 * @param object Renderer object to free subobjects from.
180 static void
181 renderer_finalize(GObject *object)
183 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
185 if (renderer->pixmap != NULL)
186 gdk_pixmap_unref(renderer->pixmap);
188 if (renderer->gc != NULL)
189 gdk_gc_unref(renderer->gc);
191 if (renderer->clip_region != NULL)
192 gdk_region_destroy(renderer->clip_region);
194 if (renderer->transform)
195 g_object_unref (renderer->transform);
197 G_OBJECT_CLASS (parent_class)->finalize (object);
200 /** Initialize members of the renderer class object. This sets up a bunch
201 * of functions to call for various render functions.
202 * @param klass The class object to initialize.
204 static void
205 dia_gdk_renderer_class_init(DiaGdkRendererClass *klass)
207 GObjectClass *object_class = G_OBJECT_CLASS (klass);
208 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
210 parent_class = g_type_class_peek_parent (klass);
212 object_class->finalize = renderer_finalize;
214 renderer_class->get_width_pixels = get_width_pixels;
215 renderer_class->get_height_pixels = get_height_pixels;
217 renderer_class->begin_render = begin_render;
218 renderer_class->end_render = end_render;
220 renderer_class->set_linewidth = set_linewidth;
221 renderer_class->set_linecaps = set_linecaps;
222 renderer_class->set_linejoin = set_linejoin;
223 renderer_class->set_linestyle = set_linestyle;
224 renderer_class->set_dashlength = set_dashlength;
225 renderer_class->set_fillstyle = set_fillstyle;
227 renderer_class->draw_line = draw_line;
228 renderer_class->fill_polygon = fill_polygon;
229 renderer_class->draw_rect = draw_rect;
230 renderer_class->fill_rect = fill_rect;
231 renderer_class->draw_arc = draw_arc;
232 renderer_class->fill_arc = fill_arc;
233 renderer_class->draw_ellipse = draw_ellipse;
234 renderer_class->fill_ellipse = fill_ellipse;
236 /* use <draw|fill>_bezier from DiaRenderer */
238 renderer_class->draw_string = draw_string;
239 renderer_class->draw_text_line = draw_text_line;
240 renderer_class->draw_image = draw_image;
242 /* medium level functions */
243 renderer_class->draw_rect = draw_rect;
244 renderer_class->draw_polyline = draw_polyline;
245 renderer_class->draw_polygon = draw_polygon;
246 renderer_class->draw_object = draw_object;
248 /* Interactive functions */
249 renderer_class->get_text_width = get_text_width;
252 /** Convert Dia color objects into GDK color objects.
253 * If the highlight color is set, that will be used instead. This allows
254 * rendering of an object to do highlight rendering.
255 * @param renderer The renderer to check for highlight color.
256 * @param col A color object to convert.
257 * @param gdk_col Resulting GDK convert.
259 static void
260 renderer_color_convert(DiaGdkRenderer *renderer,
261 Color *col, GdkColor *gdk_col)
263 if (renderer->highlight_color != NULL) {
264 color_convert(renderer->highlight_color, gdk_col);
265 } else {
266 color_convert(col, gdk_col);
270 static void
271 begin_render (DiaRenderer *object)
275 static void
276 end_render (DiaRenderer *object)
280 static void
281 set_linewidth (DiaRenderer *object, real linewidth)
283 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
285 if (renderer->highlight_color != NULL) {
286 /* 6 pixels wide -> 3 pixels beyond normal obj */
287 real border = dia_untransform_length(renderer->transform, 6);
288 linewidth += border;
291 /* 0 == hairline **/
292 renderer->line_width =
293 dia_transform_length(renderer->transform, linewidth);
295 if (renderer->line_width<=0)
296 renderer->line_width = 1; /* Minimum 1 pixel. */
298 gdk_gc_set_line_attributes(renderer->gc,
299 renderer->line_width,
300 renderer->line_style,
301 renderer->cap_style,
302 renderer->join_style);
305 static void
306 set_linecaps (DiaRenderer *object, LineCaps mode)
308 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
310 if (renderer->highlight_color != NULL) {
311 renderer->cap_style = GDK_CAP_ROUND;
312 } else {
313 switch(mode) {
314 case LINECAPS_BUTT:
315 renderer->cap_style = GDK_CAP_BUTT;
316 break;
317 case LINECAPS_ROUND:
318 renderer->cap_style = GDK_CAP_ROUND;
319 break;
320 case LINECAPS_PROJECTING:
321 renderer->cap_style = GDK_CAP_PROJECTING;
322 break;
326 gdk_gc_set_line_attributes(renderer->gc,
327 renderer->line_width,
328 renderer->line_style,
329 renderer->cap_style,
330 renderer->join_style);
333 static void
334 set_linejoin (DiaRenderer *object, LineJoin mode)
336 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
338 if (renderer->highlight_color != NULL) {
339 renderer->join_style = GDK_JOIN_ROUND;
340 } else {
341 switch(mode) {
342 case LINEJOIN_MITER:
343 renderer->join_style = GDK_JOIN_MITER;
344 break;
345 case LINEJOIN_ROUND:
346 renderer->join_style = GDK_JOIN_ROUND;
347 break;
348 case LINEJOIN_BEVEL:
349 renderer->join_style = GDK_JOIN_BEVEL;
350 break;
351 default :
352 /* invalid mode, just here to set a breakpoint */
353 renderer->join_style = GDK_JOIN_ROUND;
354 break;
358 gdk_gc_set_line_attributes(renderer->gc,
359 renderer->line_width,
360 renderer->line_style,
361 renderer->cap_style,
362 renderer->join_style);
365 /** Set the dashes for this renderer.
366 * offset determines where in the pattern the dashes will start.
367 * It is used by the grid in particular to make the grid dashes line up.
369 void
370 dia_gdk_renderer_set_dashes(DiaGdkRenderer *renderer, int offset)
372 gint8 dash_list[6];
373 int hole_width;
374 int pattern_length;
376 switch(renderer->saved_line_style) {
377 case LINESTYLE_SOLID:
378 break;
379 case LINESTYLE_DASHED:
380 dash_list[0] = renderer->dash_length;
381 dash_list[1] = renderer->dash_length;
382 pattern_length = renderer->dash_length*2;
383 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2);
384 break;
385 case LINESTYLE_DASH_DOT:
386 hole_width = (renderer->dash_length - renderer->dot_length) / 2;
387 if (hole_width==0)
388 hole_width = 1;
389 dash_list[0] = renderer->dash_length;
390 dash_list[1] = hole_width;
391 dash_list[2] = renderer->dot_length;
392 dash_list[3] = hole_width;
393 pattern_length = renderer->dash_length+renderer->dot_length+2*hole_width;
394 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 4);
395 break;
396 case LINESTYLE_DASH_DOT_DOT:
397 hole_width = (renderer->dash_length - 2*renderer->dot_length) / 3;
398 if (hole_width==0)
399 hole_width = 1;
400 dash_list[0] = renderer->dash_length;
401 dash_list[1] = hole_width;
402 dash_list[2] = renderer->dot_length;
403 dash_list[3] = hole_width;
404 dash_list[4] = renderer->dot_length;
405 dash_list[5] = hole_width;
406 pattern_length = renderer->dash_length+2*renderer->dot_length+3*hole_width;
407 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 6);
408 break;
409 case LINESTYLE_DOTTED:
410 dash_list[0] = renderer->dot_length;
411 dash_list[1] = renderer->dot_length;
412 pattern_length = renderer->dot_length;
413 gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2);
414 break;
419 static void
420 set_linestyle (DiaRenderer *object, LineStyle mode)
422 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
424 renderer->saved_line_style = mode;
425 switch(mode) {
426 case LINESTYLE_SOLID:
427 renderer->line_style = GDK_LINE_SOLID;
428 break;
429 case LINESTYLE_DASHED:
430 renderer->line_style = GDK_LINE_ON_OFF_DASH;
431 dia_gdk_renderer_set_dashes(renderer, 0);
432 break;
433 case LINESTYLE_DASH_DOT:
434 renderer->line_style = GDK_LINE_ON_OFF_DASH;
435 dia_gdk_renderer_set_dashes(renderer, 0);
436 break;
437 case LINESTYLE_DASH_DOT_DOT:
438 renderer->line_style = GDK_LINE_ON_OFF_DASH;
439 dia_gdk_renderer_set_dashes(renderer, 0);
440 break;
441 case LINESTYLE_DOTTED:
442 renderer->line_style = GDK_LINE_ON_OFF_DASH;
443 dia_gdk_renderer_set_dashes(renderer, 0);
444 break;
446 gdk_gc_set_line_attributes(renderer->gc,
447 renderer->line_width,
448 renderer->line_style,
449 renderer->cap_style,
450 renderer->join_style);
453 static void
454 set_dashlength (DiaRenderer *object, real length)
456 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
457 /* dot = 10% of len */
458 real ddisp_len;
460 ddisp_len =
461 dia_transform_length(renderer->transform, length);
463 renderer->dash_length = (int)floor(ddisp_len+0.5);
464 renderer->dot_length = (int)floor(ddisp_len*0.1+0.5);
466 if (renderer->dash_length<=0)
467 renderer->dash_length = 1;
468 if (renderer->dash_length>255)
469 renderer->dash_length = 255;
470 if (renderer->dot_length<=0)
471 renderer->dot_length = 1;
472 if (renderer->dot_length>255)
473 renderer->dot_length = 255;
474 set_linestyle(object, renderer->saved_line_style);
477 static void
478 set_fillstyle (DiaRenderer *object, FillStyle mode)
480 switch(mode) {
481 case FILLSTYLE_SOLID:
482 break;
483 default:
484 message_error("gdk_renderer: Unsupported fill mode specified!\n");
488 static void
489 draw_line (DiaRenderer *object, Point *start, Point *end, Color *line_color)
491 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
493 GdkGC *gc = renderer->gc;
494 GdkColor color;
495 int x1,y1,x2,y2;
497 dia_transform_coords(renderer->transform, start->x, start->y, &x1, &y1);
498 dia_transform_coords(renderer->transform, end->x, end->y, &x2, &y2);
500 renderer_color_convert(renderer, line_color, &color);
501 gdk_gc_set_foreground(gc, &color);
503 gdk_draw_line(renderer->pixmap, gc,
504 x1, y1, x2, y2);
507 static void
508 fill_polygon (DiaRenderer *object, Point *points, int num_points, Color *line_color)
510 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
511 GdkGC *gc = renderer->gc;
512 GdkColor color;
513 GdkPoint *gdk_points;
514 int i,x,y;
516 gdk_points = g_new(GdkPoint, num_points);
518 for (i=0;i<num_points;i++) {
519 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
520 gdk_points[i].x = x;
521 gdk_points[i].y = y;
524 renderer_color_convert(renderer, line_color, &color);
525 gdk_gc_set_foreground(gc, &color);
527 gdk_draw_polygon(renderer->pixmap, gc, TRUE, gdk_points, num_points);
528 g_free(gdk_points);
531 static void
532 draw_fill_arc (DiaRenderer *object,
533 Point *center,
534 real width, real height,
535 real angle1, real angle2,
536 Color *color,
537 gboolean fill)
539 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
540 GdkGC *gc = renderer->gc;
541 GdkColor gdkcolor;
542 gint top, left, bottom, right;
543 real dangle;
545 dia_transform_coords(renderer->transform,
546 center->x - width/2, center->y - height/2,
547 &left, &top);
548 dia_transform_coords(renderer->transform,
549 center->x + width/2, center->y + height/2,
550 &right, &bottom);
552 if ((left>right) || (top>bottom))
553 return;
555 renderer_color_convert(renderer, color, &gdkcolor);
556 gdk_gc_set_foreground(gc, &gdkcolor);
558 dangle = angle2-angle1;
559 if (dangle<0)
560 dangle += 360.0;
562 gdk_draw_arc(renderer->pixmap,
563 gc, fill,
564 left, top, right-left+(fill?1:0), bottom-top+(fill?1:0),
565 (int) (angle1*64.0), (int) (dangle*64.0));
567 static void
568 draw_arc (DiaRenderer *object,
569 Point *center,
570 real width, real height,
571 real angle1, real angle2,
572 Color *color)
574 draw_fill_arc (object, center, width, height, angle1, angle2, color, FALSE);
577 static void
578 fill_arc (DiaRenderer *object, Point *center,
579 real width, real height, real angle1, real angle2,
580 Color *color)
582 draw_fill_arc (object, center, width, height, angle1, angle2, color, TRUE);
585 static void
586 draw_ellipse (DiaRenderer *object, Point *center,
587 real width, real height,
588 Color *color)
590 draw_arc(object, center, width, height, 0.0, 360.0, color);
593 static void
594 fill_ellipse (DiaRenderer *object, Point *center,
595 real width, real height, Color *color)
597 fill_arc(object, center, width, height, 0.0, 360.0, color);
600 /* Draw a highlighted version of a string.
602 static void
603 draw_highlighted_string(DiaGdkRenderer *renderer,
604 PangoLayout *layout,
605 int x, int y,
606 GdkColor *color)
608 gint width, height;
610 pango_layout_get_pixel_size(layout, &width, &height);
612 gdk_gc_set_foreground(renderer->gc, color);
614 gdk_draw_rectangle (renderer->pixmap,
615 renderer->gc, TRUE,
616 x-3, y-3,
617 width+6, height+6);
620 static void
621 draw_string (DiaRenderer *object,
622 const gchar *text, Point *pos, Alignment alignment,
623 Color *color)
625 TextLine *text_line = text_line_new(text, object->font, object->font_height);
626 Point realigned_pos = *pos;
627 realigned_pos.x -= text_line_get_alignment_adjustment(text_line, alignment);
628 draw_text_line(object, text_line, &realigned_pos, color);
631 #ifdef HAVE_FREETYPE
632 static void
633 initialize_ft_bitmap(FT_Bitmap *ftbitmap, int width, int height)
635 int rowstride = 32*((width+31)/31);
636 guint8 *graybitmap = (guint8*)g_new0(guint8, height*rowstride);
638 ftbitmap->rows = height;
639 ftbitmap->width = width;
640 ftbitmap->pitch = rowstride;
641 ftbitmap->buffer = graybitmap;
642 ftbitmap->num_grays = 256;
643 ftbitmap->pixel_mode = ft_pixel_mode_grays;
644 ftbitmap->palette_mode = 0;
645 ftbitmap->palette = 0;
648 typedef struct _FreetypeCacheData {
649 int x;
650 int y;
651 int width;
652 int height;
653 GdkPixbuf *rgba;
654 } FreetypeCacheData;
656 static void
657 free_freetype_cache_data(gpointer data) {
658 FreetypeCacheData *ftdata = (FreetypeCacheData*) data;
660 g_object_unref(ftdata->rgba);
661 g_free(ftdata);
663 #endif
665 /** Draw a TextLine object.
666 * @param object The renderer object to use for transform and output
667 * @param text_line The TextLine to render, including font and height.
668 * @param pos The position to render it at.
669 * @param color The color to render it with.
671 static void
672 draw_text_line (DiaRenderer *object, TextLine *text_line,
673 Point *pos, Color *color)
675 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
676 GdkColor gdkcolor;
677 int x,y;
678 Point start_pos;
679 PangoLayout* layout = NULL;
680 const gchar *text = text_line_get_string(text_line);
681 int height_pixels;
682 real font_height = text_line_get_height(text_line);
683 real scale = dia_transform_length(renderer->transform, 1.0);
685 if (text == NULL || *text == '\0') return; /* Don't render empty strings. */
687 point_copy(&start_pos,pos);
689 renderer_color_convert(renderer, color, &gdkcolor);
691 height_pixels = dia_transform_length(renderer->transform, font_height);
692 if (height_pixels < 2) { /* "Greeking" instead of making tiny font */
693 int width_pixels = dia_transform_length(renderer->transform,
694 text_line_get_width(text_line));
695 gdk_gc_set_foreground(renderer->gc, &gdkcolor);
696 gdk_gc_set_dashes(renderer->gc, 0, "\1\2", 2);
697 dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y);
698 gdk_draw_line(renderer->pixmap, renderer->gc, x, y, x + width_pixels, y);
699 return;
700 } else {
701 real adjust = 0.0;
703 adjust = text_line_get_ascent(text_line);
704 start_pos.y -= adjust;
706 dia_transform_coords(renderer->transform,
707 start_pos.x, start_pos.y, &x, &y);
709 #ifdef HAVE_FREETYPE
710 /* The cache appears to work, but there's no gain from it yet, since
711 * nobody hangs on to textline objects long enough.
713 #ifdef USE_TEXTLINE_CACHE
714 FreetypeCacheData *cache = text_line_get_renderer_cache(text_line,
715 object,
716 scale);
717 if (cache != NULL) {
718 gdk_draw_pixbuf(renderer->pixmap, renderer->gc, cache->rgba,
719 0, 0, x, y,
720 cache->width, cache->height, GDK_RGB_DITHER_NONE, 0, 0);
721 return;
723 #endif
724 #endif
726 layout = dia_font_build_layout(text, text_line->font,
727 dia_transform_length(renderer->transform, text_line->height)/20.0);
729 text_line_adjust_layout_line(text_line, pango_layout_get_line(layout, 0),
730 scale/20.0);
731 if (renderer->highlight_color != NULL) {
732 draw_highlighted_string(renderer, layout, x, y, &gdkcolor);
733 } else {
734 #if defined HAVE_FREETYPE
736 FT_Bitmap ftbitmap;
737 int width, height;
738 GdkPixbuf *rgba = NULL;
740 width = dia_transform_length(renderer->transform,
741 text_line_get_width(text_line));
742 height = dia_transform_length(renderer->transform,
743 text_line_get_height(text_line));
745 if (width > 0) {
746 int stride;
747 guchar* pixels;
748 int i,j;
749 guint8 *graybitmap;
750 FreetypeCacheData *cache;
752 initialize_ft_bitmap(&ftbitmap, width, height);
753 pango_ft2_render_layout(&ftbitmap, layout, 0, 0);
755 graybitmap = ftbitmap.buffer;
757 rgba = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
758 stride = gdk_pixbuf_get_rowstride(rgba);
759 pixels = gdk_pixbuf_get_pixels(rgba);
760 for (i = 0; i < height; i++) {
761 for (j = 0; j < width; j++) {
762 pixels[i*stride+j*4] = gdkcolor.red>>8;
763 pixels[i*stride+j*4+1] = gdkcolor.green>>8;
764 pixels[i*stride+j*4+2] = gdkcolor.blue>>8;
765 pixels[i*stride+j*4+3] = graybitmap[i*ftbitmap.pitch+j];
768 g_free(graybitmap);
770 gdk_draw_pixbuf(renderer->pixmap, renderer->gc, rgba, 0, 0, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0);
771 #ifdef USE_TEXTLINE_CACHE
772 /* This is not exactly useful until textline objects start hanging
773 * around longer than the duration of draw_string(). Nor is it
774 * entirely debugged (i.e. it crashes:)
776 cache = g_new(FreetypeCacheData, 1);
777 cache->rgba = rgba;
778 cache->width = width;
779 cache->height = height;
780 text_line_set_renderer_cache(text_line, object,
781 free_freetype_cache_data, scale, cache);
782 #else
783 g_object_unref(G_OBJECT(rgba));
784 #endif
787 #else
788 gdk_gc_set_foreground(renderer->gc, &gdkcolor);
790 gdk_draw_layout(renderer->pixmap, renderer->gc, x, y, layout);
791 #endif
792 g_object_unref(G_OBJECT(layout));
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;
804 TextLine *text_line;
806 if (length != strlen(text)) {
807 char *othertx;
808 int ulen;
809 /* A couple UTF8-chars: æblegrød Š Ť Ž ę ć ń уфхцНОПРЄ є Ґ Њ Ћ Џ */
810 ulen = g_utf8_offset_to_pointer(text, length)-text;
811 if (!g_utf8_validate(text, ulen, NULL)) {
812 g_warning ("Text at char %d not valid\n", length);
814 othertx = g_strndup(text, ulen);
815 text_line = text_line_new(othertx, object->font, object->font_height);
816 } else {
817 text_line = text_line_new(text, object->font, object->font_height);
819 result = text_line_get_width(text_line);
820 text_line_destroy(text_line);
821 return result;
824 static void
825 draw_image (DiaRenderer *object,
826 Point *point,
827 real width, real height,
828 DiaImage image)
830 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
831 if (renderer->highlight_color != NULL) {
832 Point lr;
833 DiaRendererClass *self_class = DIA_RENDERER_GET_CLASS (object);
835 lr = *point;
836 lr.x += width;
837 lr.y += height;
838 self_class->fill_rect(object, point, &lr, renderer->highlight_color);
839 } else {
840 int real_width, real_height, real_x, real_y;
842 real_width = dia_transform_length(renderer->transform, width);
843 real_height = dia_transform_length(renderer->transform, height);
844 dia_transform_coords(renderer->transform, point->x, point->y,
845 &real_x, &real_y);
847 dia_image_draw(image, renderer->pixmap, real_x, real_y,
848 real_width, real_height);
853 * medium level functions
855 static void
856 draw_fill_rect (DiaGdkRenderer *renderer,
857 Point *ul_corner, Point *lr_corner,
858 Color *color, gboolean fill)
860 GdkGC *gc = renderer->gc;
861 GdkColor gdkcolor;
862 gint top, bottom, left, right;
864 dia_transform_coords(renderer->transform,
865 ul_corner->x, ul_corner->y, &left, &top);
866 dia_transform_coords(renderer->transform,
867 lr_corner->x, lr_corner->y, &right, &bottom);
869 if ((left>right) || (top>bottom))
870 return;
872 renderer_color_convert(renderer, color, &gdkcolor);
873 gdk_gc_set_foreground(gc, &gdkcolor);
875 gdk_draw_rectangle (renderer->pixmap,
876 gc, fill,
877 left, top,
878 right-left,
879 bottom-top);
882 static void
883 draw_rect (DiaRenderer *object,
884 Point *ul_corner, Point *lr_corner,
885 Color *color)
887 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
889 draw_fill_rect (renderer, ul_corner, lr_corner, color, FALSE);
892 static void
893 fill_rect (DiaRenderer *object,
894 Point *ul_corner, Point *lr_corner,
895 Color *color)
897 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
899 draw_fill_rect (renderer, ul_corner, lr_corner, color, TRUE);
902 static void
903 draw_polyline (DiaRenderer *self,
904 Point *points, int num_points,
905 Color *line_color)
907 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
908 GdkGC *gc = renderer->gc;
909 GdkColor color;
910 GdkPoint *gdk_points;
911 int i,x,y;
913 gdk_points = g_new(GdkPoint, num_points);
915 for (i=0;i<num_points;i++) {
916 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
917 gdk_points[i].x = x;
918 gdk_points[i].y = y;
921 renderer_color_convert(renderer, line_color, &color);
922 gdk_gc_set_foreground(gc, &color);
924 gdk_draw_lines(renderer->pixmap, gc, gdk_points, num_points);
925 g_free(gdk_points);
928 static void
929 draw_polygon (DiaRenderer *self,
930 Point *points, int num_points,
931 Color *line_color)
933 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
934 GdkGC *gc = renderer->gc;
935 GdkColor color;
936 GdkPoint *gdk_points;
937 int i,x,y;
939 gdk_points = g_new(GdkPoint, num_points);
941 for (i=0;i<num_points;i++) {
942 dia_transform_coords(renderer->transform, points[i].x, points[i].y, &x, &y);
943 gdk_points[i].x = x;
944 gdk_points[i].y = y;
947 renderer_color_convert(renderer, line_color, &color);
948 gdk_gc_set_foreground(gc, &color);
950 gdk_draw_polygon(renderer->pixmap, gc, FALSE, gdk_points, num_points);
951 g_free(gdk_points);
954 static void
955 draw_object (DiaRenderer *renderer, DiaObject *object)
957 if (renderer->is_interactive &&
958 object->highlight_color != NULL) {
959 DiaGdkRenderer *gdk_rend = DIA_GDK_RENDERER(renderer);
960 gdk_rend->highlight_color = object->highlight_color;
961 object->ops->draw(object, renderer);
962 gdk_rend->highlight_color = NULL;
964 object->ops->draw(object, renderer);
967 static int
968 get_width_pixels (DiaRenderer *object)
970 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
971 int width = 0;
973 if (renderer->pixmap)
974 gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &width, NULL);
976 return width;
979 static int
980 get_height_pixels (DiaRenderer *object)
982 DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
983 int height = 0;
985 if (renderer->pixmap)
986 gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), NULL, &height);
988 return height;