Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
gvrender_pango.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <assert.h>
14#include <errno.h>
15#include <limits.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20#include <common/const.h>
21#include <gvc/gvplugin_render.h>
22#include <common/utils.h>
23#include <gvc/gvplugin_device.h>
24#include <gvc/gvio.h>
25#include <math.h>
26#include <util/agxbuf.h>
27
28#include "gvplugin_pango.h"
29
30#include <pango/pangocairo.h>
31
40
41#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
42
43static double dashed[] = {6.};
45
46static double dotted[] = {2., 6.};
48
49#ifdef CAIRO_HAS_PS_SURFACE
50#include <cairo-ps.h>
51#endif
52
53#ifdef CAIRO_HAS_PDF_SURFACE
54#include <cairo-pdf.h>
55#endif
56
57#ifdef CAIRO_HAS_SVG_SURFACE
58#include <cairo-svg.h>
59#endif
60
61static void cairogen_polyline(GVJ_t *job, pointf *A, size_t n);
62
63static void cairogen_set_color(cairo_t * cr, gvcolor_t * color)
64{
65 cairo_set_source_rgba(cr, color->u.RGBA[0], color->u.RGBA[1],
66 color->u.RGBA[2], color->u.RGBA[3]);
67}
68
69static void cairogen_add_color_stop_rgba(cairo_pattern_t *pat, double stop , gvcolor_t * color)
70{
71 cairo_pattern_add_color_stop_rgba (pat, stop,color->u.RGBA[0], color->u.RGBA[1],
72 color->u.RGBA[2], color->u.RGBA[3]);
73}
74
75
76static cairo_status_t
77writer (void *closure, const unsigned char *data, unsigned int length)
78{
79 if (length == gvwrite(closure, (const char*)data, length))
80 return CAIRO_STATUS_SUCCESS;
81 return CAIRO_STATUS_WRITE_ERROR;
82}
83
84static void cairogen_begin_job(GVJ_t * job)
85{
86 if (job->external_context && job->context)
87 cairo_save(job->context);
88}
89
90static void cairogen_end_job(GVJ_t * job)
91{
92 cairo_t *cr = job->context;
93
94 if (job->external_context)
95 cairo_restore(cr);
96 else {
97 cairo_destroy(cr);
98 job->context = NULL;
99 }
100}
101
102static const double CAIRO_XMAX = 32767;
103static const double CAIRO_YMAX = 32767;
104
105static void cairogen_begin_page(GVJ_t * job)
106{
107 cairo_t *cr = job->context;
108 cairo_surface_t *surface;
109 cairo_status_t status;
110
111 if (cr == NULL) {
112 switch (job->render.id) {
113 case FORMAT_PS:
114 case FORMAT_EPS:
115#ifdef CAIRO_HAS_PS_SURFACE
116 surface = cairo_ps_surface_create_for_stream (writer,
117 job, job->width, job->height);
118 if (job->render.id == FORMAT_EPS)
119 cairo_ps_surface_set_eps (surface, TRUE);
120#endif
121 break;
122 case FORMAT_PDF:
123#ifdef CAIRO_HAS_PDF_SURFACE
124 surface = cairo_pdf_surface_create_for_stream (writer,
125 job, job->width, job->height);
126
127 {
128 const char *source_date_epoch = getenv("SOURCE_DATE_EPOCH");
129 if (source_date_epoch != NULL) {
130 char *end = NULL;
131 errno = 0;
132 long epoch = strtol(source_date_epoch, &end, 10);
133 // from https://reproducible-builds.org/specs/source-date-epoch/
134 //
135 // If the value is malformed, the build process SHOULD
136 // exit with a non-zero error code.
137 if ((epoch == LONG_MAX && errno != 0) || epoch < 0
138 || *end != '\0') {
139 fprintf(stderr,
140 "malformed value %s for $SOURCE_DATE_EPOCH\n",
141 source_date_epoch);
142 exit(EXIT_FAILURE);
143 }
144 time_t tepoch = (time_t)epoch;
145 struct tm *tm = gmtime(&tepoch);
146 if (tm == NULL) {
147 fprintf(stderr,
148 "malformed value %s for $SOURCE_DATE_EPOCH\n",
149 source_date_epoch);
150 exit(EXIT_FAILURE);
151 }
152#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
153 char iso8601[sizeof("YYYY-MM-DDThh:mm:ss")] = {0};
154 (void)strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%SZ", tm);
155 cairo_pdf_surface_set_metadata(surface,
156 CAIRO_PDF_METADATA_CREATE_DATE,
157 iso8601);
158 cairo_pdf_surface_set_metadata(surface,
159 CAIRO_PDF_METADATA_MOD_DATE,
160 iso8601);
161#endif
162 }
163 }
164#endif
165 break;
166 case FORMAT_SVG:
167#ifdef CAIRO_HAS_SVG_SURFACE
168 surface = cairo_svg_surface_create_for_stream (writer,
169 job, job->width, job->height);
170#endif
171 break;
172 case FORMAT_CAIRO:
173 case FORMAT_PNG:
174 default:
175 if (job->width >= CAIRO_XMAX || job->height >= CAIRO_YMAX) {
176 double scale = fmin(CAIRO_XMAX / job->width, CAIRO_YMAX / job->height);
177 assert(job->width * scale <= UINT_MAX);
178 job->width = (unsigned)(job->width * scale);
179 assert(job->height * scale <= UINT_MAX);
180 job->height = (unsigned)(job->height * scale);
181 job->scale.x *= scale;
182 job->scale.y *= scale;
183 fprintf(stderr,
184 "%s: graph is too large for cairo-renderer bitmaps. Scaling by %g to fit\n",
185 job->common->cmdname, scale);
186 }
187 assert(job->width <= INT_MAX);
188 assert(job->height <= INT_MAX);
189 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
190 (int)job->width, (int)job->height);
191 if (job->common->verbose)
192 fprintf(stderr,
193 "%s: allocating a %.0fK cairo image surface (%d x %d pixels)\n",
194 job->common->cmdname,
195 round(job->width * job->height * 4 / 1024.),
196 job->width, job->height);
197 break;
198 }
199 status = cairo_surface_status(surface);
200 if (status != CAIRO_STATUS_SUCCESS) {
201 fprintf(stderr, "%s: failure to create cairo surface: %s\n",
202 job->common->cmdname,
203 cairo_status_to_string(status));
204 cairo_surface_destroy (surface);
205 return;
206 }
207 cr = cairo_create(surface);
208 cairo_surface_destroy (surface);
209 job->context = cr;
210 }
211
212 cairo_scale(cr, job->scale.x, job->scale.y);
213 cairo_rotate(cr, -job->rotation * M_PI / 180.);
214 cairo_translate(cr, job->translation.x, -job->translation.y);
215
216 cairo_rectangle(cr, job->clip.LL.x, - job->clip.LL.y,
217 job->clip.UR.x - job->clip.LL.x, - (job->clip.UR.y - job->clip.LL.y));
218 cairo_clip(cr);
219}
220
221static void cairogen_end_page(GVJ_t * job)
222{
223 cairo_t *cr = job->context;
224 cairo_surface_t *surface;
225 cairo_status_t status;
226
227 switch (job->render.id) {
228
229#ifdef CAIRO_HAS_PNG_FUNCTIONS
230 case FORMAT_PNG:
231 surface = cairo_get_target(cr);
232 cairo_surface_write_to_png_stream(surface, writer, job);
233 break;
234#endif
235
236 case FORMAT_PS:
237 case FORMAT_PDF:
238 case FORMAT_SVG:
239 cairo_show_page(cr);
240 surface = cairo_surface_reference(cairo_get_target(cr));
241 cairo_surface_finish(surface);
242 status = cairo_surface_status(surface);
243 cairo_surface_destroy(surface);
244 if (status != CAIRO_STATUS_SUCCESS)
245 fprintf(stderr, "cairo: %s\n", cairo_status_to_string(status));
246 break;
247
248 case FORMAT_CAIRO:
249 default:
250 surface = cairo_get_target(cr);
251 if (cairo_image_surface_get_width(surface) == 0 || cairo_image_surface_get_height(surface) == 0) {
252 /* apparently cairo never allocates a surface if nothing was ever written to it */
253/* but suppress this error message since a zero area surface seems to happen during normal operations, particular in -Tx11
254 fprintf(stderr, "ERROR: cairo surface has zero area, this may indicate some problem during rendering shapes.\n");
255 - jce */
256 }
257 job->imagedata = cairo_image_surface_get_data(surface);
258 break;
259 /* formatting will be done by gvdevice_format() */
260 }
261}
262
263static void cairogen_begin_anchor(GVJ_t *job, char *url, char *tooltip, char *target, char *id)
264{
265 obj_state_t *obj = job->obj;
266 cairo_t *cr = job->context;
267 double p0x, p0y, p1x, p1y;
268
269 // suppress unused parameter warnings
270 (void)tooltip;
271 (void)target;
272 (void)id;
273
274 if (url && obj->url_map_p) {
275 p0x = obj->url_map_p[0].x;
276 p0y = -obj->url_map_p[0].y;
277 cairo_user_to_device (cr, &p0x, &p0y);
278 p1x = obj->url_map_p[1].x;
279 p1y = -obj->url_map_p[1].y;
280 cairo_user_to_device (cr, &p1x, &p1y);
281 agxbuf buf = {0};
282 agxbprint(&buf, "rect=[%f %f %f %f] uri='%s'", p0x, p0y, p1x - p0x,
283 p1y - p0y, url);
284#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
285 cairo_tag_begin(cr, CAIRO_TAG_LINK, agxbuse(&buf));
286 cairo_tag_end (cr, CAIRO_TAG_LINK);
287#endif
288 agxbfree(&buf);
289 }
290}
291
292static void cairogen_textspan(GVJ_t * job, pointf p, textspan_t * span)
293{
294 obj_state_t *obj = job->obj;
295 cairo_t *cr = job->context;
296 pointf A[2];
297
298 cairo_set_dash (cr, dashed, 0, 0.0); /* clear any dashing */
299 cairogen_set_color(cr, &obj->pencolor);
300
301 switch (span->just) {
302 case 'r':
303 p.x -= span->size.x;
304 break;
305 case 'l':
306 p.x -= 0.0;
307 break;
308 case 'n':
309 default:
310 p.x -= span->size.x / 2.0;
311 break;
312 }
313 p.y += span->yoffset_centerline + span->yoffset_layout;
314
315 cairo_move_to (cr, p.x, -p.y);
316 cairo_save(cr);
317 cairo_scale(cr, POINTS_PER_INCH / FONT_DPI, POINTS_PER_INCH / FONT_DPI);
318 pango_cairo_show_layout(cr, (PangoLayout*)span->layout);
319 cairo_restore(cr);
320
321 if (span->font && (span->font->flags & HTML_OL)) {
322 A[0].x = p.x;
323 A[1].x = p.x + span->size.x;
324 A[1].y = A[0].y = p.y;
325 cairogen_polyline(job, A, 2);
326 }
327}
328
329static void cairogen_set_penstyle(GVJ_t *job, cairo_t *cr)
330{
331 obj_state_t *obj = job->obj;
332
333 if (obj->pen == PEN_DASHED) {
334 cairo_set_dash (cr, dashed, dashed_len, 0.0);
335 } else if (obj->pen == PEN_DOTTED) {
336 cairo_set_dash (cr, dotted, dotted_len, 0.0);
337 } else {
338 cairo_set_dash (cr, dashed, 0, 0.0);
339 }
340 cairo_set_line_width (cr, obj->penwidth);
341}
342
343static void cairo_gradient_fill(cairo_t *cr, obj_state_t *obj, int filled,
344 pointf *A, size_t n) {
345 cairo_pattern_t* pat;
346 double angle = obj->gradient_angle * M_PI / 180;
347 pointf G[2],c1;
348
349 if (filled == GRADIENT) {
350 get_gradient_points(A, G, n, angle, 0);
351 pat = cairo_pattern_create_linear (G[0].x,G[0].y,G[1].x,G[1].y);
352 }
353 else {
354 get_gradient_points(A, G, n, 0, 1);
355 //r1 is inner radius, r2 is outer radius
356 const double r1 = G[1].x; // set a r2 ÷ 4 in get_gradient_points
357 const double r2 = G[1].y;
358 if (obj->gradient_angle == 0) {
359 c1.x = G[0].x;
360 c1.y = G[0].y;
361 }
362 else {
363 c1.x = G[0].x + r1 * cos(angle);
364 c1.y = G[0].y - r1 * sin(angle);
365 }
366 pat = cairo_pattern_create_radial(c1.x,c1.y,r1,G[0].x,G[0].y,r2);
367 }
368 if (obj->gradient_frac > 0) {
369 cairogen_add_color_stop_rgba(pat,obj->gradient_frac - 0.001,&(obj->fillcolor));
371 }
372 else {
375 }
376 cairo_set_source (cr, pat);
377 cairo_fill_preserve (cr);
378 cairo_pattern_destroy (pat);
379}
380
381static void cairogen_ellipse(GVJ_t * job, pointf * A, int filled)
382{
383 obj_state_t *obj = job->obj;
384 cairo_t *cr = job->context;
385 cairo_matrix_t matrix;
386 double rx, ry;
387
388 cairogen_set_penstyle(job, cr);
389
390 cairo_get_matrix(cr, &matrix);
391
392 rx = A[1].x - A[0].x;
393 ry = A[1].y - A[0].y;
394
395#define RMIN 0.01
396 rx = fmax(rx, RMIN);
397 ry = fmax(ry, RMIN);
398
399 cairo_translate(cr, A[0].x, -A[0].y);
400 cairo_scale(cr, rx, ry);
401 cairo_move_to(cr, 1., 0.);
402 cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI);
403
404 cairo_set_matrix(cr, &matrix);
405
406 if (filled == GRADIENT || filled == RGRADIENT) {
407 cairo_gradient_fill (cr, obj, filled, A, 2);
408 }
409 else if (filled) {
410 cairogen_set_color(cr, &obj->fillcolor);
411 cairo_fill_preserve(cr);
412 }
413 cairogen_set_color(cr, &obj->pencolor);
414 cairo_stroke(cr);
415}
416
417static void cairogen_polygon(GVJ_t *job, pointf *A, size_t n, int filled) {
418 obj_state_t *obj = job->obj;
419 cairo_t *cr = job->context;
420
421 cairogen_set_penstyle(job, cr);
422
423 cairo_move_to(cr, A[0].x, -A[0].y);
424 for (size_t i = 1; i < n; i++)
425 cairo_line_to(cr, A[i].x, -A[i].y);
426 cairo_close_path(cr);
427 if (filled == GRADIENT || filled == RGRADIENT) {
428 cairo_gradient_fill(cr, obj, filled, A, n);
429 }
430 else if (filled) {
431 cairogen_set_color(cr, &obj->fillcolor);
432 cairo_fill_preserve(cr);
433 }
434 cairogen_set_color(cr, &obj->pencolor);
435 cairo_stroke(cr);
436}
437
438static void cairogen_bezier(GVJ_t *job, pointf *A, size_t n, int filled) {
439 obj_state_t *obj = job->obj;
440 cairo_t *cr = job->context;
441
442 cairogen_set_penstyle(job, cr);
443
444 cairo_move_to(cr, A[0].x, -A[0].y);
445 for (size_t i = 1; i < n; i += 3)
446 cairo_curve_to(cr, A[i].x, -A[i].y, A[i + 1].x, -A[i + 1].y,
447 A[i + 2].x, -A[i + 2].y);
448 if (filled == GRADIENT || filled == RGRADIENT) {
449 cairo_gradient_fill(cr, obj, filled, A, n);
450 }
451 else if (filled) {
452 cairogen_set_color(cr, &obj->fillcolor);
453 cairo_fill_preserve(cr);
454 }
455 cairogen_set_color(cr, &obj->pencolor);
456 cairo_stroke(cr);
457}
458
459static void cairogen_polyline(GVJ_t *job, pointf *A, size_t n) {
460 obj_state_t *obj = job->obj;
461 cairo_t *cr = job->context;
462
463 cairogen_set_penstyle(job, cr);
464
465 cairo_move_to(cr, A[0].x, -A[0].y);
466 for (size_t i = 1; i < n; i++)
467 cairo_line_to(cr, A[i].x, -A[i].y);
468 cairogen_set_color(cr, &obj->pencolor);
469 cairo_stroke(cr);
470}
471
475 0, /* cairogen_begin_graph */
476 0, /* cairogen_end_graph */
477 0, /* cairogen_begin_layer */
478 0, /* cairogen_end_layer */
481 0, /* cairogen_begin_cluster */
482 0, /* cairogen_end_cluster */
483 0, /* cairogen_begin_nodes */
484 0, /* cairogen_end_nodes */
485 0, /* cairogen_begin_edges */
486 0, /* cairogen_end_edges */
487 0, /* cairogen_begin_node */
488 0, /* cairogen_end_node */
489 0, /* cairogen_begin_edge */
490 0, /* cairogen_end_edge */
491 cairogen_begin_anchor, /* cairogen_begin_anchor */
492 0, /* cairogen_end_anchor */
493 0, /* cairogen_begin_label */
494 0, /* cairogen_end_label */
496 0, /* cairogen_resolve_color */
501 0, /* cairogen_comment */
502 0, /* cairogen_library_shape */
503};
504
507 | GVRENDER_DOES_TRANSFORM, /* flags */
508 4., /* default pad - graph units */
509 0, /* knowncolors */
510 0, /* sizeof knowncolors */
511 RGBA_DOUBLE, /* color_type */
512};
513
516 | GVDEVICE_DOES_TRUECOLOR,/* flags */
517 {0.,0.}, /* default margin - points */
518 {0.,0.}, /* default page width, height - points */
519 {96.,96.}, /* typical monitor dpi */
520};
521
524 | GVDEVICE_DOES_TRUECOLOR, /* flags */
525 {36.,36.}, /* default margin - points */
526 {0.,0.}, /* default page width, height - points */
527 {72.,72.}, /* postscript 72 dpi */
528};
529
532 | GVDEVICE_DOES_TRUECOLOR, /* flags */
533 {36.,36.}, /* default margin - points */
534 {0.,0.}, /* default page width, height - points */
535 {72.,72.}, /* postscript 72 dpi */
536};
537
543 | GVDEVICE_DOES_TRUECOLOR,/* flags */
544 {36.,36.}, /* default margin - points */
545 {0.,0.}, /* default page width, height - points */
546 {72.,72.}, /* postscript 72 dpi */
547};
548
551 | GVDEVICE_DOES_TRUECOLOR, /* flags */
552 {0.,0.}, /* default margin - points */
553 {0.,0.}, /* default page width, height - points */
554 {72.,72.}, /* svg 72 dpi */
555};
556
561
563#ifdef CAIRO_HAS_PNG_FUNCTIONS
564 {FORMAT_PNG, "png:cairo", 10, NULL, &device_features_png},
565#endif
566#ifdef CAIRO_HAS_PS_SURFACE
567 {FORMAT_PS, "ps:cairo", -10, NULL, &device_features_ps},
568 {FORMAT_EPS, "eps:cairo", -10, NULL, &device_features_eps},
569#endif
570#ifdef CAIRO_HAS_PDF_SURFACE
571 {FORMAT_PDF, "pdf:cairo", 10, NULL, &device_features_pdf},
572#endif
573#ifdef CAIRO_HAS_SVG_SURFACE
574 {FORMAT_SVG, "svg:cairo", -10, NULL, &device_features_svg},
575#endif
576 {0, NULL, 0, NULL, NULL}
577};
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
#define M_PI
Definition arith.h:41
@ RGBA_DOUBLE
Definition color.h:27
void get_gradient_points(pointf *A, pointf *G, size_t n, double angle, int flags)
Definition utils.c:1457
#define GRADIENT
Definition const.h:232
#define RGRADIENT
Definition const.h:233
#define A(n, t)
Definition expr.h:76
#define G
Definition gdefs.h:7
#define POINTS_PER_INCH
Definition geom.h:64
static pointf scale(double c, pointf p)
Definition geomprocs.h:130
node NULL
Definition grammar.y:163
@ PEN_DOTTED
Definition gvcjob.h:35
@ PEN_DASHED
Definition gvcjob.h:35
#define GVRENDER_NO_WHITE_BG
Definition gvcjob.h:106
#define GVDEVICE_DOES_TRUECOLOR
Definition gvcjob.h:90
#define GVDEVICE_BINARY_FORMAT
Definition gvcjob.h:91
#define GVRENDER_DOES_MAPS
Definition gvcjob.h:97
#define GVRENDER_DOES_TRANSFORM
Definition gvcjob.h:95
#define GVRENDER_Y_GOES_DOWN
Definition gvcjob.h:94
#define GVRENDER_DOES_MAP_RECTANGLE
Definition gvcjob.h:98
static void color(Agraph_t *g)
Definition gvcolor.c:129
size_t gvwrite(GVJ_t *job, const char *s, size_t len)
Definition gvdevice.c:180
#define FONT_DPI
static void cairogen_begin_page(GVJ_t *job)
static int dotted_len
gvplugin_installed_t gvrender_pango_types[]
static gvdevice_features_t device_features_eps
static void cairogen_end_page(GVJ_t *job)
static gvdevice_features_t device_features_pdf
static int dashed_len
#define RMIN
static void cairogen_textspan(GVJ_t *job, pointf p, textspan_t *span)
#define ARRAY_SIZE(A)
static gvdevice_features_t device_features_svg
static void cairogen_begin_job(GVJ_t *job)
static void cairogen_ellipse(GVJ_t *job, pointf *A, int filled)
static void cairogen_bezier(GVJ_t *job, pointf *A, size_t n, int filled)
static void cairogen_set_penstyle(GVJ_t *job, cairo_t *cr)
static const double CAIRO_XMAX
static const double CAIRO_YMAX
static void cairogen_polygon(GVJ_t *job, pointf *A, size_t n, int filled)
static gvdevice_features_t device_features_ps
static void cairogen_add_color_stop_rgba(cairo_pattern_t *pat, double stop, gvcolor_t *color)
static cairo_status_t writer(void *closure, const unsigned char *data, unsigned int length)
static void cairogen_polyline(GVJ_t *job, pointf *A, size_t n)
static double dashed[]
format_type
@ FORMAT_CAIRO
@ FORMAT_SVG
@ FORMAT_EPS
@ FORMAT_PDF
@ FORMAT_PS
@ FORMAT_PNG
static double dotted[]
static void cairogen_end_job(GVJ_t *job)
static gvrender_engine_t cairogen_engine
static void cairogen_begin_anchor(GVJ_t *job, char *url, char *tooltip, char *target, char *id)
static void cairo_gradient_fill(cairo_t *cr, obj_state_t *obj, int filled, pointf *A, size_t n)
static gvrender_features_t render_features_cairo
gvplugin_installed_t gvdevice_pango_types[]
static gvdevice_features_t device_features_png
static void cairogen_set_color(cairo_t *cr, gvcolor_t *color)
char * cmdname
Definition gvcommon.h:21
int verbose
Definition gvcommon.h:22
int rotation
Definition gvcjob.h:319
boxf clip
Definition gvcjob.h:313
obj_state_t * obj
Definition gvcjob.h:269
void * context
Definition gvcjob.h:295
bool external_context
Definition gvcjob.h:296
gvplugin_active_render_t render
Definition gvcjob.h:285
unsigned char * imagedata
location of imagedata
Definition gvcjob.h:297
GVCOMMON_t * common
Definition gvcjob.h:267
pointf scale
Definition gvcjob.h:332
unsigned int width
Definition gvcjob.h:327
pointf translation
Definition gvcjob.h:333
unsigned int height
Definition gvcjob.h:328
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
Definition legal.c:50
ingroup plugin_api
Definition gvplugin.h:35
pointf * url_map_p
Definition gvcjob.h:240
gvcolor_t fillcolor
Definition gvcjob.h:194
double gradient_frac
Definition gvcjob.h:196
gvcolor_t stopcolor
Definition gvcjob.h:194
pen_type pen
Definition gvcjob.h:197
gvcolor_t pencolor
Definition gvcjob.h:194
int gradient_angle
Definition gvcjob.h:195
double penwidth
Definition gvcjob.h:199
double x
Definition geom.h:29
double y
Definition geom.h:29
unsigned int flags
Definition textspan.h:58
double yoffset_layout
Definition textspan.h:69
char just
'l' 'n' 'r'
Definition textspan.h:71
void * layout
Definition textspan.h:67
pointf size
Definition textspan.h:70
textfont_t * font
Definition textspan.h:66
double yoffset_centerline
Definition textspan.h:69
#define HTML_OL
Definition textspan.h:35