/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/plugin/pango/gvrender_pango.c

Go to the documentation of this file.
00001 /* $Id: gvrender_pango.c,v 1.58 2008/02/06 17:23:22 ellson Exp $ $Revision: 1.58 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020 
00021 #ifdef HAVE_STDLIB_H
00022 #include <stdlib.h>
00023 #endif
00024 #ifdef HAVE_STRING_H
00025 #include <string.h>
00026 #endif
00027 #include <fcntl.h>
00028 
00029 #if defined(HAVE_FENV_H) && defined(HAVE_FESETENV) && defined(HAVE_FEGETENV) && defined(HAVE_FEENABLEEXCEPT)
00030 
00031 /* _GNU_SOURCE is needed (supposedly) for the feenableexcept
00032  * prototype to be defined in fenv.h on GNU systems.
00033  * Presumably it will do no harm on other systems.
00034  */
00035 #ifndef _GNU_SOURCE
00036 #define _GNU_SOURCE
00037 #endif
00038 
00039 /* We are not supposed to need __USE_GNU, but I can't see
00040  * how to get the prototype for fedisableexcept from
00041  * /usr/include/fenv.h without it.
00042  */
00043 #ifndef __USE_GNU
00044 #define __USE_GNU
00045 #endif
00046 
00047 #if 0
00048 # include <fenv.h>
00049 #elif HAVE_FPU_CONTROL_H
00050 # include <fpu_control.h>
00051 #elif HAVE_SYS_FPU_H
00052 # include <sys/fpu.h>
00053 #endif
00054 #endif
00055 
00056 #include "gvplugin_render.h"
00057 #include "gvplugin_device.h"
00058 
00059 #ifdef HAVE_PANGOCAIRO
00060 #include <pango/pangocairo.h>
00061 
00062 typedef enum {
00063                 FORMAT_GLITZ,
00064                 FORMAT_CAIRO,
00065                 FORMAT_PNG,
00066                 FORMAT_PS,
00067                 FORMAT_PDF,
00068                 FORMAT_QUARTZ,
00069                 FORMAT_SVG,
00070     } format_type;
00071 
00072 #define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
00073 
00074 /* FIXME - FONT_DPI also defined in gvtextlayout_pango.c - need shared header */
00075 #define FONT_DPI 96.
00076 
00077 static double dashed[] = {6.};
00078 static int dashed_len = ARRAY_SIZE(dashed);
00079 
00080 static double dotted[] = {2., 6.};
00081 static int dotted_len = ARRAY_SIZE(dotted);
00082 
00083 #ifdef CAIRO_HAS_PS_SURFACE
00084 #include <cairo-ps.h>
00085 #endif
00086 
00087 #ifdef CAIRO_HAS_PDF_SURFACE
00088 #include <cairo-pdf.h>
00089 #endif
00090 
00091 #ifdef CAIRO_HAS_SVG_SURFACE
00092 #include <cairo-svg.h>
00093 #endif
00094 
00095 #ifdef CAIRO_HAS_QUARTZ_SURFACE
00096 #include <cairo-quartz.h>
00097 #endif
00098 
00099 #ifdef CAIRO_HAS_GLITZ
00100 #include <cairo-glitz.h>
00101 #endif
00102 
00103 #if 0
00104 #if defined(HAVE_FENV_H) && defined(HAVE_FESETENV) && defined(HAVE_FEGETENV) && defined(HAVE_FEENABLEEXCEPT)
00105 /* place to save fp environment temporarily */
00106 static fenv_t fenv; /* FIXME - not thread safe */
00107 #endif
00108 #endif
00109 
00110 static void cairogen_set_color(cairo_t * cr, gvcolor_t * color)
00111 {
00112     cairo_set_source_rgba(cr, color->u.RGBA[0], color->u.RGBA[1],
00113                         color->u.RGBA[2], color->u.RGBA[3]);
00114 }
00115 
00116 extern size_t gvdevice_write(GVJ_t * job, const unsigned char *s, unsigned int len);
00117 
00118 static cairo_status_t
00119 writer (void *closure, const unsigned char *data, unsigned int length)
00120 {
00121     if (length == gvdevice_write((GVJ_t *)closure, data, length))
00122         return CAIRO_STATUS_SUCCESS;
00123     return CAIRO_STATUS_WRITE_ERROR;
00124 }
00125 
00126 static void cairogen_begin_page(GVJ_t * job)
00127 {
00128     cairo_t *cr = NULL;
00129     cairo_surface_t *surface;
00130 
00131 #if 0
00132 #if defined(HAVE_FENV_H) && defined(HAVE_FESETENV) && defined(HAVE_FEGETENV) && defined(HAVE_FEDISABLEEXCEPT)
00133     /* cairo generates FE_INVALID and other exceptions we 
00134      * want to ignore for now.  Save the current fenv and
00135      * set one just for cairo.
00136      * The fenv is restored in cairogen_end_graph  */
00137     fegetenv(&fenv);
00138     fedisableexcept(FE_ALL_EXCEPT);
00139 #endif
00140 #endif
00141 
00142     if (job->context) 
00143         cr = (cairo_t *) job->context;
00144     if (job->external_context && cr)
00145         cairo_save(cr);
00146     else {
00147         if (cr)
00148             cairo_destroy(cr);
00149         switch (job->render.id) {
00150         case FORMAT_PS:
00151             surface = cairo_ps_surface_create_for_stream (writer,
00152                         job, job->width, job->height);
00153             break;
00154         case FORMAT_PDF:
00155             surface = cairo_pdf_surface_create_for_stream (writer,
00156                         job, job->width, job->height);
00157             break;
00158         case FORMAT_SVG:
00159             surface = cairo_svg_surface_create_for_stream (writer,
00160                         job, job->width, job->height);
00161             break;
00162         case FORMAT_CAIRO:
00163         case FORMAT_PNG:
00164         default:
00165             surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
00166                         job->width, job->height);
00167             if (job->common->verbose)
00168                 fprintf(stderr,
00169                         "%s: allocating a %dK cairo image surface\n",
00170                         job->common->cmdname,
00171                         ROUND(job->width * job->height * 4 / 1024.));
00172             break;
00173         }
00174         cr = cairo_create(surface);
00175         cairo_surface_destroy (surface);
00176         job->context = (void *) cr;
00177     }
00178 
00179     cairo_scale(cr, job->scale.x, job->scale.y);
00180     cairo_rotate(cr, -job->rotation * M_PI / 180.);
00181     cairo_translate(cr, job->translation.x, -job->translation.y);
00182 
00183     cairo_rectangle(cr,
00184             job->clip.LL.x,
00185             - job->clip.LL.y,
00186             job->clip.UR.x - job->clip.LL.x,
00187             - (job->clip.UR.y - job->clip.LL.y));
00188     cairo_clip(cr);
00189 }
00190 
00191 static void cairogen_end_page(GVJ_t * job)
00192 {
00193     cairo_t *cr = (cairo_t *) job->context;
00194     cairo_surface_t *surface;
00195     cairo_status_t status;
00196 
00197     switch (job->render.id) {
00198 
00199 #ifdef CAIRO_HAS_PNG_FUNCTIONS
00200     case FORMAT_PNG:
00201         surface = cairo_get_target(cr);
00202         cairo_surface_write_to_png_stream(surface, writer, job);
00203         break;
00204 #endif
00205 
00206     case FORMAT_PS:
00207     case FORMAT_PDF:
00208     case FORMAT_SVG:
00209         cairo_show_page(cr);
00210         surface = cairo_surface_reference(cairo_get_target(cr));
00211         cairo_destroy(cr);
00212         job->context = NULL;
00213         cairo_surface_finish(surface);
00214         status = cairo_surface_status(surface);
00215         cairo_surface_destroy(surface);
00216         if (status != CAIRO_STATUS_SUCCESS)
00217             fprintf(stderr, "cairo: %s\n", cairo_status_to_string(status));
00218         break;
00219 
00220     case FORMAT_CAIRO:
00221     default:
00222         surface = cairo_get_target(cr);
00223         job->imagedata = cairo_image_surface_get_data(surface); 
00224         break;
00225         /* formatting will be done by gvdevice_format() */
00226     }
00227 
00228     if (job->external_context)
00229         cairo_restore(cr);
00230 
00231 #if 0
00232 #if defined HAVE_FENV_H && defined HAVE_FESETENV && defined HAVE_FEGETENV && defined(HAVE_FEENABLEEXCEPT)
00233     /* Restore FP environment */
00234     fesetenv(&fenv);
00235 #endif
00236 #endif
00237 }
00238 
00239 static void cairogen_textpara(GVJ_t * job, pointf p, textpara_t * para)
00240 {
00241     obj_state_t *obj = job->obj;
00242     cairo_t *cr = (cairo_t *) job->context;
00243 
00244     cairo_set_dash (cr, dashed, 0, 0.0);  /* clear any dashing */
00245     cairogen_set_color(cr, &(obj->pencolor));
00246 
00247     switch (para->just) {
00248     case 'r':
00249         p.x -= para->width;
00250         break;
00251     case 'l':
00252         p.x -= 0.0;
00253         break;
00254     case 'n':
00255     default:
00256         p.x -= para->width / 2.0;
00257         break;
00258     }
00259     p.y += para->yoffset_centerline + para->yoffset_layout;
00260 
00261     cairo_move_to (cr, p.x, -p.y);
00262     cairo_save(cr);
00263     cairo_scale(cr, POINTS_PER_INCH / FONT_DPI, POINTS_PER_INCH / FONT_DPI);
00264     pango_cairo_show_layout(cr, (PangoLayout*)(para->layout));
00265     cairo_restore(cr);
00266 }
00267 
00268 static void cairogen_set_penstyle(GVJ_t *job, cairo_t *cr)
00269 {
00270     obj_state_t *obj = job->obj;
00271 
00272     if (obj->pen == PEN_DASHED) {
00273         cairo_set_dash (cr, dashed, dashed_len, 0.0);
00274     } else if (obj->pen == PEN_DOTTED) {
00275         cairo_set_dash (cr, dotted, dotted_len, 0.0);
00276     } else {
00277         cairo_set_dash (cr, dashed, 0, 0.0);
00278     }
00279     cairo_set_line_width (cr, obj->penwidth);
00280 
00281 }
00282 
00283 static void cairogen_ellipse(GVJ_t * job, pointf * A, int filled)
00284 {
00285     obj_state_t *obj = job->obj;
00286     cairo_t *cr = (cairo_t *) job->context;
00287     cairo_matrix_t matrix;
00288     double rx, ry;
00289 
00290     cairogen_set_penstyle(job, cr);
00291 
00292     cairo_get_matrix(cr, &matrix);
00293     cairo_translate(cr, A[0].x, -A[0].y);
00294 
00295     rx = A[1].x - A[0].x;
00296     ry = A[1].y - A[0].y;
00297     cairo_scale(cr, 1, ry / rx);
00298     cairo_move_to(cr, rx, 0);
00299     cairo_arc(cr, 0, 0, rx, 0, 2 * M_PI);
00300     cairo_close_path(cr);
00301 
00302     cairo_set_matrix(cr, &matrix);
00303 
00304     if (filled) {
00305         cairogen_set_color(cr, &(obj->fillcolor));
00306         cairo_fill_preserve(cr);
00307     }
00308     cairogen_set_color(cr, &(obj->pencolor));
00309     cairo_stroke(cr);
00310 }
00311 
00312 static void
00313 cairogen_polygon(GVJ_t * job, pointf * A, int n, int filled)
00314 {
00315     obj_state_t *obj = job->obj;
00316     cairo_t *cr = (cairo_t *) job->context;
00317     int i;
00318 
00319     cairogen_set_penstyle(job, cr);
00320 
00321     cairo_move_to(cr, A[0].x, -A[0].y);
00322     for (i = 1; i < n; i++)
00323         cairo_line_to(cr, A[i].x, -A[i].y);
00324     cairo_close_path(cr);
00325     if (filled) {
00326         cairogen_set_color(cr, &(obj->fillcolor));
00327         cairo_fill_preserve(cr);
00328     }
00329     cairogen_set_color(cr, &(obj->pencolor));
00330     cairo_stroke(cr);
00331 }
00332 
00333 static void
00334 cairogen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00335                 int arrow_at_end, int filled)
00336 {
00337     obj_state_t *obj = job->obj;
00338     cairo_t *cr = (cairo_t *) job->context;
00339     int i;
00340 
00341     cairogen_set_penstyle(job, cr);
00342 
00343     cairo_move_to(cr, A[0].x, -A[0].y);
00344     for (i = 1; i < n; i += 3)
00345         cairo_curve_to(cr, A[i].x, -A[i].y, A[i + 1].x, -A[i + 1].y,
00346                        A[i + 2].x, -A[i + 2].y);
00347     if (filled) {
00348         cairogen_set_color(cr, &(obj->fillcolor));
00349         cairo_fill_preserve(cr);
00350     }
00351     cairogen_set_color(cr, &(obj->pencolor));
00352     cairo_stroke(cr);
00353 }
00354 
00355 static void
00356 cairogen_polyline(GVJ_t * job, pointf * A, int n)
00357 {
00358     obj_state_t *obj = job->obj;
00359     cairo_t *cr = (cairo_t *) job->context;
00360     int i;
00361 
00362     cairogen_set_penstyle(job, cr);
00363 
00364     cairo_set_line_width (cr, obj->penwidth * job->scale.x);
00365     cairo_move_to(cr, A[0].x, -A[0].y);
00366     for (i = 1; i < n; i++)
00367         cairo_line_to(cr, A[i].x, -A[i].y);
00368     cairogen_set_color(cr, &(obj->pencolor));
00369     cairo_stroke(cr);
00370 }
00371 
00372 static gvrender_engine_t cairogen_engine = {
00373     0,                          /* cairogen_begin_job */
00374     0,                          /* cairogen_end_job */
00375     0,                          /* cairogen_begin_graph */
00376     0,                          /* cairogen_end_graph */
00377     0,                          /* cairogen_begin_layer */
00378     0,                          /* cairogen_end_layer */
00379     cairogen_begin_page,
00380     cairogen_end_page,
00381     0,                          /* cairogen_begin_cluster */
00382     0,                          /* cairogen_end_cluster */
00383     0,                          /* cairogen_begin_nodes */
00384     0,                          /* cairogen_end_nodes */
00385     0,                          /* cairogen_begin_edges */
00386     0,                          /* cairogen_end_edges */
00387     0,                          /* cairogen_begin_node */
00388     0,                          /* cairogen_end_node */
00389     0,                          /* cairogen_begin_edge */
00390     0,                          /* cairogen_end_edge */
00391     0,                          /* cairogen_begin_anchor */
00392     0,                          /* cairogen_end_anchor */
00393     cairogen_textpara,
00394     0,                          /* cairogen_resolve_color */
00395     cairogen_ellipse,
00396     cairogen_polygon,
00397     cairogen_bezier,
00398     cairogen_polyline,
00399     0,                          /* cairogen_comment */
00400     0,                          /* cairogen_library_shape */
00401 };
00402 
00403 static gvrender_features_t render_features_cairo = {
00404     GVRENDER_Y_GOES_DOWN
00405         | GVRENDER_DOES_TRANSFORM, /* flags */
00406     4.,                         /* default pad - graph units */
00407     0,                          /* knowncolors */
00408     0,                          /* sizeof knowncolors */
00409     RGBA_DOUBLE,                /* color_type */
00410 };
00411 
00412 static gvdevice_features_t device_features_png = {
00413     GVDEVICE_BINARY_FORMAT
00414       | GVDEVICE_DOES_TRUECOLOR,/* flags */
00415     {0.,0.},                    /* default margin - points */
00416     {0.,0.},                    /* default page width, height - points */
00417     {96.,96.},                  /* typical monitor dpi */
00418 };
00419 
00420 static gvdevice_features_t device_features_ps = {
00421     GVDEVICE_DOES_TRUECOLOR,    /* flags */
00422     {36.,36.},                  /* default margin - points */
00423     {0.,0.},                    /* default page width, height - points */
00424     {72.,72.},                  /* postscript 72 dpi */
00425 };
00426 
00427 static gvdevice_features_t device_features_pdf = {
00428     GVDEVICE_BINARY_FORMAT
00429       | GVDEVICE_DOES_TRUECOLOR,/* flags */
00430     {36.,36.},                  /* default margin - points */
00431     {0.,0.},                    /* default page width, height - points */
00432     {72.,72.},                  /* postscript 72 dpi */
00433 };
00434 
00435 static gvdevice_features_t device_features_svg = {
00436     GVDEVICE_DOES_TRUECOLOR,    /* flags */
00437     {0.,0.},                    /* default margin - points */
00438     {0.,0.},                    /* default page width, height - points */
00439     {72.,72.},                  /* svg 72 dpi */
00440 };
00441 #endif
00442 
00443 gvplugin_installed_t gvrender_pango_types[] = {
00444 #ifdef HAVE_PANGOCAIRO
00445     {FORMAT_CAIRO, "cairo", 10, &cairogen_engine, &render_features_cairo},
00446 #endif
00447     {0, NULL, 0, NULL, NULL}
00448 };
00449 
00450 gvplugin_installed_t gvdevice_pango_types[] = {
00451 #ifdef HAVE_PANGOCAIRO
00452 #ifdef CAIRO_HAS_PNG_FUNCTIONS
00453     {FORMAT_PNG, "png:cairo", 10, NULL, &device_features_png},
00454 #endif
00455 #ifdef CAIRO_HAS_PS_SURFACE
00456     {FORMAT_PS, "ps:cairo", -10, NULL, &device_features_ps},
00457 #endif
00458 #ifdef CAIRO_HAS_PDF_SURFACE
00459     {FORMAT_PDF, "pdf:cairo", 10, NULL, &device_features_pdf},
00460 #endif
00461 #ifdef CAIRO_HAS_SVG_SURFACE
00462     {FORMAT_SVG, "svg:cairo", -10, NULL, &device_features_svg},
00463 #endif
00464 //#ifdef CAIRO_HAS_XCB_SURFACE
00465 //    {FORMAT_XCB, "xcb:cairo", 0, NULL, &device_features_xcb},
00466 //#endif
00467 //#ifdef CAIRO_HAS_SDL_SURFACE
00468 //    {FORMAT_SDL, "sdl:cairo", 0, NULL, &device_features_sdl},
00469 //#endif
00470 //#ifdef CAIRO_HAS_GLITZ_SURFACE
00471 //    {FORMAT_GLITZ, "glitz:cairo", 0, NULL, &device_features_glitz},
00472 //#endif
00473 //#ifdef CAIRO_HAS_QUARTZ_SURFACE
00474 //    {FORMAT_QUARTZ, "quartz:cairo", 0, NULL, &device_features_quartz},
00475 //#endif
00476 //#ifdef CAIRO_HAS_WIN32_SURFACE
00477 //    {FORMAT_WIN32, "win32:cairo", 0, NULL, &device_features_win32},
00478 //#endif
00479 #endif
00480     {0, NULL, 0, NULL, NULL}
00481 };

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1