--font-render-mode is back, and there is also
[rrdtool.git] / src / rrd_graph.c
index 5154210..6648d9c 100644 (file)
@@ -140,16 +140,17 @@ ylab_t    ylab[] = {
 
 
 gfx_color_t graph_col[] =   /* default colors */
-{ 0xFFFFFFFF,           /* canvas     */
-    0xF0F0F0FF,         /* background */
-    0xD0D0D0FF,         /* shade A    */
-    0xA0A0A0FF,         /* shade B    */
-    0x90909080,         /* grid       */
-    0xE0505080,         /* major grid */
-    0x000000FF,         /* font       */
-    0x802020FF,         /* arrow      */
-    0x202020FF,         /* axis       */
-    0x000000FF          /* frame      */
+{
+    {1.00, 1.00, 1.00, 1.00},   /* canvas     */
+    {0.95, 0.95, 0.95, 1.00},   /* background */
+    {0.81, 0.81, 0.81, 1.00},   /* shade A    */
+    {0.62, 0.62, 0.62, 1.00},   /* shade B    */
+    {0.56, 0.56, 0.56, 0.75},   /* grid       */
+    {0.87, 0.31, 0.31, 0.60},   /* major grid */
+    {0.00, 0.00, 0.00, 1.00},   /* font       */
+    {0.50, 0.12, 0.12, 1.00},   /* arrow      */
+    {0.12, 0.12, 0.12, 1.00},   /* axis       */
+    {0.00, 0.00, 0.00, 1.00}    /* frame      */
 };
 
 
@@ -164,7 +165,7 @@ gfx_color_t graph_col[] =   /* default colors */
 
 /* initialize with xtr(im,0); */
 int xtr(
-    image_desc_t * im,
+    image_desc_t *im,
     time_t mytime)
 {
     static double pixie;
@@ -178,7 +179,7 @@ int xtr(
 
 /* translate data values into y coordinates */
 double ytr(
-    image_desc_t * im,
+    image_desc_t *im,
     double value)
 {
     static double pixie;
@@ -225,88 +226,85 @@ enum gf_en gf_conv(
     char *string)
 {
 
-    conv_if(PRINT, GF_PRINT)
-        conv_if(GPRINT, GF_GPRINT)
-        conv_if(COMMENT, GF_COMMENT)
-        conv_if(HRULE, GF_HRULE)
-        conv_if(VRULE, GF_VRULE)
-        conv_if(LINE, GF_LINE)
-        conv_if(AREA, GF_AREA)
-        conv_if(STACK, GF_STACK)
-        conv_if(TICK, GF_TICK)
-        conv_if(DEF, GF_DEF)
-        conv_if(CDEF, GF_CDEF)
-        conv_if(VDEF, GF_VDEF)
-#ifdef WITH_PIECHART
-        conv_if(PART, GF_PART)
-#endif
-        conv_if(XPORT, GF_XPORT)
-        conv_if(SHIFT, GF_SHIFT)
-
-        return (-1);
+    conv_if(PRINT, GF_PRINT);
+    conv_if(GPRINT, GF_GPRINT);
+    conv_if(COMMENT, GF_COMMENT);
+    conv_if(HRULE, GF_HRULE);
+    conv_if(VRULE, GF_VRULE);
+    conv_if(LINE, GF_LINE);
+    conv_if(AREA, GF_AREA);
+    conv_if(STACK, GF_STACK);
+    conv_if(TICK, GF_TICK);
+    conv_if(DEF, GF_DEF);
+    conv_if(CDEF, GF_CDEF);
+    conv_if(VDEF, GF_VDEF);
+    conv_if(XPORT, GF_XPORT);
+    conv_if(SHIFT, GF_SHIFT);
+
+    return (-1);
 }
 
 enum gfx_if_en if_conv(
     char *string)
 {
 
-    conv_if(PNG, IF_PNG)
-        conv_if(SVG, IF_SVG)
-        conv_if(EPS, IF_EPS)
-        conv_if(PDF, IF_PDF)
+    conv_if(PNG, IF_PNG);
+    conv_if(SVG, IF_SVG);
+    conv_if(EPS, IF_EPS);
+    conv_if(PDF, IF_PDF);
 
-        return (-1);
+    return (-1);
 }
 
 enum tmt_en tmt_conv(
     char *string)
 {
 
-    conv_if(SECOND, TMT_SECOND)
-        conv_if(MINUTE, TMT_MINUTE)
-        conv_if(HOUR, TMT_HOUR)
-        conv_if(DAY, TMT_DAY)
-        conv_if(WEEK, TMT_WEEK)
-        conv_if(MONTH, TMT_MONTH)
-        conv_if(YEAR, TMT_YEAR)
-        return (-1);
+    conv_if(SECOND, TMT_SECOND);
+    conv_if(MINUTE, TMT_MINUTE);
+    conv_if(HOUR, TMT_HOUR);
+    conv_if(DAY, TMT_DAY);
+    conv_if(WEEK, TMT_WEEK);
+    conv_if(MONTH, TMT_MONTH);
+    conv_if(YEAR, TMT_YEAR);
+    return (-1);
 }
 
 enum grc_en grc_conv(
     char *string)
 {
 
-    conv_if(BACK, GRC_BACK)
-        conv_if(CANVAS, GRC_CANVAS)
-        conv_if(SHADEA, GRC_SHADEA)
-        conv_if(SHADEB, GRC_SHADEB)
-        conv_if(GRID, GRC_GRID)
-        conv_if(MGRID, GRC_MGRID)
-        conv_if(FONT, GRC_FONT)
-        conv_if(ARROW, GRC_ARROW)
-        conv_if(AXIS, GRC_AXIS)
-        conv_if(FRAME, GRC_FRAME)
+    conv_if(BACK, GRC_BACK);
+    conv_if(CANVAS, GRC_CANVAS);
+    conv_if(SHADEA, GRC_SHADEA);
+    conv_if(SHADEB, GRC_SHADEB);
+    conv_if(GRID, GRC_GRID);
+    conv_if(MGRID, GRC_MGRID);
+    conv_if(FONT, GRC_FONT);
+    conv_if(ARROW, GRC_ARROW);
+    conv_if(AXIS, GRC_AXIS);
+    conv_if(FRAME, GRC_FRAME);
 
-        return -1;
+    return -1;
 }
 
 enum text_prop_en text_prop_conv(
     char *string)
 {
 
-    conv_if(DEFAULT, TEXT_PROP_DEFAULT)
-        conv_if(TITLE, TEXT_PROP_TITLE)
-        conv_if(AXIS, TEXT_PROP_AXIS)
-        conv_if(UNIT, TEXT_PROP_UNIT)
-        conv_if(LEGEND, TEXT_PROP_LEGEND)
-        return -1;
+    conv_if(DEFAULT, TEXT_PROP_DEFAULT);
+    conv_if(TITLE, TEXT_PROP_TITLE);
+    conv_if(AXIS, TEXT_PROP_AXIS);
+    conv_if(UNIT, TEXT_PROP_UNIT);
+    conv_if(LEGEND, TEXT_PROP_LEGEND);
+    return -1;
 }
 
 
 #undef conv_if
 
 int im_free(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     unsigned long i, ii;
 
@@ -326,13 +324,16 @@ int im_free(
         free(im->gdes[i].rpnp);
     }
     free(im->gdes);
-    gfx_destroy(im->canvas);
+    if (im->surface)
+        cairo_surface_destroy(im->surface);
+    if (im->font_options)
+        cairo_font_options_destroy(im->font_options);
     return 0;
 }
 
 /* find SI magnitude symbol for the given number*/
 void auto_scale(
-    image_desc_t * im,  /* image description */
+    image_desc_t *im,   /* image description */
     double *value,
     char **symb_ptr,
     double *magfact)
@@ -391,7 +392,7 @@ static const int si_symbcenter = 6;
 
 /* find SI magnitude symbol for the numbers on the y-axis*/
 void si_unit(
-    image_desc_t * im   /* image description */
+    image_desc_t *im    /* image description */
     )
 {
 
@@ -426,7 +427,7 @@ void si_unit(
 /*  move min and max values around to become sensible */
 
 void expand_range(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     double    sensiblevalues[] = { 1000.0, 900.0, 800.0, 750.0, 700.0,
         600.0, 500.0, 400.0, 300.0, 250.0,
@@ -520,8 +521,9 @@ void expand_range(
 #endif
 }
 
+
 void apply_gridfit(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     if (isnan(im->minval) || isnan(im->maxval))
         return;
@@ -604,7 +606,7 @@ void reduce_data(
     time_t *end,        /* ... by the application will be   ... */
     unsigned long *step,    /* ... adjusted to represent reality    */
     unsigned long *ds_cnt,  /* number of data sources in file */
-    rrd_value_t ** data)
+    rrd_value_t **data)
 {                       /* two dimensional array containing the data */
     int       i, reduce_factor = ceil((double) (*step) / (double) cur_step);
     unsigned long col, dst_row, row_cnt, start_offset, end_offset, skiprows =
@@ -772,7 +774,7 @@ void reduce_data(
    relevant rrds ... */
 
 int data_fetch(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       i, ii;
     int       skip;
@@ -867,7 +869,7 @@ long find_var_wrapper(
 
 /* find gdes containing var*/
 long find_var(
-    image_desc_t * im,
+    image_desc_t *im,
     char *key)
 {
     long      ii;
@@ -904,7 +906,7 @@ long lcd(
 
 /* run the rpn calculator on all the VDEF and CDEF arguments */
 int data_calc(
-    image_desc_t * im)
+    image_desc_t *im)
 {
 
     int       gdi;
@@ -1102,7 +1104,7 @@ int data_calc(
 
 /* massage data so, that we get one value for each x coordinate in the graph */
 int data_proc(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     long      i, ii;
     double    pixstep = (double) (im->end - im->start)
@@ -1261,49 +1263,58 @@ time_t find_first_time(
     struct tm tm;
 
     localtime_r(&start, &tm);
+
     switch (baseint) {
     case TMT_SECOND:
-        tm.tm_sec -= tm.tm_sec % basestep;
+        tm.       tm_sec -= tm.tm_sec % basestep;
+
         break;
     case TMT_MINUTE:
-        tm.tm_sec = 0;
-        tm.tm_min -= tm.tm_min % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min -= tm.tm_min % basestep;
+
         break;
     case TMT_HOUR:
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour -= tm.tm_hour % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour -= tm.tm_hour % basestep;
+
         break;
     case TMT_DAY:
         /* we do NOT look at the basestep for this ... */
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+
         break;
     case TMT_WEEK:
         /* we do NOT look at the basestep for this ... */
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
-        tm.tm_mday -= tm.tm_wday - 1;   /* -1 because we want the monday */
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+        tm.       tm_mday -= tm.tm_wday - 1;    /* -1 because we want the monday */
+
         if (tm.tm_wday == 0)
-            tm.tm_mday -= 7;    /* we want the *previous* monday */
+            tm.       tm_mday -= 7; /* we want the *previous* monday */
+
         break;
     case TMT_MONTH:
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
-        tm.tm_mday = 1;
-        tm.tm_mon -= tm.tm_mon % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+        tm.       tm_mday = 1;
+        tm.       tm_mon -= tm.tm_mon % basestep;
+
         break;
 
     case TMT_YEAR:
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
-        tm.tm_mday = 1;
-        tm.tm_mon = 0;
-        tm.tm_year -= (tm.tm_year + 1900) % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+        tm.       tm_mday = 1;
+        tm.       tm_mon = 0;
+        tm.       tm_year -= (
+    tm.tm_year + 1900) %basestep;
 
     }
     return mktime(&tm);
@@ -1320,28 +1331,35 @@ time_t find_next_time(
     time_t    madetime;
 
     localtime_r(&current, &tm);
+
     do {
         switch (baseint) {
         case TMT_SECOND:
-            tm.tm_sec += basestep;
+            tm.       tm_sec += basestep;
+
             break;
         case TMT_MINUTE:
-            tm.tm_min += basestep;
+            tm.       tm_min += basestep;
+
             break;
         case TMT_HOUR:
-            tm.tm_hour += basestep;
+            tm.       tm_hour += basestep;
+
             break;
         case TMT_DAY:
-            tm.tm_mday += basestep;
+            tm.       tm_mday += basestep;
+
             break;
         case TMT_WEEK:
-            tm.tm_mday += 7 * basestep;
+            tm.       tm_mday += 7 * basestep;
+
             break;
         case TMT_MONTH:
-            tm.tm_mon += basestep;
+            tm.       tm_mon += basestep;
+
             break;
         case TMT_YEAR:
-            tm.tm_year += basestep;
+            tm.       tm_year += basestep;
         }
         madetime = mktime(&tm);
     } while (madetime == -1);   /* this is necessary to skip impssible times
@@ -1354,7 +1372,7 @@ time_t find_next_time(
 /* calculate values required for PRINT and GPRINT functions */
 
 int print_calc(
-    image_desc_t * im,
+    image_desc_t *im,
     char ***prdata)
 {
     long      i, ii, validsteps;
@@ -1536,7 +1554,8 @@ int print_calc(
 
 /* place legends with color spots */
 int leg_place(
-    image_desc_t * im)
+    image_desc_t *im,
+    int *gY)
 {
     /* graph labels */
     int       interleg = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
@@ -1557,10 +1576,14 @@ int leg_place(
             return -1;
         }
 
+        if (im->extra_flags & FULL_SIZE_MODE)
+            leg_y = leg_y_prev =
+                leg_y - (int) (im->text_prop[TEXT_PROP_LEGEND].size * 1.8);
+
         for (i = 0; i < im->gdes_c; i++) {
             fill_last = fill;
 
-            /* hid legends for rules which are not displayed */
+            /* hide legends for rules which are not displayed */
 
             if (!(im->extra_flags & FORCE_RULES_LEGEND)) {
                 if (im->gdes[i].gf == GF_HRULE &&
@@ -1617,12 +1640,12 @@ int leg_place(
                     /* no interleg space if string ends in \g */
                     fill += legspace[i];
                 }
-                fill += gfx_get_text_width(im->canvas, fill + border,
+                fill += gfx_get_text_width(im, fill + border,
                                            im->text_prop[TEXT_PROP_LEGEND].
                                            font,
                                            im->text_prop[TEXT_PROP_LEGEND].
                                            size, im->tabwidth,
-                                           im->gdes[i].legend, 0);
+                                           im->gdes[i].legend);
                 leg_c++;
             } else {
                 legspace[i] = 0;
@@ -1669,30 +1692,45 @@ int leg_place(
                     im->gdes[ii].leg_x = leg_x;
                     im->gdes[ii].leg_y = leg_y;
                     leg_x +=
-                        gfx_get_text_width(im->canvas, leg_x,
+                        gfx_get_text_width(im, leg_x,
                                            im->text_prop[TEXT_PROP_LEGEND].
                                            font,
                                            im->text_prop[TEXT_PROP_LEGEND].
                                            size, im->tabwidth,
-                                           im->gdes[ii].legend, 0)
+                                           im->gdes[ii].legend)
                         + legspace[ii]
                         + glue;
                 }
                 leg_y_prev = leg_y;
-                /* only add y space if there was text on the line */
-                if (leg_x > border || prt_fctn == 's')
-                    leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
-                if (prt_fctn == 's')
-                    leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+                if (im->extra_flags & FULL_SIZE_MODE) {
+                    /* only add y space if there was text on the line */
+                    if (leg_x > border || prt_fctn == 's')
+                        leg_y -= im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+                    if (prt_fctn == 's')
+                        leg_y += im->text_prop[TEXT_PROP_LEGEND].size;
+                } else {
+                    if (leg_x > border || prt_fctn == 's')
+                        leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+                    if (prt_fctn == 's')
+                        leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+                }
                 fill = 0;
                 leg_c = 0;
                 mark = ii;
             }
         }
-        im->yimg = leg_y_prev;
-        /* if we did place some legends we have to add vertical space */
-        if (leg_y != im->yimg) {
-            im->yimg += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+
+        if (im->extra_flags & FULL_SIZE_MODE) {
+            if (leg_y != leg_y_prev) {
+                *gY = leg_y - im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+                im->yorigin =
+                    leg_y - im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+            }
+        } else {
+            im->yimg = leg_y_prev;
+            /* if we did place some legends we have to add vertical space */
+            if (leg_y != im->yimg)
+                im->yimg += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
         }
         free(legspace);
     }
@@ -1708,7 +1746,7 @@ int leg_place(
 
 
 int calc_horizontal_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     double    range;
     double    scaledrange;
@@ -1804,7 +1842,7 @@ int calc_horizontal_grid(
 }
 
 int draw_horizontal_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       i;
     double    scaledstep;
@@ -1864,25 +1902,37 @@ int draw_horizontal_grid(
                 }
                 nlabels++;
 
-                gfx_new_text(im->canvas,
-                             X0 - im->text_prop[TEXT_PROP_AXIS].size, Y0,
-                             im->graph_col[GRC_FONT],
-                             im->text_prop[TEXT_PROP_AXIS].font,
-                             im->text_prop[TEXT_PROP_AXIS].size,
-                             im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER,
-                             graph_label);
-                gfx_new_dashed_line(im->canvas,
-                                    X0 - 2, Y0,
-                                    X1 + 2, Y0,
-                                    MGRIDWIDTH, im->graph_col[GRC_MGRID],
-                                    im->grid_dash_on, im->grid_dash_off);
+                gfx_text(im,
+                         X0 - im->text_prop[TEXT_PROP_AXIS].size, Y0,
+                         im->graph_col[GRC_FONT],
+                         im->text_prop[TEXT_PROP_AXIS].font,
+                         im->text_prop[TEXT_PROP_AXIS].size,
+                         im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER,
+                         graph_label);
+                gfx_line(im,
+                         X0 - 2, Y0,
+                         X0, Y0, MGRIDWIDTH, im->graph_col[GRC_MGRID]);
+                gfx_line(im,
+                         X1, Y0,
+                         X1 + 2, Y0, MGRIDWIDTH, im->graph_col[GRC_MGRID]);
+                gfx_dashed_line(im,
+                                X0 - 2, Y0,
+                                X1 + 2, Y0,
+                                MGRIDWIDTH, im->graph_col[GRC_MGRID],
+                                im->grid_dash_on, im->grid_dash_off);
 
             } else if (!(im->extra_flags & NOMINOR)) {
-                gfx_new_dashed_line(im->canvas,
-                                    X0 - 1, Y0,
-                                    X1 + 1, Y0,
-                                    GRIDWIDTH, im->graph_col[GRC_GRID],
-                                    im->grid_dash_on, im->grid_dash_off);
+                gfx_line(im,
+                         X0 - 2, Y0,
+                         X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+                gfx_line(im,
+                         X1, Y0,
+                         X1 + 2, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+                gfx_dashed_line(im,
+                                X0 - 1, Y0,
+                                X1 + 1, Y0,
+                                GRIDWIDTH, im->graph_col[GRC_GRID],
+                                im->grid_dash_on, im->grid_dash_off);
 
             }
         }
@@ -1946,7 +1996,7 @@ static int AlmostEqual2sComplement(
 
 /* logaritmic horizontal grid */
 int horizontal_log_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     double    yloglab[][10] = {
         {1.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
@@ -2020,11 +2070,18 @@ int horizontal_log_grid(
             break;
 
         /* major grid line */
-        gfx_new_dashed_line(im->canvas,
-                            X0 - 2, Y0,
-                            X1 + 2, Y0,
-                            MGRIDWIDTH, im->graph_col[GRC_MGRID],
-                            im->grid_dash_on, im->grid_dash_off);
+
+        gfx_line(im,
+                 X0 - 2, Y0, X0, Y0, MGRIDWIDTH, im->graph_col[GRC_MGRID]);
+        gfx_line(im,
+                 X1, Y0, X1 + 2, Y0, MGRIDWIDTH, im->graph_col[GRC_MGRID]);
+
+
+        gfx_dashed_line(im,
+                        X0 - 2, Y0,
+                        X1 + 2, Y0,
+                        MGRIDWIDTH, im->graph_col[GRC_MGRID],
+                        im->grid_dash_on, im->grid_dash_off);
 
         /* label */
         if (im->extra_flags & FORCE_UNITS_SI) {
@@ -2048,13 +2105,12 @@ int horizontal_log_grid(
             sprintf(graph_label, "%3.0f %c", pvalue, symbol);
         } else
             sprintf(graph_label, "%3.0e", value);
-        gfx_new_text(im->canvas,
-                     X0 - im->text_prop[TEXT_PROP_AXIS].size, Y0,
-                     im->graph_col[GRC_FONT],
-                     im->text_prop[TEXT_PROP_AXIS].font,
-                     im->text_prop[TEXT_PROP_AXIS].size,
-                     im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER,
-                     graph_label);
+        gfx_text(im,
+                 X0 - im->text_prop[TEXT_PROP_AXIS].size, Y0,
+                 im->graph_col[GRC_FONT],
+                 im->text_prop[TEXT_PROP_AXIS].font,
+                 im->text_prop[TEXT_PROP_AXIS].size,
+                 im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER, graph_label);
 
         /* minor grid */
         if (mid < 4 && exfrac == 1) {
@@ -2083,11 +2139,17 @@ int horizontal_log_grid(
                     break;
 
                 /* draw lines */
-                gfx_new_dashed_line(im->canvas,
-                                    X0 - 1, Y0,
-                                    X1 + 1, Y0,
-                                    GRIDWIDTH, im->graph_col[GRC_GRID],
-                                    im->grid_dash_on, im->grid_dash_off);
+                gfx_line(im,
+                         X0 - 2, Y0,
+                         X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+                gfx_line(im,
+                         X1, Y0,
+                         X1 + 2, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+                gfx_dashed_line(im,
+                                X0 - 1, Y0,
+                                X1 + 1, Y0,
+                                GRIDWIDTH, im->graph_col[GRC_GRID],
+                                im->grid_dash_on, im->grid_dash_off);
             }
         } else if (exfrac > 1) {
             for (i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) {
@@ -2100,11 +2162,17 @@ int horizontal_log_grid(
                     break;
 
                 /* draw lines */
-                gfx_new_dashed_line(im->canvas,
-                                    X0 - 1, Y0,
-                                    X1 + 1, Y0,
-                                    GRIDWIDTH, im->graph_col[GRC_GRID],
-                                    im->grid_dash_on, im->grid_dash_off);
+                gfx_line(im,
+                         X0 - 2, Y0,
+                         X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+                gfx_line(im,
+                         X1, Y0,
+                         X1 + 2, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+                gfx_dashed_line(im,
+                                X0 - 1, Y0,
+                                X1 + 1, Y0,
+                                GRIDWIDTH, im->graph_col[GRC_GRID],
+                                im->grid_dash_on, im->grid_dash_off);
             }
         }
 
@@ -2142,11 +2210,15 @@ int horizontal_log_grid(
                 break;
 
             /* draw lines */
-            gfx_new_dashed_line(im->canvas,
-                                X0 - 1, Y0,
-                                X1 + 1, Y0,
-                                GRIDWIDTH, im->graph_col[GRC_GRID],
-                                im->grid_dash_on, im->grid_dash_off);
+            gfx_line(im,
+                     X0 - 2, Y0, X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+            gfx_line(im,
+                     X1, Y0, X1 + 2, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+            gfx_dashed_line(im,
+                            X0 - 1, Y0,
+                            X1 + 1, Y0,
+                            GRIDWIDTH, im->graph_col[GRC_GRID],
+                            im->grid_dash_on, im->grid_dash_off);
         }
     }
     /* fancy minor gridlines */
@@ -2161,11 +2233,15 @@ int horizontal_log_grid(
                 break;
 
             /* draw lines */
-            gfx_new_dashed_line(im->canvas,
-                                X0 - 1, Y0,
-                                X1 + 1, Y0,
-                                GRIDWIDTH, im->graph_col[GRC_GRID],
-                                im->grid_dash_on, im->grid_dash_off);
+            gfx_line(im,
+                     X0 - 2, Y0, X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+            gfx_line(im,
+                     X1, Y0, X1 + 2, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]);
+            gfx_dashed_line(im,
+                            X0 - 1, Y0,
+                            X1 + 1, Y0,
+                            GRIDWIDTH, im->graph_col[GRC_GRID],
+                            im->grid_dash_on, im->grid_dash_off);
         }
     }
 
@@ -2174,7 +2250,7 @@ int horizontal_log_grid(
 
 
 void vertical_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       xlab_sel; /* which sort of label and grid ? */
     time_t    ti, tilab, timajor;
@@ -2236,9 +2312,13 @@ void vertical_grid(
             if (ti == timajor)
                 continue;   /* skip as falls on major grid line */
             X0 = xtr(im, ti);
-            gfx_new_dashed_line(im->canvas, X0, Y0 + 1, X0, Y1 - 1, GRIDWIDTH,
-                                im->graph_col[GRC_GRID],
-                                im->grid_dash_on, im->grid_dash_off);
+            gfx_line(im, X0, Y1 - 2, X0, Y1, GRIDWIDTH,
+                     im->graph_col[GRC_GRID]);
+            gfx_line(im, X0, Y0, X0, Y0 + 2, GRIDWIDTH,
+                     im->graph_col[GRC_GRID]);
+            gfx_dashed_line(im, X0, Y0 + 1, X0, Y1 - 1, GRIDWIDTH,
+                            im->graph_col[GRC_GRID],
+                            im->grid_dash_on, im->grid_dash_off);
 
         }
     }
@@ -2254,9 +2334,13 @@ void vertical_grid(
         if (ti < im->start || ti > im->end)
             continue;
         X0 = xtr(im, ti);
-        gfx_new_dashed_line(im->canvas, X0, Y0 + 3, X0, Y1 - 2, MGRIDWIDTH,
-                            im->graph_col[GRC_MGRID],
-                            im->grid_dash_on, im->grid_dash_off);
+        gfx_line(im, X0, Y1 - 2, X0, Y1, MGRIDWIDTH,
+                 im->graph_col[GRC_MGRID]);
+        gfx_line(im, X0, Y0, X0, Y0 + 3, MGRIDWIDTH,
+                 im->graph_col[GRC_MGRID]);
+        gfx_dashed_line(im, X0, Y0 + 3, X0, Y1 - 2, MGRIDWIDTH,
+                        im->graph_col[GRC_MGRID],
+                        im->grid_dash_on, im->grid_dash_off);
 
     }
     /* paint the labels below the graph */
@@ -2277,13 +2361,13 @@ void vertical_grid(
 #else
 # error "your libc has no strftime I guess we'll abort the exercise here."
 #endif
-        gfx_new_text(im->canvas,
-                     xtr(im, tilab),
-                     Y0 + im->text_prop[TEXT_PROP_AXIS].size * 1.4 + 5,
-                     im->graph_col[GRC_FONT],
-                     im->text_prop[TEXT_PROP_AXIS].font,
-                     im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 0.0,
-                     GFX_H_CENTER, GFX_V_BOTTOM, graph_label);
+        gfx_text(im,
+                 xtr(im, tilab),
+                 Y0 + 3,
+                 im->graph_col[GRC_FONT],
+                 im->text_prop[TEXT_PROP_AXIS].font,
+                 im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 0.0,
+                 GFX_H_CENTER, GFX_V_TOP, graph_label);
 
     }
 
@@ -2291,58 +2375,61 @@ void vertical_grid(
 
 
 void axis_paint(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     /* draw x and y axis */
-    /* gfx_new_line ( im->canvas, im->xorigin+im->xsize,im->yorigin,
+    /* gfx_line ( im->canvas, im->xorigin+im->xsize,im->yorigin,
        im->xorigin+im->xsize,im->yorigin-im->ysize,
        GRIDWIDTH, im->graph_col[GRC_AXIS]);
 
-       gfx_new_line ( im->canvas, im->xorigin,im->yorigin-im->ysize,
+       gfx_line ( im->canvas, im->xorigin,im->yorigin-im->ysize,
        im->xorigin+im->xsize,im->yorigin-im->ysize,
        GRIDWIDTH, im->graph_col[GRC_AXIS]); */
 
-    gfx_new_line(im->canvas, im->xorigin - 4, im->yorigin,
-                 im->xorigin + im->xsize + 4, im->yorigin,
-                 MGRIDWIDTH, im->graph_col[GRC_AXIS]);
+    gfx_line(im, im->xorigin - 4, im->yorigin,
+             im->xorigin + im->xsize + 4, im->yorigin,
+             MGRIDWIDTH, im->graph_col[GRC_AXIS]);
 
-    gfx_new_line(im->canvas, im->xorigin, im->yorigin + 4,
-                 im->xorigin, im->yorigin - im->ysize - 4,
-                 MGRIDWIDTH, im->graph_col[GRC_AXIS]);
+    gfx_line(im, im->xorigin, im->yorigin + 4,
+             im->xorigin, im->yorigin - im->ysize - 4,
+             MGRIDWIDTH, im->graph_col[GRC_AXIS]);
 
 
     /* arrow for X and Y axis direction */
-    gfx_new_area(im->canvas, im->xorigin + im->xsize + 2, im->yorigin - 2, im->xorigin + im->xsize + 2, im->yorigin + 3, im->xorigin + im->xsize + 7, im->yorigin + 0.5,    /* LINEOFFSET */
+    gfx_new_area(im, im->xorigin + im->xsize + 2, im->yorigin - 2, im->xorigin + im->xsize + 2, im->yorigin + 3, im->xorigin + im->xsize + 7, im->yorigin + 0.5,    /* LINEOFFSET */
                  im->graph_col[GRC_ARROW]);
+    gfx_close_path(im);
 
-    gfx_new_area(im->canvas, im->xorigin - 2, im->yorigin - im->ysize - 2, im->xorigin + 3, im->yorigin - im->ysize - 2, im->xorigin + 0.5, im->yorigin - im->ysize - 7,    /* LINEOFFSET */
+    gfx_new_area(im, im->xorigin - 2, im->yorigin - im->ysize - 2, im->xorigin + 3, im->yorigin - im->ysize - 2, im->xorigin + 0.5, im->yorigin - im->ysize - 7,    /* LINEOFFSET */
                  im->graph_col[GRC_ARROW]);
+    gfx_close_path(im);
+
 
 }
 
 void grid_paint(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     long      i;
     int       res = 0;
     double    X0, Y0;   /* points for filled graph and more */
-    gfx_node_t *node;
+    struct gfx_color_t water_color;
 
     /* draw 3d border */
-    node = gfx_new_area(im->canvas, 0, im->yimg,
-                        2, im->yimg - 2, 2, 2, im->graph_col[GRC_SHADEA]);
-    gfx_add_point(node, im->ximg - 2, 2);
-    gfx_add_point(node, im->ximg, 0);
-    gfx_add_point(node, 0, 0);
-/*    gfx_add_point( node , 0,im->yimg ); */
-
-    node = gfx_new_area(im->canvas, 2, im->yimg - 2,
-                        im->ximg - 2, im->yimg - 2,
-                        im->ximg - 2, 2, im->graph_col[GRC_SHADEB]);
-    gfx_add_point(node, im->ximg, 0);
-    gfx_add_point(node, im->ximg, im->yimg);
-    gfx_add_point(node, 0, im->yimg);
-/*    gfx_add_point( node , 0,im->yimg ); */
+    gfx_new_area(im, 0, im->yimg,
+                 2, im->yimg - 2, 2, 2, im->graph_col[GRC_SHADEA]);
+    gfx_add_point(im, im->ximg - 2, 2);
+    gfx_add_point(im, im->ximg, 0);
+    gfx_add_point(im, 0, 0);
+    gfx_close_path(im);
+
+    gfx_new_area(im, 2, im->yimg - 2,
+                 im->ximg - 2, im->yimg - 2,
+                 im->ximg - 2, 2, im->graph_col[GRC_SHADEB]);
+    gfx_add_point(im, im->ximg, 0);
+    gfx_add_point(im, im->ximg, im->yimg);
+    gfx_add_point(im, 0, im->yimg);
+    gfx_close_path(im);
 
 
     if (im->draw_x_grid == 1)
@@ -2359,47 +2446,48 @@ void grid_paint(
         if (!res) {
             char     *nodata = "No Data found";
 
-            gfx_new_text(im->canvas, im->ximg / 2,
-                         (2 * im->yorigin - im->ysize) / 2,
-                         im->graph_col[GRC_FONT],
-                         im->text_prop[TEXT_PROP_AXIS].font,
-                         im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth,
-                         0.0, GFX_H_CENTER, GFX_V_CENTER, nodata);
+            gfx_text(im, im->ximg / 2,
+                     (2 * im->yorigin - im->ysize) / 2,
+                     im->graph_col[GRC_FONT],
+                     im->text_prop[TEXT_PROP_AXIS].font,
+                     im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth,
+                     0.0, GFX_H_CENTER, GFX_V_CENTER, nodata);
         }
     }
 
     /* yaxis unit description */
-    gfx_new_text(im->canvas,
-                 10, (im->yorigin - im->ysize / 2),
-                 im->graph_col[GRC_FONT],
-                 im->text_prop[TEXT_PROP_UNIT].font,
-                 im->text_prop[TEXT_PROP_UNIT].size, im->tabwidth,
-                 RRDGRAPH_YLEGEND_ANGLE,
-                 GFX_H_LEFT, GFX_V_CENTER, im->ylegend);
+    gfx_text(im,
+             10, (im->yorigin - im->ysize / 2),
+             im->graph_col[GRC_FONT],
+             im->text_prop[TEXT_PROP_UNIT].font,
+             im->text_prop[TEXT_PROP_UNIT].size, im->tabwidth,
+             RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend);
 
     /* graph title */
-    gfx_new_text(im->canvas,
-                 im->ximg / 2, im->text_prop[TEXT_PROP_TITLE].size * 1.3 + 4,
-                 im->graph_col[GRC_FONT],
-                 im->text_prop[TEXT_PROP_TITLE].font,
-                 im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
-                 GFX_H_CENTER, GFX_V_CENTER, im->title);
+    gfx_text(im,
+             im->ximg / 2, 6,
+             im->graph_col[GRC_FONT],
+             im->text_prop[TEXT_PROP_TITLE].font,
+             im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
+             GFX_H_CENTER, GFX_V_TOP, im->title);
     /* rrdtool 'logo' */
-    gfx_new_text(im->canvas,
-                 im->ximg - 7, 7,
-                 (im->graph_col[GRC_FONT] & 0xffffff00) | 0x00000044,
-                 im->text_prop[TEXT_PROP_AXIS].font,
-                 5.5, im->tabwidth, 270,
-                 GFX_H_RIGHT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER");
+    water_color = im->graph_col[GRC_FONT];
+    water_color.alpha = 0.3;
+    gfx_text(im,
+             im->ximg - 4, 5,
+             water_color,
+             im->text_prop[TEXT_PROP_AXIS].font,
+             5.5, im->tabwidth, -90,
+             GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER");
 
     /* graph watermark */
     if (im->watermark[0] != '\0') {
-        gfx_new_text(im->canvas,
-                     im->ximg / 2, im->yimg - 6,
-                     (im->graph_col[GRC_FONT] & 0xffffff00) | 0x00000044,
-                     im->text_prop[TEXT_PROP_AXIS].font,
-                     5.5, im->tabwidth, 0,
-                     GFX_H_CENTER, GFX_V_BOTTOM, im->watermark);
+        gfx_text(im,
+                 im->ximg / 2, im->yimg - 6,
+                 water_color,
+                 im->text_prop[TEXT_PROP_AXIS].font,
+                 5.5, im->tabwidth, 0,
+                 GFX_H_CENTER, GFX_V_BOTTOM, im->watermark);
     }
 
     /* graph labels */
@@ -2411,42 +2499,62 @@ void grid_paint(
             /* im->gdes[i].leg_y is the bottom of the legend */
             X0 = im->gdes[i].leg_x;
             Y0 = im->gdes[i].leg_y;
-            gfx_new_text(im->canvas, X0, Y0,
-                         im->graph_col[GRC_FONT],
-                         im->text_prop[TEXT_PROP_LEGEND].font,
-                         im->text_prop[TEXT_PROP_LEGEND].size,
-                         im->tabwidth, 0.0, GFX_H_LEFT, GFX_V_BOTTOM,
-                         im->gdes[i].legend);
+            gfx_text(im, X0, Y0,
+                     im->graph_col[GRC_FONT],
+                     im->text_prop[TEXT_PROP_LEGEND].font,
+                     im->text_prop[TEXT_PROP_LEGEND].size,
+                     im->tabwidth, 0.0, GFX_H_LEFT, GFX_V_BOTTOM,
+                     im->gdes[i].legend);
             /* The legend for GRAPH items starts with "M " to have
                enough space for the box */
             if (im->gdes[i].gf != GF_PRINT &&
                 im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT) {
-                int       boxH, boxV;
+                double    boxH, boxV;
+                double    X1, Y1;
 
-                boxH = gfx_get_text_width(im->canvas, 0,
+
+                boxH = gfx_get_text_width(im, 0,
                                           im->text_prop[TEXT_PROP_LEGEND].
                                           font,
                                           im->text_prop[TEXT_PROP_LEGEND].
-                                          size, im->tabwidth, "o", 0) * 1.2;
-                boxV = boxH * 1.1;
+                                          size, im->tabwidth, "o") * 1.2;
+                boxV = boxH;
+
+                /* shift the box up a bit */
+                Y0 -= boxV * 0.4;
 
                 /* make sure transparent colors show up the same way as in the graph */
-                node = gfx_new_area(im->canvas,
-                                    X0, Y0 - boxV,
-                                    X0, Y0,
-                                    X0 + boxH, Y0, im->graph_col[GRC_BACK]);
-                gfx_add_point(node, X0 + boxH, Y0 - boxV);
-
-                node = gfx_new_area(im->canvas,
-                                    X0, Y0 - boxV,
-                                    X0, Y0, X0 + boxH, Y0, im->gdes[i].col);
-                gfx_add_point(node, X0 + boxH, Y0 - boxV);
-                node = gfx_new_line(im->canvas,
-                                    X0, Y0 - boxV,
-                                    X0, Y0, 1.0, im->graph_col[GRC_FRAME]);
-                gfx_add_point(node, X0 + boxH, Y0);
-                gfx_add_point(node, X0 + boxH, Y0 - boxV);
-                gfx_close_path(node);
+
+                gfx_new_area(im,
+                             X0, Y0 - boxV,
+                             X0, Y0, X0 + boxH, Y0, im->graph_col[GRC_BACK]);
+                gfx_add_point(im, X0 + boxH, Y0 - boxV);
+                gfx_close_path(im);
+
+                gfx_new_area(im,
+                             X0, Y0 - boxV,
+                             X0, Y0, X0 + boxH, Y0, im->gdes[i].col);
+                gfx_add_point(im, X0 + boxH, Y0 - boxV);
+                gfx_close_path(im);
+
+                cairo_save(im->cr);
+                cairo_new_path(im->cr);
+                cairo_set_line_width(im->cr, 1.0);
+                X1 = X0 + boxH;
+                Y1 = Y0 - boxV;
+                gfx_line_fit(im, &X0, &Y0);
+                gfx_line_fit(im, &X1, &Y1);
+                cairo_move_to(im->cr, X0, Y0);
+                cairo_line_to(im->cr, X1, Y0);
+                cairo_line_to(im->cr, X1, Y1);
+                cairo_line_to(im->cr, X0, Y1);
+                cairo_close_path(im->cr);
+                cairo_set_source_rgba(im->cr, im->graph_col[GRC_FRAME].red,
+                                      im->graph_col[GRC_FRAME].green,
+                                      im->graph_col[GRC_FRAME].blue,
+                                      im->graph_col[GRC_FRAME].alpha);
+                cairo_stroke(im->cr);
+                cairo_restore(im->cr);
             }
         }
     }
@@ -2458,7 +2566,7 @@ void grid_paint(
  *****************************************************/
 
 int lazy_check(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     FILE     *fd = NULL;
     int       size = 1;
@@ -2474,7 +2582,7 @@ int lazy_check(
         return 0;
     if ((fd = fopen(im->graphfile, "rb")) == NULL)
         return 0;       /* the file does not exist */
-    switch (im->canvas->imgformat) {
+    switch (im->imgformat) {
     case IF_PNG:
         size = PngSize(fd, &(im->ximg), &(im->yimg));
         break;
@@ -2485,67 +2593,10 @@ int lazy_check(
     return size;
 }
 
-#ifdef WITH_PIECHART
-void pie_part(
-    image_desc_t * im,
-    gfx_color_t color,
-    double PieCenterX,
-    double PieCenterY,
-    double Radius,
-    double startangle,
-    double endangle)
-{
-    gfx_node_t *node;
-    double    angle;
-    double    step = M_PI / 50; /* Number of iterations for the circle;
-                                 ** 10 is definitely too low, more than
-                                 ** 50 seems to be overkill
-                                 */
-
-    /* Strange but true: we have to work clockwise or else
-     ** anti aliasing nor transparency don't work.
-     **
-     ** This test is here to make sure we do it right, also
-     ** this makes the for...next loop more easy to implement.
-     ** The return will occur if the user enters a negative number
-     ** (which shouldn't be done according to the specs) or if the
-     ** programmers do something wrong (which, as we all know, never
-     ** happens anyway :)
-     */
-    if (endangle < startangle)
-        return;
-
-    /* Hidden feature: Radius decreases each full circle */
-    angle = startangle;
-    while (angle >= 2 * M_PI) {
-        angle -= 2 * M_PI;
-        Radius *= 0.8;
-    }
-
-    node = gfx_new_area(im->canvas,
-                        PieCenterX + sin(startangle) * Radius,
-                        PieCenterY - cos(startangle) * Radius,
-                        PieCenterX,
-                        PieCenterY,
-                        PieCenterX + sin(endangle) * Radius,
-                        PieCenterY - cos(endangle) * Radius, color);
-    for (angle = endangle; angle - startangle >= step; angle -= step) {
-        gfx_add_point(node,
-                      PieCenterX + sin(angle) * Radius,
-                      PieCenterY - cos(angle) * Radius);
-    }
-}
-
-#endif
 
 int graph_size_location(
-    image_desc_t * im,
-    int elements
-#ifdef WITH_PIECHART
-    ,
-    int piechart
-#endif
-    )
+    image_desc_t *im,
+    int elements)
 {
     /* The actual size of the image to draw is determined from
      ** several sources.  The size given on the command line is
@@ -2553,31 +2604,8 @@ int graph_size_location(
      ** and other things outside the graph area
      */
 
-    /* +-+-------------------------------------------+
-     ** |l|.................title.....................|
-     ** |e+--+-------------------------------+--------+
-     ** |b| b|                               |        |
-     ** |a| a|                               |  pie   |
-     ** |l| l|          main graph area      | chart  |
-     ** |.| .|                               |  area  |
-     ** |t| y|                               |        |
-     ** |r+--+-------------------------------+--------+
-     ** |e|  | x-axis labels                 |        |
-     ** |v+--+-------------------------------+--------+
-     ** | |..............legends......................|
-     ** +-+-------------------------------------------+
-     ** |                 watermark                   |
-     ** +---------------------------------------------+
-     */
     int       Xvertical = 0, Ytitle = 0, Xylabel = 0, Xmain = 0, Ymain = 0,
-#ifdef WITH_PIECHART
-        Xpie = 0, Ypie = 0,
-#endif
-        Yxlabel = 0,
-#if 0
-        Xlegend = 0, Ylegend = 0,
-#endif
-        Xspacing = 15, Yspacing = 15, Ywatermark = 4;
+        Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4;
 
     if (im->extra_flags & ONLY_GRAPH) {
         im->xorigin = 0;
@@ -2588,143 +2616,218 @@ int graph_size_location(
         return 0;
     }
 
+    /** +---+--------------------------------------------+
+     ** | y |...............graph title..................|
+     ** |   +---+-------------------------------+--------+
+     ** | a | y |                               |        |
+     ** | x |   |                               |        |
+     ** | i | a |                               |  pie   |
+     ** | s | x |       main graph area         | chart  |
+     ** |   | i |                               |  area  |
+     ** | t | s |                               |        |
+     ** | i |   |                               |        |
+     ** | t | l |                               |        |
+     ** | l | b +-------------------------------+--------+
+     ** | e | l |       x axis labels           |        |
+     ** +---+---+-------------------------------+--------+
+     ** |....................legends.....................|
+     ** +------------------------------------------------+
+     ** |                   watermark                    |
+     ** +------------------------------------------------+
+     */
+
     if (im->ylegend[0] != '\0') {
         Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
     }
 
-
     if (im->title[0] != '\0') {
         /* The title is placed "inbetween" two text lines so it
          ** automatically has some vertical spacing.  The horizontal
          ** spacing is added here, on each side.
          */
-        /* don't care for the with of the title
-           Xtitle = gfx_get_text_width(im->canvas, 0,
-           im->text_prop[TEXT_PROP_TITLE].font,
-           im->text_prop[TEXT_PROP_TITLE].size,
-           im->tabwidth,
-           im->title, 0) + 2*Xspacing; */
+        /* if necessary, reduce the font size of the title until it fits the image width */
         Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
     }
 
     if (elements) {
-        Xmain = im->xsize;
-        Ymain = im->ysize;
         if (im->draw_x_grid) {
             Yxlabel = im->text_prop[TEXT_PROP_AXIS].size * 2.5;
         }
         if (im->draw_y_grid || im->forceleftspace) {
-            Xylabel = gfx_get_text_width(im->canvas, 0,
+            Xylabel = gfx_get_text_width(im, 0,
                                          im->text_prop[TEXT_PROP_AXIS].font,
                                          im->text_prop[TEXT_PROP_AXIS].size,
-                                         im->tabwidth,
-                                         "0", 0) * im->unitslength;
+                                         im->tabwidth, "0") * im->unitslength;
         }
     }
-#ifdef WITH_PIECHART
-    if (piechart) {
-        im->piesize = im->xsize < im->ysize ? im->xsize : im->ysize;
-        Xpie = im->piesize;
-        Ypie = im->piesize;
-    }
-#endif
 
-    /* Now calculate the total size.  Insert some spacing where
-       desired.  im->xorigin and im->yorigin need to correspond
-       with the lower left corner of the main graph area or, if
-       this one is not set, the imaginary box surrounding the
-       pie chart area. */
+    if (im->extra_flags & FULL_SIZE_MODE) {
+        /* The actual size of the image to draw has been determined by the user.
+         ** The graph area is the space remaining after accounting for the legend,
+         ** the watermark, the pie chart, the axis labels, and the title.
+         */
+        im->xorigin = 0;
+        im->ximg = im->xsize;
+        im->yimg = im->ysize;
+        im->yorigin = im->ysize;
+        Xmain = im->ximg;
+        Ymain = im->yimg;
+
+        im->yorigin += Ytitle;
 
-    /* The legend width cannot yet be determined, as a result we
-     ** have problems adjusting the image to it.  For now, we just
-     ** forget about it at all; the legend will have to fit in the
-     ** size already allocated.
-     */
-    im->ximg = Xylabel + Xmain + 2 * Xspacing;
+        /* Now calculate the total size.  Insert some spacing where
+           desired.  im->xorigin and im->yorigin need to correspond
+           with the lower left corner of the main graph area or, if
+           this one is not set, the imaginary box surrounding the
+           pie chart area. */
 
-#ifdef WITH_PIECHART
-    im->ximg += Xpie;
-#endif
+        /* Initial size calculation for the main graph area */
+        Xmain = im->ximg - (Xylabel + 2 * Xspacing);
+        if (Xmain)
+            Xmain -= Xspacing;  /* put space between main graph area and right edge */
 
-    if (Xmain)
-        im->ximg += Xspacing;
-#ifdef WITH_PIECHART
-    if (Xpie)
-        im->ximg += Xspacing;
-#endif
+        im->xorigin = Xspacing + Xylabel;
+
+        /* the length of the title should not influence with width of the graph
+           if (Xtitle > im->ximg) im->ximg = Xtitle; */
 
-    im->xorigin = Xspacing + Xylabel;
+        if (Xvertical) {    /* unit description */
+            Xmain -= Xvertical;
+            im->xorigin += Xvertical;
+        }
+        im->xsize = Xmain;
+        xtr(im, 0);
 
-    /* the length of the title should not influence with width of the graph
-       if (Xtitle > im->ximg) im->ximg = Xtitle; */
+        /* The vertical size of the image is known in advance.  The main graph area
+         ** (Ymain) and im->yorigin must be set according to the space requirements
+         ** of the legend and the axis labels.
+         */
 
-    if (Xvertical) {    /* unit description */
-        im->ximg += Xvertical;
-        im->xorigin += Xvertical;
-    }
-    xtr(im, 0);
-
-    /* The vertical size is interesting... we need to compare
-     ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with 
-     ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel}
-     ** in order to start even thinking about Ylegend or Ywatermark.
-     **
-     ** Do it in three portions: First calculate the inner part,
-     ** then do the legend, then adjust the total height of the img,
-     ** adding space for a watermark if one exists;
-     */
+        if (im->extra_flags & NOLEGEND) {
+            /* set dimensions correctly if using full size mode with no legend */
+            im->yorigin =
+                im->yimg - im->text_prop[TEXT_PROP_AXIS].size * 2.5 -
+                Yspacing;
+            Ymain = im->yorigin;
+        } else {
+            /* Determine where to place the legends onto the image.
+             ** Set Ymain and adjust im->yorigin to match the space requirements.
+             */
+            if (leg_place(im, &Ymain) == -1)
+                return -1;
+        }
 
-    /* reserve space for main and/or pie */
 
-    im->yimg = Ymain + Yxlabel;
+        /* remove title space *or* some padding above the graph from the main graph area */
+        if (Ytitle) {
+            Ymain -= Ytitle;
+        } else {
+            Ymain -= 1.5 * Yspacing;
+        }
 
-#ifdef WITH_PIECHART
-    if (im->yimg < Ypie)
-        im->yimg = Ypie;
-#endif
+        /* watermark doesn't seem to effect the vertical size of the main graph area, oh well! */
+        if (im->watermark[0] != '\0') {
+            Ymain -= Ywatermark;
+        }
 
-    im->yorigin = im->yimg - Yxlabel;
+        im->ysize = Ymain;
 
-    /* reserve space for the title *or* some padding above the graph */
-    if (Ytitle) {
-        im->yimg += Ytitle;
-        im->yorigin += Ytitle;
-    } else {
-        im->yimg += 1.5 * Yspacing;
-        im->yorigin += 1.5 * Yspacing;
-    }
-    /* reserve space for padding below the graph */
-    im->yimg += Yspacing;
+    } else {            /* dimension options -width and -height refer to the dimensions of the main graph area */
 
-    /* Determine where to place the legends onto the image.
-     ** Adjust im->yimg to match the space requirements.
-     */
-    if (leg_place(im) == -1)
-        return -1;
+        /* The actual size of the image to draw is determined from
+         ** several sources.  The size given on the command line is
+         ** the graph area but we need more as we have to draw labels
+         ** and other things outside the graph area.
+         */
 
-    if (im->watermark[0] != '\0') {
-        im->yimg += Ywatermark;
-    }
-#if 0
-    if (Xlegend > im->ximg) {
-        im->ximg = Xlegend;
-        /* reposition Pie */
-    }
-#endif
+        if (im->ylegend[0] != '\0') {
+            Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
+        }
 
-#ifdef WITH_PIECHART
-    /* The pie is placed in the upper right hand corner,
-     ** just below the title (if any) and with sufficient
-     ** padding.
-     */
-    if (elements) {
-        im->pie_x = im->ximg - Xspacing - Xpie / 2;
-        im->pie_y = im->yorigin - Ymain + Ypie / 2;
-    } else {
-        im->pie_x = im->ximg / 2;
-        im->pie_y = im->yorigin - Ypie / 2;
+
+        if (im->title[0] != '\0') {
+            /* The title is placed "inbetween" two text lines so it
+             ** automatically has some vertical spacing.  The horizontal
+             ** spacing is added here, on each side.
+             */
+            /* don't care for the with of the title
+               Xtitle = gfx_get_text_width(im->canvas, 0,
+               im->text_prop[TEXT_PROP_TITLE].font,
+               im->text_prop[TEXT_PROP_TITLE].size,
+               im->tabwidth,
+               im->title, 0) + 2*Xspacing; */
+            Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
+        }
+
+        if (elements) {
+            Xmain = im->xsize;
+            Ymain = im->ysize;
+        }
+        /* Now calculate the total size.  Insert some spacing where
+           desired.  im->xorigin and im->yorigin need to correspond
+           with the lower left corner of the main graph area or, if
+           this one is not set, the imaginary box surrounding the
+           pie chart area. */
+
+        /* The legend width cannot yet be determined, as a result we
+         ** have problems adjusting the image to it.  For now, we just
+         ** forget about it at all; the legend will have to fit in the
+         ** size already allocated.
+         */
+        im->ximg = Xylabel + Xmain + 2 * Xspacing;
+
+        if (Xmain)
+            im->ximg += Xspacing;
+
+        im->xorigin = Xspacing + Xylabel;
+
+        /* the length of the title should not influence with width of the graph
+           if (Xtitle > im->ximg) im->ximg = Xtitle; */
+
+        if (Xvertical) {    /* unit description */
+            im->ximg += Xvertical;
+            im->xorigin += Xvertical;
+        }
+        xtr(im, 0);
+
+        /* The vertical size is interesting... we need to compare
+         ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with 
+         ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel}
+         ** in order to start even thinking about Ylegend or Ywatermark.
+         **
+         ** Do it in three portions: First calculate the inner part,
+         ** then do the legend, then adjust the total height of the img,
+         ** adding space for a watermark if one exists;
+         */
+
+        /* reserve space for main and/or pie */
+
+        im->yimg = Ymain + Yxlabel;
+
+
+        im->yorigin = im->yimg - Yxlabel;
+
+        /* reserve space for the title *or* some padding above the graph */
+        if (Ytitle) {
+            im->yimg += Ytitle;
+            im->yorigin += Ytitle;
+        } else {
+            im->yimg += 1.5 * Yspacing;
+            im->yorigin += 1.5 * Yspacing;
+        }
+        /* reserve space for padding below the graph */
+        im->yimg += Yspacing;
+
+        /* Determine where to place the legends onto the image.
+         ** Adjust im->yimg to match the space requirements.
+         */
+        if (leg_place(im, 0) == -1)
+            return -1;
+
+        if (im->watermark[0] != '\0') {
+            im->yimg += Ywatermark;
+        }
     }
-#endif
 
     ytr(im, DNAN);
     return 0;
@@ -2737,22 +2840,18 @@ int graph_size_location(
 
 /* draw that picture thing ... */
 int graph_paint(
-    image_desc_t * im,
+    image_desc_t *im,
     char ***calcpr)
 {
     int       i, ii;
     int       lazy = lazy_check(im);
 
-#ifdef WITH_PIECHART
-    int       piechart = 0;
-    double    PieStart = 0.0;
-#endif
-    FILE     *fo;
-    gfx_node_t *node;
-
     double    areazero = 0.0;
     graph_desc_t *lastgdes = NULL;
 
+    PangoFontMap *font_map = pango_cairo_font_map_get_default();
+
+
     /* if we are lazy and there is nothing to PRINT ... quit now */
     if (lazy && im->prt_c == 0)
         return 0;
@@ -2766,15 +2865,6 @@ int graph_paint(
     if (data_calc(im) == -1)
         return -1;
 
-#ifdef WITH_PIECHART
-    /* check if we need to draw a piechart */
-    for (i = 0; i < im->gdes_c; i++) {
-        if (im->gdes[i].gf == GF_PART) {
-            piechart = 1;
-            break;
-        }
-    }
-#endif
 
     /* calculate and PRINT and GPRINT definitions. We have to do it at
      * this point because it will affect the length of the legends
@@ -2784,18 +2874,15 @@ int graph_paint(
     i = print_calc(im, calcpr);
     if (i < 0)
         return -1;
-    if (((i == 0)
-#ifdef WITH_PIECHART
-         && (piechart == 0)
-#endif
-        ) || lazy)
+    if ((i == 0) || lazy)
         return 0;
 
-#ifdef WITH_PIECHART
-    /* If there's only the pie chart to draw, signal this */
-    if (i == 0)
-        piechart = 2;
-#endif
+/**************************************************************
+ *** Calculating sizes and locations became a bit confusing ***
+ *** so I moved this into a separate function.              ***
+ **************************************************************/
+    if (graph_size_location(im, i) == -1)
+        return -1;
 
     /* get actual drawing data and find min and max values */
     if (data_proc(im) == -1)
@@ -2812,56 +2899,67 @@ int graph_paint(
     if (!calc_horizontal_grid(im))
         return -1;
 
-    if (im->gridfit)
-        apply_gridfit(im);
+    /* reset precalc */
+    ytr(im, DNAN);
 
+/*   if (im->gridfit)
+     apply_gridfit(im); */
 
-/**************************************************************
- *** Calculating sizes and locations became a bit confusing ***
- *** so I moved this into a separate function.              ***
- **************************************************************/
-    if (graph_size_location(im, i
-#ifdef WITH_PIECHART
-                            , piechart
-#endif
-        ) == -1)
-        return -1;
 
     /* the actual graph is created by going through the individual
        graph elements and then drawing them */
+    cairo_surface_destroy(im->surface);
+
+    switch (im->imgformat) {
+    case IF_PNG:
+        im->surface =
+            cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                       im->ximg * im->zoom,
+                                       im->yimg * im->zoom);
+        break;
+    case IF_PDF:
+        im->surface =
+            cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom,
+                                     im->yimg * im->zoom);
+        break;
+    case IF_EPS:
+        im->surface =
+            cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom,
+                                    im->yimg * im->zoom);
+        break;
+    case IF_SVG:
+        im->surface =
+            cairo_svg_surface_create(im->graphfile, im->ximg * im->zoom,
+                                     im->yimg * im->zoom);
+        cairo_svg_surface_restrict_to_version(im->surface,
+                                              CAIRO_SVG_VERSION_1_1);
+        break;
+    };
+    im->cr = cairo_create(im->surface);
+    pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100);
+    cairo_set_antialias(im->cr, im->graph_antialias);
+    cairo_scale(im->cr, im->zoom, im->zoom);
 
-    node = gfx_new_area(im->canvas,
-                        0, 0,
-                        0, im->yimg,
-                        im->ximg, im->yimg, im->graph_col[GRC_BACK]);
+    gfx_new_area(im,
+                 0, 0,
+                 0, im->yimg, im->ximg, im->yimg, im->graph_col[GRC_BACK]);
 
-    gfx_add_point(node, im->ximg, 0);
+    gfx_add_point(im, im->ximg, 0);
+    gfx_close_path(im);
 
-#ifdef WITH_PIECHART
-    if (piechart != 2) {
-#endif
-        node = gfx_new_area(im->canvas,
-                            im->xorigin, im->yorigin,
-                            im->xorigin + im->xsize, im->yorigin,
-                            im->xorigin + im->xsize, im->yorigin - im->ysize,
-                            im->graph_col[GRC_CANVAS]);
-
-        gfx_add_point(node, im->xorigin, im->yorigin - im->ysize);
-
-        if (im->minval > 0.0)
-            areazero = im->minval;
-        if (im->maxval < 0.0)
-            areazero = im->maxval;
-#ifdef WITH_PIECHART
-    }
-#endif
+    gfx_new_area(im,
+                 im->xorigin, im->yorigin,
+                 im->xorigin + im->xsize, im->yorigin,
+                 im->xorigin + im->xsize, im->yorigin - im->ysize,
+                 im->graph_col[GRC_CANVAS]);
 
-#ifdef WITH_PIECHART
-    if (piechart) {
-        pie_part(im, im->graph_col[GRC_CANVAS], im->pie_x, im->pie_y,
-                 im->piesize * 0.5, 0, 2 * M_PI);
-    }
-#endif
+    gfx_add_point(im, im->xorigin, im->yorigin - im->ysize);
+    gfx_close_path(im);
+
+    if (im->minval > 0.0)
+        areazero = im->minval;
+    if (im->maxval < 0.0)
+        areazero = im->maxval;
 
     for (i = 0; i < im->gdes_c; i++) {
         switch (im->gdes[i].gf) {
@@ -2881,20 +2979,20 @@ int graph_paint(
                 if (!isnan(im->gdes[i].p_data[ii]) &&
                     im->gdes[i].p_data[ii] != 0.0) {
                     if (im->gdes[i].yrule > 0) {
-                        gfx_new_line(im->canvas,
-                                     im->xorigin + ii, im->yorigin,
-                                     im->xorigin + ii,
-                                     im->yorigin -
-                                     im->gdes[i].yrule * im->ysize, 1.0,
-                                     im->gdes[i].col);
+                        gfx_line(im,
+                                 im->xorigin + ii, im->yorigin,
+                                 im->xorigin + ii,
+                                 im->yorigin -
+                                 im->gdes[i].yrule * im->ysize, 1.0,
+                                 im->gdes[i].col);
                     } else if (im->gdes[i].yrule < 0) {
-                        gfx_new_line(im->canvas,
-                                     im->xorigin + ii,
-                                     im->yorigin - im->ysize,
-                                     im->xorigin + ii,
-                                     im->yorigin - (1 -
-                                                    im->gdes[i].yrule) *
-                                     im->ysize, 1.0, im->gdes[i].col);
+                        gfx_line(im,
+                                 im->xorigin + ii,
+                                 im->yorigin - im->ysize,
+                                 im->xorigin + ii,
+                                 im->yorigin - (1 -
+                                                im->gdes[i].yrule) *
+                                 im->ysize, 1.0, im->gdes[i].col);
 
                     }
                 }
@@ -2925,52 +3023,74 @@ int graph_paint(
                we draw a square from t-1 to t with the value a.
 
                ********************************************************* */
-            if (im->gdes[i].col != 0x0) {
+            if (im->gdes[i].col.alpha != 0.0) {
                 /* GF_LINE and friend */
                 if (im->gdes[i].gf == GF_LINE) {
                     double    last_y = 0.0;
+                    int       draw_on = 0;
 
-                    node = NULL;
+                    cairo_save(im->cr);
+                    cairo_new_path(im->cr);
+
+                    cairo_set_line_width(im->cr, im->gdes[i].linewidth);
                     for (ii = 1; ii < im->xsize; ii++) {
                         if (isnan(im->gdes[i].p_data[ii])
                             || (im->slopemode == 1
                                 && isnan(im->gdes[i].p_data[ii - 1]))) {
-                            node = NULL;
+                            draw_on = 0;
                             continue;
                         }
-                        if (node == NULL) {
+                        if (draw_on == 0) {
                             last_y = ytr(im, im->gdes[i].p_data[ii]);
                             if (im->slopemode == 0) {
-                                node = gfx_new_line(im->canvas,
-                                                    ii - 1 + im->xorigin,
-                                                    last_y, ii + im->xorigin,
-                                                    last_y,
-                                                    im->gdes[i].linewidth,
-                                                    im->gdes[i].col);
+                                double    x = ii - 1 + im->xorigin;
+                                double    y = last_y;
+
+                                gfx_line_fit(im, &x, &y);
+                                cairo_move_to(im->cr, x, y);
+                                x = ii + im->xorigin;
+                                y = last_y;
+                                gfx_line_fit(im, &x, &y);
+                                cairo_line_to(im->cr, x, y);
                             } else {
-                                node = gfx_new_line(im->canvas,
-                                                    ii - 1 + im->xorigin,
-                                                    ytr(im,
-                                                        im->gdes[i].
-                                                        p_data[ii - 1]),
-                                                    ii + im->xorigin, last_y,
-                                                    im->gdes[i].linewidth,
-                                                    im->gdes[i].col);
+                                double    x = ii - 1 + im->xorigin;
+                                double    y = ytr(im,
+                                                  im->gdes[i].p_data[ii - 1]);
+
+                                gfx_line_fit(im, &x, &y);
+                                cairo_move_to(im->cr, x, y);
+                                x = ii + im->xorigin;
+                                y = last_y;
+                                gfx_line_fit(im, &x, &y);
+                                cairo_line_to(im->cr, x, y);
                             }
+                            draw_on = 1;
                         } else {
-                            double    new_y = ytr(im, im->gdes[i].p_data[ii]);
+                            double    x1 = ii + im->xorigin;
+                            double    y1 = ytr(im, im->gdes[i].p_data[ii]);
 
                             if (im->slopemode == 0
-                                && !AlmostEqual2sComplement(new_y, last_y,
-                                                            4)) {
-                                gfx_add_point(node, ii - 1 + im->xorigin,
-                                              new_y);
+                                && !AlmostEqual2sComplement(y1, last_y, 4)) {
+                                double    x = ii - 1 + im->xorigin;
+                                double    y = y1;
+
+                                gfx_line_fit(im, &x, &y);
+                                cairo_line_to(im->cr, x, y);
                             };
-                            last_y = new_y;
-                            gfx_add_point(node, ii + im->xorigin, new_y);
+                            last_y = y1;
+                            gfx_line_fit(im, &x1, &y1);
+                            cairo_line_to(im->cr, x1, y1);
                         };
 
                     }
+                    cairo_set_source_rgba(im->cr, im->gdes[i].col.red,
+                                          im->gdes[i].col.green,
+                                          im->gdes[i].col.blue,
+                                          im->gdes[i].col.alpha);
+                    cairo_set_line_cap(im->cr, CAIRO_LINE_CAP_ROUND);
+                    cairo_set_line_join(im->cr, CAIRO_LINE_JOIN_ROUND);
+                    cairo_stroke(im->cr);
+                    cairo_restore(im->cr);
                 } else {
                     int       idxI = -1;
                     double   *foreY = malloc(sizeof(double) * im->xsize * 2);
@@ -2994,11 +3114,11 @@ int graph_paint(
                                                               4)) {
                                 cntI++;
                             }
-                            node = gfx_new_area(im->canvas,
-                                                backX[0], backY[0],
-                                                foreX[0], foreY[0],
-                                                foreX[cntI], foreY[cntI],
-                                                im->gdes[i].col);
+                            gfx_new_area(im,
+                                         backX[0], backY[0],
+                                         foreX[0], foreY[0],
+                                         foreX[cntI], foreY[cntI],
+                                         im->gdes[i].col);
                             while (cntI < idxI) {
                                 lastI = cntI;
                                 cntI++;
@@ -3012,9 +3132,9 @@ int graph_paint(
                                                                      1], 4)) {
                                     cntI++;
                                 }
-                                gfx_add_point(node, foreX[cntI], foreY[cntI]);
+                                gfx_add_point(im, foreX[cntI], foreY[cntI]);
                             }
-                            gfx_add_point(node, backX[idxI], backY[idxI]);
+                            gfx_add_point(im, backX[idxI], backY[idxI]);
                             while (idxI > 1) {
                                 lastI = idxI;
                                 idxI--;
@@ -3028,10 +3148,11 @@ int graph_paint(
                                                                      1], 4)) {
                                     idxI--;
                                 }
-                                gfx_add_point(node, backX[idxI], backY[idxI]);
+                                gfx_add_point(im, backX[idxI], backY[idxI]);
                             }
                             idxI = -1;
                             drawem = 0;
+                            gfx_close_path(im);
                         }
                         if (drawem != 0) {
                             drawem = 0;
@@ -3040,10 +3161,6 @@ int graph_paint(
                         if (ii == im->xsize)
                             break;
 
-                        /* keep things simple for now, just draw these bars
-                           do not try to build a big and complex area */
-
-
                         if (im->slopemode == 0 && ii == 0) {
                             continue;
                         }
@@ -3061,8 +3178,7 @@ int graph_paint(
                             drawem = 1;
                             continue;
                         }
-                        /* every area has to be wound clock-wise,
-                           so we have to make sur base remains base  */
+
                         if (ybase > ytop) {
                             double    extra = ytop;
 
@@ -3100,20 +3216,6 @@ int graph_paint(
             }
             lastgdes = &(im->gdes[i]);
             break;
-#ifdef WITH_PIECHART
-        case GF_PART:
-            if (isnan(im->gdes[i].yrule))   /* fetch variable */
-                im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
-
-            if (finite(im->gdes[i].yrule)) {    /* even the fetched var can be NaN */
-                pie_part(im, im->gdes[i].col,
-                         im->pie_x, im->pie_y, im->piesize * 0.4,
-                         M_PI * 2.0 * PieStart / 100.0,
-                         M_PI * 2.0 * (PieStart + im->gdes[i].yrule) / 100.0);
-                PieStart += im->gdes[i].yrule;
-            }
-            break;
-#endif
         case GF_STACK:
             rrd_set_error
                 ("STACK should already be turned into LINE or AREA here");
@@ -3122,13 +3224,6 @@ int graph_paint(
 
         }               /* switch */
     }
-#ifdef WITH_PIECHART
-    if (piechart == 2) {
-        im->draw_x_grid = 0;
-        im->draw_y_grid = 0;
-    }
-#endif
-
 
     /* grid_paint also does the text */
     if (!(im->extra_flags & ONLY_GRAPH))
@@ -3145,19 +3240,19 @@ int graph_paint(
         case GF_HRULE:
             if (im->gdes[i].yrule >= im->minval
                 && im->gdes[i].yrule <= im->maxval)
-                gfx_new_line(im->canvas,
-                             im->xorigin, ytr(im, im->gdes[i].yrule),
-                             im->xorigin + im->xsize, ytr(im,
-                                                          im->gdes[i].yrule),
-                             1.0, im->gdes[i].col);
+                gfx_line(im,
+                         im->xorigin, ytr(im, im->gdes[i].yrule),
+                         im->xorigin + im->xsize, ytr(im,
+                                                      im->gdes[i].yrule),
+                         1.0, im->gdes[i].col);
             break;
         case GF_VRULE:
             if (im->gdes[i].xrule >= im->start
                 && im->gdes[i].xrule <= im->end)
-                gfx_new_line(im->canvas,
-                             xtr(im, im->gdes[i].xrule), im->yorigin,
-                             xtr(im, im->gdes[i].xrule),
-                             im->yorigin - im->ysize, 1.0, im->gdes[i].col);
+                gfx_line(im,
+                         xtr(im, im->gdes[i].xrule), im->yorigin,
+                         xtr(im, im->gdes[i].xrule),
+                         im->yorigin - im->ysize, 1.0, im->gdes[i].col);
             break;
         default:
             break;
@@ -3165,22 +3260,18 @@ int graph_paint(
     }
 
 
-    if (strcmp(im->graphfile, "-") == 0) {
-        fo = im->graphhandle ? im->graphhandle : stdout;
-#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
-        /* Change translation mode for stdout to BINARY */
-        _setmode(_fileno(fo), O_BINARY);
-#endif
-    } else {
-        if ((fo = fopen(im->graphfile, "wb")) == NULL) {
-            rrd_set_error("Opening '%s' for write: %s", im->graphfile,
-                          rrd_strerror(errno));
-            return (-1);
+    switch (im->imgformat) {
+    case IF_PNG:
+        if (cairo_surface_write_to_png(im->surface, im->graphfile) !=
+            CAIRO_STATUS_SUCCESS) {
+            rrd_set_error("Could not save png to '%s'", im->graphfile);
+            return 1;
         }
+        break;
+    default:
+        cairo_show_page(im->cr);
+        break;
     }
-    gfx_render(im->canvas, im->ximg, im->yimg, 0x00000000, fo);
-    if (strcmp(im->graphfile, "-") != 0)
-        fclose(fo);
     return 0;
 }
 
@@ -3190,7 +3281,7 @@ int graph_paint(
  *****************************************************/
 
 int gdes_alloc(
-    image_desc_t * im)
+    image_desc_t *im)
 {
 
     im->gdes_c++;
@@ -3217,8 +3308,11 @@ int gdes_alloc(
     im->gdes[im->gdes_c - 1].data_first = 0;
     im->gdes[im->gdes_c - 1].p_data = NULL;
     im->gdes[im->gdes_c - 1].rpnp = NULL;
-    im->gdes[im->gdes_c - 1].shift = 0;
-    im->gdes[im->gdes_c - 1].col = 0x0;
+    im->gdes[im->gdes_c - 1].shift = 0.0;
+    im->gdes[im->gdes_c - 1].col.red = 0.0;
+    im->gdes[im->gdes_c - 1].col.green = 0.0;
+    im->gdes[im->gdes_c - 1].col.blue = 0.0;
+    im->gdes[im->gdes_c - 1].col.alpha = 0.0;
     im->gdes[im->gdes_c - 1].legend[0] = '\0';
     im->gdes[im->gdes_c - 1].format[0] = '\0';
     im->gdes[im->gdes_c - 1].strftm = 0;
@@ -3273,6 +3367,13 @@ int rrd_graph(
     image_desc_t im;
 
     rrd_graph_init(&im);
+
+    /* a dummy surface so that we can measure text sizes for placements */
+    im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);
+    im.cr = cairo_create(im.surface);
+
+
+    /* not currently using this ... */
     im.graphhandle = stream;
 
     rrd_graph_options(argc, argv, &im);
@@ -3336,15 +3437,14 @@ int rrd_graph(
         }
 
         sprintf((*prdata)[0], im.imginfo, filename,
-                (long) (im.canvas->zoom * im.ximg),
-                (long) (im.canvas->zoom * im.yimg));
+                (long) (im.zoom * im.ximg), (long) (im.zoom * im.yimg));
     }
     im_free(&im);
     return 0;
 }
 
 void rrd_graph_init(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     unsigned int i;
 
@@ -3376,6 +3476,9 @@ void rrd_graph_init(
     im->forceleftspace = 0;
     im->symbol = ' ';
     im->viewfactor = 1.0;
+    im->imgformat = IF_PNG;
+    im->cr = NULL;
+    im->surface = NULL;
     im->extra_flags = 0;
     im->rigid = 0;
     im->gridfit = 1;
@@ -3390,10 +3493,19 @@ void rrd_graph_init(
     im->prt_c = 0;
     im->gdes_c = 0;
     im->gdes = NULL;
-    im->canvas = gfx_new_canvas();
     im->grid_dash_on = 1;
     im->grid_dash_off = 1;
     im->tabwidth = 40.0;
+    im->zoom = 1;
+    im->font_options = cairo_font_options_create();
+    im->graph_antialias = CAIRO_ANTIALIAS_GRAY;
+
+    cairo_font_options_set_hint_style(im->font_options,
+                                      CAIRO_HINT_STYLE_FULL);
+    cairo_font_options_set_hint_metrics(im->font_options,
+                                        CAIRO_HINT_METRICS_ON);
+    cairo_font_options_set_antialias(im->font_options, CAIRO_ANTIALIAS_GRAY);
+
 
     for (i = 0; i < DIM(graph_col); i++)
         im->graph_col[i] = graph_col[i];
@@ -3439,7 +3551,7 @@ void rrd_graph_init(
 void rrd_graph_options(
     int argc,
     char *argv[],
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       stroff;
     char     *parsetime_error = NULL;
@@ -3447,7 +3559,7 @@ void rrd_graph_options(
     time_t    start_tmp = 0, end_tmp = 0;
     long      long_tmp;
     struct rrd_time_value start_tv, end_tv;
-    gfx_color_t color;
+    long unsigned int color;
 
     optind = 0;
     opterr = 0;         /* initialize getopt */
@@ -3468,6 +3580,7 @@ void rrd_graph_options(
             {"vertical-label", required_argument, 0, 'v'},
             {"width", required_argument, 0, 'w'},
             {"height", required_argument, 0, 'h'},
+            {"full-size-mode", no_argument, 0, 'D'},
             {"interlaced", no_argument, 0, 'i'},
             {"upper-limit", required_argument, 0, 'u'},
             {"lower-limit", required_argument, 0, 'l'},
@@ -3497,6 +3610,7 @@ void rrd_graph_options(
             {"step", required_argument, 0, 'S'},
             {"tabwidth", required_argument, 0, 'T'},
             {"font-render-mode", required_argument, 0, 'R'},
+            {"graph-render-mode", required_argument, 0, 'G'},
             {"font-smoothing-threshold", required_argument, 0, 'B'},
             {"watermark", required_argument, 0, 'W'},
             {"alt-y-mrtg", no_argument, 0, 1000},   /* this has no effect it is just here to save old apps from crashing when they use it */
@@ -3507,7 +3621,7 @@ void rrd_graph_options(
         int       col_start, col_end;
 
         opt = getopt_long(argc, argv,
-                          "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:",
+                          "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:",
                           long_options, &option_index);
 
         if (opt == EOF)
@@ -3669,8 +3783,11 @@ void rrd_graph_options(
             }
             im->ysize = long_tmp;
             break;
+        case 'D':
+            im->extra_flags |= FULL_SIZE_MODE;
+            break;
         case 'i':
-            im->canvas->interlaced = 1;
+            /* interlaced png not supported at the moment */
             break;
         case 'r':
             im->rigid = 1;
@@ -3679,7 +3796,7 @@ void rrd_graph_options(
             im->imginfo = optarg;
             break;
         case 'a':
-            if ((int) (im->canvas->imgformat = if_conv(optarg)) == -1) {
+            if ((int) (im->imgformat = if_conv(optarg)) == -1) {
                 rrd_set_error("unsupported graphics format '%s'", optarg);
                 return;
             }
@@ -3724,7 +3841,7 @@ void rrd_graph_options(
                     return;
                 }
                 if ((ci = grc_conv(col_nam)) != -1) {
-                    im->graph_col[ci] = color;
+                    im->graph_col[ci] = gfx_hex_to_col(color);
                 } else {
                     rrd_set_error("invalid color name '%s'", col_nam);
                     return;
@@ -3765,8 +3882,8 @@ void rrd_graph_options(
             break;
         }
         case 'm':
-            im->canvas->zoom = atof(optarg);
-            if (im->canvas->zoom <= 0.0) {
+            im->zoom = atof(optarg);
+            if (im->zoom <= 0.0) {
                 rrd_set_error("zoom factor must be > 0");
                 return;
             }
@@ -3777,20 +3894,38 @@ void rrd_graph_options(
             break;
 
         case 'R':
+            if (strcmp(optarg, "normal") == 0) {
+                cairo_font_options_set_antialias(im->font_options,
+                                                 CAIRO_ANTIALIAS_GRAY);
+                cairo_font_options_set_hint_style(im->font_options,
+                                                  CAIRO_HINT_STYLE_FULL);
+            } else if (strcmp(optarg, "light") == 0) {
+                cairo_font_options_set_antialias(im->font_options,
+                                                 CAIRO_ANTIALIAS_GRAY);
+                cairo_font_options_set_hint_style(im->font_options,
+                                                  CAIRO_HINT_STYLE_SLIGHT);
+            } else if (strcmp(optarg, "mono") == 0) {
+                cairo_font_options_set_antialias(im->font_options,
+                                                 CAIRO_ANTIALIAS_NONE);
+                cairo_font_options_set_hint_style(im->font_options,
+                                                  CAIRO_HINT_STYLE_FULL);
+            } else {
+                rrd_set_error("unknown font-render-mode '%s'", optarg);
+                return;
+            }
+            break;
+        case 'G':
             if (strcmp(optarg, "normal") == 0)
-                im->canvas->aa_type = AA_NORMAL;
-            else if (strcmp(optarg, "light") == 0)
-                im->canvas->aa_type = AA_LIGHT;
+                im->graph_antialias = CAIRO_ANTIALIAS_GRAY;
             else if (strcmp(optarg, "mono") == 0)
-                im->canvas->aa_type = AA_NONE;
+                im->graph_antialias = CAIRO_ANTIALIAS_NONE;
             else {
-                rrd_set_error("unknown font-render-mode '%s'", optarg);
+                rrd_set_error("unknown graph-render-mode '%s'", optarg);
                 return;
             }
             break;
-
         case 'B':
-            im->canvas->font_aa_threshold = atof(optarg);
+            /* not supported curently */
             break;
 
         case 'W':
@@ -3841,7 +3976,7 @@ void rrd_graph_options(
 }
 
 int rrd_graph_color(
-    image_desc_t * im,
+    image_desc_t *im,
     char *var,
     char *err,
     int optional)
@@ -3859,7 +3994,7 @@ int rrd_graph_color(
     } else {
         int       n = 0;
         char     *rest;
-        gfx_color_t col;
+        long unsigned int col;
 
         rest = strstr(color, ":");
         if (rest != NULL)
@@ -3883,7 +4018,7 @@ int rrd_graph_color(
         }
         if (rrd_test_error())
             return 0;
-        gdp->col = col;
+        gdp->col = gfx_hex_to_col(col);
         return n;
     }
 }