00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00032
00033
00034
00035 #ifndef _GNU_SOURCE
00036 #define _GNU_SOURCE
00037 #endif
00038
00039
00040
00041
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
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
00106 static fenv_t fenv;
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
00134
00135
00136
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
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
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);
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,
00374 0,
00375 0,
00376 0,
00377 0,
00378 0,
00379 cairogen_begin_page,
00380 cairogen_end_page,
00381 0,
00382 0,
00383 0,
00384 0,
00385 0,
00386 0,
00387 0,
00388 0,
00389 0,
00390 0,
00391 0,
00392 0,
00393 cairogen_textpara,
00394 0,
00395 cairogen_ellipse,
00396 cairogen_polygon,
00397 cairogen_bezier,
00398 cairogen_polyline,
00399 0,
00400 0,
00401 };
00402
00403 static gvrender_features_t render_features_cairo = {
00404 GVRENDER_Y_GOES_DOWN
00405 | GVRENDER_DOES_TRANSFORM,
00406 4.,
00407 0,
00408 0,
00409 RGBA_DOUBLE,
00410 };
00411
00412 static gvdevice_features_t device_features_png = {
00413 GVDEVICE_BINARY_FORMAT
00414 | GVDEVICE_DOES_TRUECOLOR,
00415 {0.,0.},
00416 {0.,0.},
00417 {96.,96.},
00418 };
00419
00420 static gvdevice_features_t device_features_ps = {
00421 GVDEVICE_DOES_TRUECOLOR,
00422 {36.,36.},
00423 {0.,0.},
00424 {72.,72.},
00425 };
00426
00427 static gvdevice_features_t device_features_pdf = {
00428 GVDEVICE_BINARY_FORMAT
00429 | GVDEVICE_DOES_TRUECOLOR,
00430 {36.,36.},
00431 {0.,0.},
00432 {72.,72.},
00433 };
00434
00435 static gvdevice_features_t device_features_svg = {
00436 GVDEVICE_DOES_TRUECOLOR,
00437 {0.,0.},
00438 {0.,0.},
00439 {72.,72.},
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
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 #endif
00480 {0, NULL, 0, NULL, NULL}
00481 };