Graphviz 13.0.0~dev.20250121.0651
Loading...
Searching...
No Matches
gvrender_quartz.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 <stdlib.h>
14#include <string.h>
15#include <util/gv_math.h>
16
17#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
18#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
19#include <mach/mach_host.h>
20#include <sys/mman.h>
21#endif
22
23#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000
24#include <ImageIO/ImageIO.h>
25#endif
26#endif
27
28#include <gvc/gvplugin_device.h>
29#include <gvc/gvplugin_render.h>
30#include <cgraph/cgraph.h>
31
32#include "gvplugin_quartz.h"
33
34static CGFloat dashed[] = { 6.0 };
35static CGFloat dotted[] = { 2.0, 6.0 };
36
37static void quartzgen_begin_job(GVJ_t * job)
38{
39 switch (job->device.id) {
40 case FORMAT_CGIMAGE:
41 /* save the passed-in context in the window field, so we can create a CGContext in the context field later on */
42 job->window = job->context;
43 *((CGImageRef *) job->window) = NULL;
44 }
45
46 job->context = NULL;
47}
48
49static void quartzgen_end_job(GVJ_t * job)
50{
51 CGContextRef context = job->context;
52
53#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
54#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
55 void* context_data;
56 size_t context_datalen;
57
58 switch (job->device.id) {
59
60 case FORMAT_PDF:
61 context_data = NULL;
62 context_datalen = 0;
63 break;
64
65 default:
66 context_data = CGBitmapContextGetData(context);
67 context_datalen = CGBitmapContextGetBytesPerRow(context) * CGBitmapContextGetHeight(context);
68 break;
69 }
70#endif
71#endif
72
73 switch (job->device.id) {
74
75 case FORMAT_PDF:
76 /* save the PDF */
77 CGPDFContextClose(context);
78 break;
79
80 case FORMAT_CGIMAGE:
81 /* create an image and save it where the window field is, which was set to the passed-in context at begin job */
82 *((CGImageRef *) job->window) = CGBitmapContextCreateImage(context);
83 break;
84
85#if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
86 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040) || \
87 (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
88 __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000)
89 default: /* bitmap formats */
90 {
91 /* create an image destination */
92 CGDataConsumerRef data_consumer =
93 CGDataConsumerCreate(job,
95 CGImageDestinationRef image_destination =
96 CGImageDestinationCreateWithDataConsumer(data_consumer,
97 format_to_uti((format_type)job->device.id), 1, NULL);
98
99 /* add the bitmap image to the destination and save it */
100 CGImageRef image = CGBitmapContextCreateImage(context);
101 CGImageDestinationAddImage(image_destination, image, NULL);
102 CGImageDestinationFinalize(image_destination);
103
104 /* clean up */
105 if (image_destination)
106 CFRelease(image_destination);
107 CGImageRelease(image);
108 CGDataConsumerRelease(data_consumer);
109 }
110 break;
111#endif
112 }
113
114 CGContextRelease(context);
115
116#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
117#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
118 if (context_data && context_datalen)
119 munmap(context_data, context_datalen);
120#endif
121#endif
122}
123
124static void quartzgen_begin_page(GVJ_t * job)
125{
126 CGRect bounds = CGRectMake(0.0, 0.0, job->width, job->height);
127
128 if (!job->context) {
129
130 switch (job->device.id) {
131
132 case FORMAT_PDF:
133 {
134 /* create the auxiliary info for PDF content, author and title */
135 CFStringRef auxiliaryKeys[] = {
136 kCGPDFContextCreator,
137 kCGPDFContextTitle
138 };
139 CFStringRef auxiliaryValues[] = {
140 CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
141 CFSTR("%s %s"),
142 job->common->info[0],
143 job->common->info[1]),
144 job->obj->type ==
146 CFStringCreateWithBytesNoCopy(kCFAllocatorDefault,
147 (const UInt8 *) agnameof(job->obj->u.g),
148 strlen(agnameof(job->obj->u.g)),
149 kCFStringEncodingUTF8,
150 false,
151 kCFAllocatorNull)
152 : CFSTR("")
153 };
154 CFDictionaryRef auxiliaryInfo =
155 CFDictionaryCreate(kCFAllocatorDefault,
156 (const void **) &auxiliaryKeys,
157 (const void **) &auxiliaryValues,
158 sizeof(auxiliaryValues) /
159 sizeof(auxiliaryValues[0]),
160 &kCFTypeDictionaryKeyCallBacks,
161 &kCFTypeDictionaryValueCallBacks);
162
163 /* create a PDF for drawing into */
164 CGDataConsumerRef data_consumer =
165 CGDataConsumerCreate(job,
167 job->context =
168 CGPDFContextCreate(data_consumer, &bounds,
169 auxiliaryInfo);
170
171 /* clean up */
172 CGDataConsumerRelease(data_consumer);
173 CFRelease(auxiliaryInfo);
174 for (size_t i = 0; i < sizeof(auxiliaryValues) / sizeof(auxiliaryValues[0]);
175 ++i)
176 CFRelease(auxiliaryValues[i]);
177 }
178 break;
179
180 default: /* bitmap formats */
181 {
182 size_t bytes_per_row =
183 (job->width * BYTES_PER_PIXEL +
185
186 void *buffer = NULL;
187
188#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
189#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
190
191 /* iPhoneOS has no swap files for memory, so if we're short of memory we need to make our own temp scratch file to back it */
192
193 size_t buffer_size = job->height * bytes_per_row;
194 mach_msg_type_number_t vm_info_size = HOST_VM_INFO_COUNT;
195 vm_statistics_data_t vm_info;
196
197 if (host_statistics
198 (mach_host_self(), HOST_VM_INFO,
199 (host_info_t) & vm_info,
200 &vm_info_size) != KERN_SUCCESS
201 || buffer_size * 2 >
202 vm_info.free_count * vm_page_size) {
203 FILE *temp_file = tmpfile();
204 if (temp_file) {
205 int temp_file_descriptor = fileno(temp_file);
206 if (temp_file_descriptor >= 0
207 && ftruncate(temp_file_descriptor,
208 buffer_size) == 0) {
209 buffer = mmap(NULL, buffer_size, PROT_READ | PROT_WRITE,
210 MAP_FILE | MAP_PRIVATE, temp_file_descriptor, 0);
211 if (buffer == MAP_FAILED)
212 buffer = NULL;
213 }
214 fclose(temp_file);
215 }
216 }
217 if (buffer == NULL) {
218 buffer = mmap(NULL, buffer_size, PROT_READ | PROT_WRITE,
219 MAP_ANON | MAP_PRIVATE, -1, 0);
220 if (buffer == MAP_FAILED) {
221 buffer = NULL;
222 }
223 }
224#endif
225#endif
226
227 /* create a true color bitmap for drawing into */
228 CGColorSpaceRef color_space =
229 CGColorSpaceCreateDeviceRGB();
230 job->context = CGBitmapContextCreate(buffer, /* data: MacOSX lets system allocate, iPhoneOS use manual memory mapping */
231 job->width, /* width in pixels */
232 job->height, /* height in pixels */
233 BITS_PER_COMPONENT, /* bits per component */
234 bytes_per_row, /* bytes per row: align to 16 byte boundary */
235 color_space, /* color space: device RGB */
236 kCGImageAlphaPremultipliedFirst /* bitmap info: premul ARGB has best support in OS X */
237 );
238 job->imagedata = CGBitmapContextGetData(job->context);
239
240 /* clean up */
241 CGColorSpaceRelease(color_space);
242 }
243 break;
244 }
245
246 }
247
248 /* start the page (if this is a paged context) and graphics state */
249 CGContextRef context = job->context;
250 CGContextBeginPage(context, &bounds);
251 CGContextSaveGState(context);
252 /* CGContextSetMiterLimit(context, 1.0); */
253 /* CGContextSetLineJoin(context, kCGLineJoinBevel); */
254
255 /* set up the context transformation */
256 CGContextScaleCTM(context, job->scale.x, job->scale.y);
257 CGContextRotateCTM(context, job->rotation * M_PI / 180.0);
258 CGContextTranslateCTM(context, job->translation.x, job->translation.y);
259}
260
261static void quartzgen_end_page(GVJ_t * job)
262{
263 /* end the page (if this is a paged context) and graphics state */
264 CGContextRef context = job->context;
265 CGContextRestoreGState(context);
266 CGContextEndPage(context);
267}
268
269static void quartzgen_begin_anchor(GVJ_t * job, char *url, char *tooltip,
270 char *target, char *id)
271{
272 (void)tooltip;
273 (void)target;
274 (void)id;
275
276 pointf *url_map = job->obj->url_map_p;
277 if (url && url_map) {
278 /* set up the hyperlink to the given url */
279 CGContextRef context = job->context;
280 CFURLRef uri =
281 CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8 *) url,
282 strlen(url), kCFStringEncodingUTF8, NULL);
283 CGPDFContextSetURLForRect(context, uri,
284 /* need to reverse the CTM on the area to get it to work */
285 CGRectApplyAffineTransform(CGRectMake
286 (url_map[0].x,
287 url_map[0].y,
288 url_map[1].
289 x -
290 url_map[0].x,
291 url_map[1].
292 y -
293 url_map[0].
294 y),
295 CGContextGetCTM
296 (context))
297 );
298
299 /* clean up */
300 CFRelease(uri);
301 }
302}
303
304static void quartzgen_path(GVJ_t * job, int filled)
305{
306 CGContextRef context = job->context;
307
308 /* set up colors */
309 if (filled)
310 CGContextSetRGBFillColor(context, job->obj->fillcolor.u.RGBA[0],
311 job->obj->fillcolor.u.RGBA[1],
312 job->obj->fillcolor.u.RGBA[2],
313 job->obj->fillcolor.u.RGBA[3]);
314 CGContextSetRGBStrokeColor(context, job->obj->pencolor.u.RGBA[0],
315 job->obj->pencolor.u.RGBA[1],
316 job->obj->pencolor.u.RGBA[2],
317 job->obj->pencolor.u.RGBA[3]);
318
319 /* set up line style */
320 const CGFloat *segments;
321 size_t segment_count;
322 switch (job->obj->pen) {
323 case PEN_DASHED:
324 segments = dashed;
325 segment_count = sizeof(dashed) / sizeof(CGFloat);
326 break;
327 case PEN_DOTTED:
328 segments = dotted;
329 segment_count = sizeof(dotted) / sizeof(CGFloat);
330 break;
331 default:
332 segments = NULL;
333 segment_count = 0;
334 break;
335 }
336 CGContextSetLineDash(context, 0.0, segments, segment_count);
337
338 /* set up line width */
339 CGContextSetLineWidth(context, job->obj->penwidth); // *job->scale.x);
340
341 /* draw the path */
342 CGContextDrawPath(context, filled ? kCGPathFillStroke : kCGPathStroke);
343}
344
345static void quartzgen_textspan(GVJ_t * job, pointf p, textspan_t * span)
346{
347 CGContextRef context = job->context;
348
349 /* adjust text position */
350 switch (span->just) {
351 case 'r':
352 p.x -= span->size.x;
353 break;
354 case 'l':
355 p.x -= 0.0;
356 break;
357 case 'n':
358 default:
359 p.x -= span->size.x / 2.0;
360 break;
361 }
362 p.y += span->yoffset_centerline;
363
364 void *layout;
365 if (span->free_layout == &quartz_free_layout)
366 layout = span->layout;
367 else
368 layout =
369 quartz_new_layout(span->font->name, span->font->size, span->str);
370
371 CGContextSetRGBFillColor(context, job->obj->pencolor.u.RGBA[0],
372 job->obj->pencolor.u.RGBA[1],
373 job->obj->pencolor.u.RGBA[2],
374 job->obj->pencolor.u.RGBA[3]);
375 quartz_draw_layout(layout, context, CGPointMake(p.x, p.y));
376
377 if (span->free_layout != &quartz_free_layout)
379}
380
381static void quartzgen_ellipse(GVJ_t * job, pointf * A, int filled)
382{
383 /* convert ellipse into the current path */
384 CGContextRef context = job->context;
385 double dx = A[1].x - A[0].x;
386 double dy = A[1].y - A[0].y;
387 CGContextAddEllipseInRect(context,
388 CGRectMake(A[0].x - dx, A[0].y - dy,
389 dx * 2.0, dy * 2.0));
390
391 /* draw the ellipse */
392 quartzgen_path(job, filled);
393}
394
395static void quartzgen_polygon(GVJ_t *job, pointf *A, size_t n, int filled) {
396 /* convert polygon into the current path */
397 CGContextRef context = job->context;
398 CGContextMoveToPoint(context, A[0].x, A[0].y);
399 for (size_t i = 1; i < n; ++i)
400 CGContextAddLineToPoint(context, A[i].x, A[i].y);
401 CGContextClosePath(context);
402
403 /* draw the ellipse */
404 quartzgen_path(job, filled);
405}
406
407static void quartzgen_bezier(GVJ_t *job, pointf *A, size_t n, int filled) {
408 /* convert bezier into the current path */
409 CGContextRef context = job->context;
410 CGContextMoveToPoint(context, A[0].x, A[0].y);
411 for (size_t i = 1; i < n; i += 3)
412 CGContextAddCurveToPoint(context, A[i].x, A[i].y, A[i + 1].x,
413 A[i + 1].y, A[i + 2].x, A[i + 2].y);
414
415 /* draw the ellipse */
416 quartzgen_path(job, filled);
417}
418
419static void quartzgen_polyline(GVJ_t *job, pointf *A, size_t n) {
420 /* convert polyline into the current path */
421 CGContextRef context = job->context;
422 CGContextMoveToPoint(context, A[0].x, A[0].y);
423 for (size_t i = 1; i < n; ++i)
424 CGContextAddLineToPoint(context, A[i].x, A[i].y);
425
426 /* draw the ellipse */
427 quartzgen_path(job, 0);
428}
429
433 0, /* quartzgen_begin_graph */
434 0, /* quartzgen_end_graph */
435 0, /* quartzgen_begin_layer */
436 0, /* quartzgen_end_layer */
439 0, /* quartzgen_begin_cluster */
440 0, /* quartzgen_end_cluster */
441 0, /* quartzgen_begin_nodes */
442 0, /* quartzgen_end_nodes */
443 0, /* quartzgen_begin_edges */
444 0, /* quartzgen_end_edges */
445 0, /* quartzgen_begin_node */
446 0, /* quartzgen_end_node */
447 0, /* quartzgen_begin_edge */
448 0, /* quartzgen_end_edge */
450 0, /* quartzgen_end_anchor */
451 0, /* quartzgen_begin_label */
452 0, /* quartzgen_end_label */
454 0,
459 0, /* quartzgen_comment */
460 0, /* quartzgen_library_shape */
461};
462
465 4., /* default pad - graph units */
466 NULL, /* knowncolors */
467 0, /* sizeof knowncolors */
468 RGBA_DOUBLE /* color_type */
469};
470
471#if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
472 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040) || \
473 (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
474 __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000)
475static gvdevice_features_t device_features_quartz = {
477 {0., 0.}, /* default margin - points */
478 {0., 0.}, /* default page width, height - points */
479 {72., 72.} /* dpi */
480};
481#endif
482
485 {36., 36.}, /* default margin - points */
486 {0., 0.}, /* default page width, height - points */
487 {72., 72.} /* dpi */
488};
489
494
496 {FORMAT_PDF, "pdf:quartz", 8, NULL, &device_features_quartz_paged},
497#if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
498 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040) || \
499 (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
500 __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000)
501 {FORMAT_CGIMAGE, "cgimage:quartz", 8, NULL, &device_features_quartz},
502#endif
503#if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
504 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040) || \
505 (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
506 __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000)
507 {FORMAT_BMP, "bmp:quartz", 8, NULL, &device_features_quartz},
508 {FORMAT_GIF, "gif:quartz", 8, NULL, &device_features_quartz},
509 {FORMAT_ICO, "ico:quartz", 8, NULL, &device_features_quartz},
510 {FORMAT_JPEG, "jpe:quartz", 8, NULL, &device_features_quartz},
511 {FORMAT_JPEG, "jpeg:quartz", 8, NULL, &device_features_quartz},
512 {FORMAT_JPEG, "jpg:quartz", 8, NULL, &device_features_quartz},
513 {FORMAT_JPEG2000, "jp2:quartz", 8, NULL, &device_features_quartz},
514 {FORMAT_PNG, "png:quartz", 8, NULL, &device_features_quartz},
515 {FORMAT_TIFF, "tif:quartz", 8, NULL, &device_features_quartz},
516 {FORMAT_TIFF, "tiff:quartz", 8, NULL, &device_features_quartz},
517 {FORMAT_TGA, "tga:quartz", 8, NULL, &device_features_quartz},
518#endif
519#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
520#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040
521 {FORMAT_EXR, "exr:quartz", 8, NULL, &device_features_quartz},
522 {FORMAT_ICNS, "icns:quartz", 8, NULL, &device_features_quartz},
523 {FORMAT_PICT, "pct:quartz", 8, NULL, &device_features_quartz},
524 {FORMAT_PICT, "pict:quartz", 8, NULL, &device_features_quartz},
525 {FORMAT_PSD, "psd:quartz", 8, NULL, &device_features_quartz},
526 {FORMAT_SGI, "sgi:quartz", 8, NULL, &device_features_quartz},
527#endif
528#endif
529 {0, NULL, 0, NULL, NULL}
530};
#define M_PI
Definition arith.h:41
abstract graph C library, Cgraph API
@ RGBA_DOUBLE
Definition color.h:27
static float dy
Definition draw.c:38
static float dx
Definition draw.c:37
#define A(n, t)
Definition expr.h:76
node NULL
Definition grammar.y:163
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
Arithmetic helper functions.
@ BYTES_PER_PIXEL
Definition gv_math.h:87
@ PEN_DOTTED
Definition gvcjob.h:35
@ PEN_DASHED
Definition gvcjob.h:35
#define GVRENDER_NO_WHITE_BG
Definition gvcjob.h:106
#define GVDEVICE_DOES_PAGES
Definition gvcjob.h:87
#define GVDEVICE_DOES_TRUECOLOR
Definition gvcjob.h:90
#define GVDEVICE_BINARY_FORMAT
Definition gvcjob.h:91
#define GVRENDER_DOES_MAPS
Definition gvcjob.h:97
@ ROOTGRAPH_OBJTYPE
Definition gvcjob.h:168
#define GVRENDER_DOES_TRANSFORM
Definition gvcjob.h:95
#define GVRENDER_DOES_MAP_RECTANGLE
Definition gvcjob.h:98
format_type
@ FORMAT_TIFF
@ FORMAT_BMP
CGDataConsumerCallbacks device_data_consumer_callbacks
void quartz_draw_layout(void *layout, CGContextRef context, CGPoint position)
void * quartz_new_layout(char *fontname, double fontsize, char *text)
static const int BYTE_ALIGN
static const int BITS_PER_COMPONENT
@ FORMAT_ICO
@ FORMAT_PICT
@ FORMAT_CGIMAGE
@ FORMAT_EXR
@ FORMAT_JPEG2000
@ FORMAT_TGA
@ FORMAT_ICNS
@ FORMAT_PSD
@ FORMAT_SGI
void quartz_free_layout(void *layout)
@ FORMAT_JPEG
Definition gvrender_gd.c:37
@ FORMAT_GIF
Definition gvrender_gd.c:36
@ FORMAT_PNG
Definition gvrender_gd.c:38
@ FORMAT_PDF
static void quartzgen_bezier(GVJ_t *job, pointf *A, size_t n, int filled)
static CGFloat dashed[]
static gvdevice_features_t device_features_quartz_paged
static CGFloat dotted[]
static gvrender_engine_t quartzgen_engine
static void quartzgen_end_page(GVJ_t *job)
static void quartzgen_polygon(GVJ_t *job, pointf *A, size_t n, int filled)
static void quartzgen_path(GVJ_t *job, int filled)
static void quartzgen_begin_job(GVJ_t *job)
static gvrender_features_t render_features_quartz
static void quartzgen_end_job(GVJ_t *job)
gvplugin_installed_t gvrender_quartz_types[]
static void quartzgen_ellipse(GVJ_t *job, pointf *A, int filled)
static void quartzgen_polyline(GVJ_t *job, pointf *A, size_t n)
static void quartzgen_begin_page(GVJ_t *job)
static void quartzgen_begin_anchor(GVJ_t *job, char *url, char *tooltip, char *target, char *id)
gvplugin_installed_t gvdevice_quartz_types[]
static void quartzgen_textspan(GVJ_t *job, pointf p, textspan_t *span)
T_cell image
Definition htmlparse.y:340
static int layout(graph_t *g, layout_info *infop)
Definition layout.c:814
char ** info
Definition gvcommon.h:20
int rotation
Definition gvcjob.h:319
obj_state_t * obj
Definition gvcjob.h:269
gvplugin_active_device_t device
Definition gvcjob.h:286
void * context
Definition gvcjob.h:295
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
void * window
Definition gvcjob.h:353
pointf translation
Definition gvcjob.h:333
unsigned int height
Definition gvcjob.h:328
double RGBA[4]
Definition color.h:32
union color_s::@71 u
ingroup plugin_api
Definition gvplugin.h:35
graph_t * g
Definition gvcjob.h:186
pointf * url_map_p
Definition gvcjob.h:240
gvcolor_t fillcolor
Definition gvcjob.h:194
union obj_state_s::@89 u
obj_type type
Definition gvcjob.h:184
pen_type pen
Definition gvcjob.h:197
gvcolor_t pencolor
Definition gvcjob.h:194
double penwidth
Definition gvcjob.h:199
double x
Definition geom.h:29
double y
Definition geom.h:29
char * name
Definition textspan.h:54
double size
Definition textspan.h:57
char * str
Definition textspan.h:65
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
void(* free_layout)(void *layout)
Definition textspan.h:68