1 /****************************************************************************
2 * RRDtool 1.2.23 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_gfx.h"
24 /* create a new line */
25 void gfx_line(
26 cairo_t * cr,
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(cr, X0, Y0, X1, Y1, width, color, 0, 0);
35 }
37 void gfx_dashed_line(
38 cairo_t * cr,
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 double dashes[] = { dash_on, dash_off };
49 double x = 0;
50 double y = 0;
52 cairo_save(cr);
53 cairo_new_path(cr);
54 cairo_set_line_width(cr, width);
55 gfx_line_fit(cr, &x, &y);
56 gfx_line_fit(cr, &X0, &Y0);
57 cairo_move_to(cr, X0, Y0);
58 gfx_line_fit(cr, &X1, &Y1);
59 cairo_line_to(cr, X1, Y1);
60 if (dash_on > 0 || dash_off > 0)
61 cairo_set_dash(cr, dashes, 2, x);
62 cairo_set_source_rgba(cr, color.red, color.green, color.blue,
63 color.alpha);
64 cairo_stroke(cr);
65 cairo_restore(cr);
66 }
68 /* create a new area */
69 void gfx_new_area(
70 cairo_t * cr,
71 double X0,
72 double Y0,
73 double X1,
74 double Y1,
75 double X2,
76 double Y2,
77 gfx_color_t color)
78 {
79 cairo_new_path(cr);
80 gfx_area_fit(cr, &X0, &Y0);
81 cairo_move_to(cr, X0, Y0);
82 gfx_area_fit(cr, &X1, &Y1);
83 cairo_line_to(cr, X1, Y1);
84 gfx_area_fit(cr, &X2, &Y2);
85 cairo_line_to(cr, X2, Y2);
86 cairo_set_source_rgba(cr, color.red, color.green, color.blue,
87 color.alpha);
88 }
90 /* add a point to a line or to an area */
91 void gfx_add_point(
92 cairo_t * cr,
93 double x,
94 double y)
95 {
96 gfx_area_fit(cr, &x, &y);
97 cairo_line_to(cr, x, y);
98 }
100 void gfx_close_path(
101 cairo_t * cr)
102 {
103 cairo_close_path(cr);
104 cairo_fill(cr);
105 }
107 /* create a text node */
108 static PangoLayout *gfx_prep_text(
109 cairo_t * cr,
110 double x,
111 gfx_color_t color,
112 char *font,
113 double size,
114 double tabwidth,
115 const char *text)
116 {
117 PangoLayout *layout;
118 PangoFontDescription *font_desc;
120 /* for performance reasons we might
121 want todo that only once ... tabs will always
122 be the same */
123 long i;
124 long tab_count = strlen(text);
125 long tab_shift = fmod(x, tabwidth);
127 PangoTabArray *tab_array;
129 tab_array = pango_tab_array_new(tab_count, (gboolean) (1));
130 for (i = 1; i <= tab_count; i++) {
131 pango_tab_array_set_tab(tab_array,
132 i, PANGO_TAB_LEFT, tabwidth * i - tab_shift);
133 }
134 cairo_new_path(cr);
135 cairo_set_source_rgba(cr, color.red, color.green, color.blue,
136 color.alpha);
137 layout = pango_cairo_create_layout(cr);
139 pango_layout_set_tabs(layout, tab_array);
140 font_desc = pango_font_description_from_string(font);
141 pango_font_description_set_size(font_desc, size * PANGO_SCALE);
142 pango_layout_set_font_description(layout, font_desc);
143 pango_layout_set_markup(layout, text, -1);
144 return layout;
145 }
147 /* Size Text Node */
148 double gfx_get_text_width(
149 cairo_t * cr,
150 double start,
151 char *font,
152 double size,
153 double tabwidth,
154 char *text)
155 {
156 PangoLayout *layout;
157 PangoRectangle log_rect;
158 gfx_color_t color = { 0, 0, 0, 0 };
159 char *tab;
161 /* turn \\t into tab */
162 while (tab = strstr(text, "\\t")) {
163 memmove(tab + 1, tab + 2, strlen(tab + 2));
164 tab[0] = (char) 9;
165 }
166 layout = gfx_prep_text(cr, start, color, font, size, tabwidth, text);
167 pango_layout_get_pixel_extents(layout, NULL, &log_rect);
168 pango_tab_array_free(pango_layout_get_tabs(layout));
169 g_object_unref(layout);
170 return log_rect.width;
171 }
173 void gfx_text(
174 cairo_t * cr,
175 double x,
176 double y,
177 gfx_color_t color,
178 char *font,
179 double size,
180 double tabwidth,
181 double angle,
182 enum gfx_h_align_en h_align,
183 enum gfx_v_align_en v_align,
184 const char *text)
185 {
186 PangoLayout *layout;
187 PangoRectangle log_rect;
188 PangoRectangle ink_rect;
189 double sx = 0;
190 double sy = 0;
192 cairo_save(cr);
193 cairo_translate(cr, x, y);
194 /* gfx_line(cr,-2,0,2,0,1,color);
195 gfx_line(cr,0,-2,0,2,1,color); */
196 layout = gfx_prep_text(cr, x, color, font, size, tabwidth, text);
197 pango_layout_get_pixel_extents(layout, &ink_rect, &log_rect);
198 cairo_rotate(cr, -angle * G_PI / 180.0);
199 sx = log_rect.x;
200 sy = ink_rect.y;
201 switch (h_align) {
202 case GFX_H_RIGHT:
203 sx -= log_rect.width;
204 break;
205 case GFX_H_CENTER:
206 sx -= log_rect.width / 2;
207 break;
208 case GFX_H_LEFT:
209 break;
210 case GFX_H_NULL:
211 break;
212 }
213 sy += log_rect.y;
214 switch (v_align) {
215 case GFX_V_TOP:
216 break;
217 case GFX_V_CENTER:
218 sy -= log_rect.height / 2;
219 break;
220 case GFX_V_BOTTOM:
221 sy -= log_rect.height;
222 break;
223 case GFX_V_NULL:
224 break;
225 }
226 pango_cairo_update_layout(cr, layout);
227 cairo_move_to(cr, sx, sy);
228 pango_cairo_show_layout(cr, layout);
229 pango_tab_array_free(pango_layout_get_tabs(layout));
230 g_object_unref(layout);
231 cairo_restore(cr);
233 }
235 /* convert color */
236 struct gfx_color_t gfx_hex_to_col(
237 long unsigned int color)
238 {
239 struct gfx_color_t gfx_color;
241 gfx_color.red = 1.0 / 255.0 * ((color & 0xff000000) >> (3 * 8));
242 gfx_color.green = 1.0 / 255.0 * ((color & 0x00ff0000) >> (2 * 8));
243 gfx_color.blue = 1.0 / 255.0 * ((color & 0x0000ff00) >> (1 * 8));
244 gfx_color.alpha = 1.0 / 255.0 * (color & 0x000000ff);
245 return gfx_color;
246 }
248 /* gridfit_lines */
250 void gfx_line_fit(
251 cairo_t * cr,
252 double *x,
253 double *y)
254 {
255 double line_width;
256 double line_height;
258 cairo_user_to_device(cr, x, y);
259 line_width = cairo_get_line_width(cr);
260 line_height = line_width;
261 cairo_user_to_device_distance(cr, &line_width, &line_height);
262 line_width = line_width / 2.0 - (long) (line_width / 2.0);
263 line_height = line_height / 2.0 - (long) (line_height / 2.0);
264 *x = (double) ((long) (*x + 0.5)) + line_width;
265 *y = (double) ((long) (*y + 0.5)) + line_height;
266 cairo_device_to_user(cr, x, y);
267 }
269 /* gridfit_areas */
271 void gfx_area_fit(
272 cairo_t * cr,
273 double *x,
274 double *y)
275 {
276 cairo_user_to_device(cr, x, y);
277 *x = (double) ((long) (*x + 0.5));
278 *y = (double) ((long) (*y + 0.5));
279 cairo_device_to_user(cr, x, y);
280 }