1 /****************************************************************************
2 * RRDtool 1.2.99907080300 Copyright by Tobi Oetiker, 1997-2007
3 ****************************************************************************
4 * rrd_gfx.c graphics wrapper for rrdtool
5 **************************************************************************/
7 /* #define DEBUG */
9 /* stupid MSVC doesnt support variadic macros = no debug for now! */
10 #ifdef _MSC_VER
11 # define RRDPRINTF()
12 #else
13 # ifdef DEBUG
14 # define RRDPRINTF(...) fprintf(stderr, __VA_ARGS__);
15 # else
16 # define RRDPRINTF(...)
17 # endif /* DEBUG */
18 #endif /* _MSC_VER */
20 #include "rrd_tool.h"
21 #include "rrd_graph.h"
24 /* create a new line */
25 void gfx_line(
26 image_desc_t *im,
27 double X0,
28 double Y0,
29 double X1,
30 double Y1,
31 double width,
32 gfx_color_t color)
33 {
34 gfx_dashed_line(im, X0, Y0, X1, Y1, width, color, 0, 0);
35 }
37 void gfx_dashed_line(
38 image_desc_t *im,
39 double X0,
40 double Y0,
41 double X1,
42 double Y1,
43 double width,
44 gfx_color_t color,
45 double dash_on,
46 double dash_off)
47 {
48 cairo_t *cr = im->cr;
49 double dashes[] = { dash_on, dash_off };
50 double x = 0;
51 double y = 0;
53 cairo_save(cr);
54 cairo_new_path(cr);
55 cairo_set_line_width(cr, width);
56 gfx_line_fit(im, &x, &y);
57 gfx_line_fit(im, &X0, &Y0);
58 cairo_move_to(cr, X0, Y0);
59 gfx_line_fit(im, &X1, &Y1);
60 cairo_line_to(cr, X1, Y1);
61 if (dash_on > 0 || dash_off > 0)
62 cairo_set_dash(cr, dashes, 2, x);
63 cairo_set_source_rgba(cr, color.red, color.green, color.blue,
64 color.alpha);
65 cairo_stroke(cr);
66 cairo_restore(cr);
67 }
69 /* create a new area */
70 void gfx_new_area(
71 image_desc_t *im,
72 double X0,
73 double Y0,
74 double X1,
75 double Y1,
76 double X2,
77 double Y2,
78 gfx_color_t color)
79 {
80 cairo_t *cr = im->cr;
82 cairo_new_path(cr);
83 gfx_area_fit(im, &X0, &Y0);
84 cairo_move_to(cr, X0, Y0);
85 gfx_area_fit(im, &X1, &Y1);
86 cairo_line_to(cr, X1, Y1);
87 gfx_area_fit(im, &X2, &Y2);
88 cairo_line_to(cr, X2, Y2);
89 cairo_set_source_rgba(cr, color.red, color.green, color.blue,
90 color.alpha);
91 }
93 /* add a point to a line or to an area */
94 void gfx_add_point(
95 image_desc_t *im,
96 double x,
97 double y)
98 {
99 cairo_t *cr = im->cr;
101 gfx_area_fit(im, &x, &y);
102 cairo_line_to(cr, x, y);
103 }
105 void gfx_close_path(
106 image_desc_t *im)
107 {
108 cairo_t *cr = im->cr;
110 cairo_close_path(cr);
111 cairo_fill(cr);
112 }
114 /* create a text node */
115 static PangoLayout *gfx_prep_text(
116 image_desc_t *im,
117 double x,
118 gfx_color_t color,
119 char *font,
120 double size,
121 double tabwidth,
122 const char *text)
123 {
124 PangoLayout *layout;
125 PangoFontDescription *font_desc;
126 cairo_t *cr = im->cr;
128 /* for performance reasons we might
129 want todo that only once ... tabs will always
130 be the same */
131 long i;
132 long tab_count = strlen(text);
133 long tab_shift = fmod(x, tabwidth);
135 PangoTabArray *tab_array;
136 PangoContext *pango_context;
138 tab_array = pango_tab_array_new(tab_count, (gboolean) (1));
139 for (i = 1; i <= tab_count; i++) {
140 pango_tab_array_set_tab(tab_array,
141 i, PANGO_TAB_LEFT, tabwidth * i - tab_shift);
142 }
143 cairo_new_path(cr);
144 cairo_set_source_rgba(cr, color.red, color.green, color.blue,
145 color.alpha);
146 layout = pango_cairo_create_layout(cr);
147 pango_context = pango_layout_get_context(layout);
148 pango_cairo_context_set_font_options(pango_context, im->font_options);
149 pango_cairo_context_set_resolution(pango_context, 100);
151 /* pango_cairo_update_context(cr, pango_context); */
153 pango_layout_set_tabs(layout, tab_array);
154 font_desc = pango_font_description_from_string(font);
155 pango_font_description_set_size(font_desc, size * PANGO_SCALE);
156 pango_layout_set_font_description(layout, font_desc);
157 pango_layout_set_markup(layout, text, -1);
158 return layout;
159 }
161 /* Size Text Node */
162 double gfx_get_text_width(
163 image_desc_t *im,
164 double start,
165 char *font,
166 double size,
167 double tabwidth,
168 char *text)
169 {
170 PangoLayout *layout;
171 PangoRectangle log_rect;
172 gfx_color_t color = { 0, 0, 0, 0 };
173 char *tab;
175 /* turn \\t into tab */
176 while ((tab = strstr(text, "\\t"))) {
177 memmove(tab + 1, tab + 2, strlen(tab + 2));
178 tab[0] = (char) 9;
179 }
180 layout = gfx_prep_text(im, start, color, font, size, tabwidth, text);
181 pango_layout_get_pixel_extents(layout, NULL, &log_rect);
182 pango_tab_array_free(pango_layout_get_tabs(layout));
183 g_object_unref(layout);
184 return log_rect.width;
185 }
187 void gfx_text(
188 image_desc_t *im,
189 double x,
190 double y,
191 gfx_color_t color,
192 char *font,
193 double size,
194 double tabwidth,
195 double angle,
196 enum gfx_h_align_en h_align,
197 enum gfx_v_align_en v_align,
198 const char *text)
199 {
200 PangoLayout *layout;
201 PangoRectangle log_rect;
202 PangoRectangle ink_rect;
203 cairo_t *cr = im->cr;
204 double sx = 0;
205 double sy = 0;
207 cairo_save(cr);
208 cairo_translate(cr, x, y);
209 /* gfx_line(cr,-2,0,2,0,1,color);
210 gfx_line(cr,0,-2,0,2,1,color); */
211 layout = gfx_prep_text(im, x, color, font, size, tabwidth, text);
212 pango_layout_get_pixel_extents(layout, &ink_rect, &log_rect);
213 cairo_rotate(cr, -angle * G_PI / 180.0);
214 sx = log_rect.x;
215 switch (h_align) {
216 case GFX_H_RIGHT:
217 sx -= log_rect.width;
218 break;
219 case GFX_H_CENTER:
220 sx -= log_rect.width / 2;
221 break;
222 case GFX_H_LEFT:
223 break;
224 case GFX_H_NULL:
225 break;
226 }
227 sy = log_rect.y;
228 switch (v_align) {
229 case GFX_V_TOP:
230 break;
231 case GFX_V_CENTER:
232 sy -= log_rect.height / 2;
233 break;
234 case GFX_V_BOTTOM:
235 sy -= log_rect.height;
236 break;
237 case GFX_V_NULL:
238 break;
239 }
240 pango_cairo_update_layout(cr, layout);
241 cairo_move_to(cr, sx, sy);
242 pango_cairo_show_layout(cr, layout);
243 pango_tab_array_free(pango_layout_get_tabs(layout));
244 g_object_unref(layout);
245 cairo_restore(cr);
247 }
249 /* convert color */
250 struct gfx_color_t gfx_hex_to_col(
251 long unsigned int color)
252 {
253 struct gfx_color_t gfx_color;
255 gfx_color.red = 1.0 / 255.0 * ((color & 0xff000000) >> (3 * 8));
256 gfx_color.green = 1.0 / 255.0 * ((color & 0x00ff0000) >> (2 * 8));
257 gfx_color.blue = 1.0 / 255.0 * ((color & 0x0000ff00) >> (1 * 8));
258 gfx_color.alpha = 1.0 / 255.0 * (color & 0x000000ff);
259 return gfx_color;
260 }
262 /* gridfit_lines */
264 void gfx_line_fit(
265 image_desc_t *im,
266 double *x,
267 double *y)
268 {
269 cairo_t *cr = im->cr;
270 double line_width;
271 double line_height;
273 if (!im->gridfit)
274 return;
275 cairo_user_to_device(cr, x, y);
276 line_width = cairo_get_line_width(cr);
277 line_height = line_width;
278 cairo_user_to_device_distance(cr, &line_width, &line_height);
279 line_width = line_width / 2.0 - (long) (line_width / 2.0);
280 line_height = line_height / 2.0 - (long) (line_height / 2.0);
281 *x = (double) ((long) (*x + 0.5)) - line_width;
282 *y = (double) ((long) (*y + 0.5)) + line_height;
283 cairo_device_to_user(cr, x, y);
284 }
286 /* gridfit_areas */
288 void gfx_area_fit(
289 image_desc_t *im,
290 double *x,
291 double *y)
292 {
293 cairo_t *cr = im->cr;
295 if (!im->gridfit)
296 return;
297 cairo_user_to_device(cr, x, y);
298 *x = (double) ((long) (*x + 0.5));
299 *y = (double) ((long) (*y + 0.5));
300 cairo_device_to_user(cr, x, y);
301 }