1 /*
2 / gaiagraphics_paint.c
3 /
4 / painting helpers
5 /
6 / version 1.0, 2010 October 19
7 /
8 / Author: Sandro Furieri a.furieri@lqt.it
9 /
10 / Copyright (C) 2009 Alessandro Furieri
11 /
12 / This program is free software: you can redistribute it and/or modify
13 / it under the terms of the GNU Lesser General Public License as published by
14 / the Free Software Foundation, either version 3 of the License, or
15 / (at your option) any later version.
16 /
17 / This program is distributed in the hope that it will be useful,
18 / but WITHOUT ANY WARRANTY; without even the implied warranty of
19 / MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 / GNU Lesser General Public License for more details.
21 /
22 / You should have received a copy of the GNU Lesser General Public License
23 / along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31
32 #include "gaiagraphics.h"
33 #include "gaiagraphics_internals.h"
34
35 GGRAPH_DECLARE int
gGraphCreateContext(int width,int height,const void ** context)36 gGraphCreateContext (int width, int height, const void **context)
37 {
38 /* creating a Graphics Context */
39 gGraphContextPtr ctx;
40
41 *context = NULL;
42
43 ctx = malloc (sizeof (gGraphContext));
44 if (!ctx)
45 return GGRAPH_INSUFFICIENT_MEMORY;
46 ctx->signature = GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE;
47 ctx->surface =
48 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
49 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
50 ;
51 else
52 goto error1;
53 ctx->cairo = cairo_create (ctx->surface);
54 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
55 goto error2;
56
57 /* setting up a default Black Pen */
58 ctx->current_pen.red = 0.0;
59 ctx->current_pen.green = 0.0;
60 ctx->current_pen.blue = 0.0;
61 ctx->current_pen.alpha = 1.0;
62 ctx->current_pen.width = 1.0;
63 ctx->current_pen.lengths[0] = 1.0;
64 ctx->current_pen.lengths_count = 1;
65
66 /* setting up a default Black Brush */
67 ctx->current_brush.is_solid_color = 1;
68 ctx->current_brush.is_linear_gradient = 0;
69 ctx->current_brush.is_pattern = 0;
70 ctx->current_brush.red = 0.0;
71 ctx->current_brush.green = 0.0;
72 ctx->current_brush.blue = 0.0;
73 ctx->current_brush.alpha = 1.0;
74 ctx->current_brush.pattern = NULL;
75
76 /* priming a transparent background */
77 cairo_rectangle (ctx->cairo, 0, 0, width, height);
78 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
79 cairo_fill (ctx->cairo);
80
81 /* setting up default Font options */
82 ctx->font_red = 0.0;
83 ctx->font_green = 0.0;
84 ctx->font_blue = 0.0;
85 ctx->font_alpha = 1.0;
86 ctx->is_font_outlined = 0;
87 ctx->font_outline_width = 0.0;
88
89 *context = ctx;
90 return GGRAPH_OK;
91 error2:
92 cairo_destroy (ctx->cairo);
93 cairo_surface_destroy (ctx->surface);
94 return GGRAPH_ERROR;
95 error1:
96 cairo_surface_destroy (ctx->surface);
97 return GGRAPH_ERROR;
98 }
99
100 GGRAPH_DECLARE int
gGraphDestroyContext(const void * context)101 gGraphDestroyContext (const void *context)
102 {
103 /* freeing a Graphics Context */
104 gGraphContextPtr ctx = (gGraphContextPtr) context;
105 if (!ctx)
106 return GGRAPH_INVALID_PAINT_CONTEXT;
107 if (ctx->signature != GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE)
108 return GGRAPH_INVALID_PAINT_CONTEXT;
109 cairo_destroy (ctx->cairo);
110 cairo_surface_destroy (ctx->surface);
111 free (ctx);
112 return GGRAPH_OK;
113 }
114
115 GGRAPH_DECLARE int
gGraphCreateSvgContext(const char * path,int width,int height,const void ** context)116 gGraphCreateSvgContext (const char *path, int width, int height,
117 const void **context)
118 {
119 /* creating an SVG Graphics Context */
120 gGraphContextPtr ctx;
121
122 *context = NULL;
123
124 ctx = malloc (sizeof (gGraphContext));
125 if (!ctx)
126 return GGRAPH_INSUFFICIENT_MEMORY;
127 ctx->signature = GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE;
128
129 ctx->surface =
130 cairo_svg_surface_create (path, (double) width, (double) height);
131
132 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
133 ;
134 else
135 goto error1;
136 ctx->cairo = cairo_create (ctx->surface);
137 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
138 goto error2;
139
140 /* setting up a default Black Pen */
141 ctx->current_pen.red = 0.0;
142 ctx->current_pen.green = 0.0;
143 ctx->current_pen.blue = 0.0;
144 ctx->current_pen.alpha = 1.0;
145 ctx->current_pen.width = 1.0;
146 ctx->current_pen.lengths[0] = 1.0;
147 ctx->current_pen.lengths_count = 1;
148
149 /* setting up a default Black Brush */
150 ctx->current_brush.is_solid_color = 1;
151 ctx->current_brush.is_linear_gradient = 0;
152 ctx->current_brush.is_pattern = 0;
153 ctx->current_brush.red = 0.0;
154 ctx->current_brush.green = 0.0;
155 ctx->current_brush.blue = 0.0;
156 ctx->current_brush.alpha = 1.0;
157 ctx->current_brush.pattern = NULL;
158
159 /* priming a transparent background */
160 cairo_rectangle (ctx->cairo, 0, 0, width, height);
161 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
162 cairo_fill (ctx->cairo);
163
164 /* setting up default Font options */
165 ctx->font_red = 0.0;
166 ctx->font_green = 0.0;
167 ctx->font_blue = 0.0;
168 ctx->font_alpha = 1.0;
169 ctx->is_font_outlined = 0;
170 ctx->font_outline_width = 0.0;
171
172 *context = ctx;
173 return GGRAPH_OK;
174 error2:
175 cairo_destroy (ctx->cairo);
176 cairo_surface_destroy (ctx->surface);
177 return GGRAPH_ERROR;
178 error1:
179 cairo_surface_destroy (ctx->surface);
180 return GGRAPH_ERROR;
181 }
182
183 GGRAPH_DECLARE int
gGraphDestroySvgContext(const void * context)184 gGraphDestroySvgContext (const void *context)
185 {
186 /* freeing an SVG Graphics Context */
187 gGraphContextPtr ctx = (gGraphContextPtr) context;
188 if (!ctx)
189 return GGRAPH_INVALID_PAINT_CONTEXT;
190 if (ctx->signature != GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE)
191 return GGRAPH_INVALID_PAINT_CONTEXT;
192 cairo_surface_show_page (ctx->surface);
193 cairo_destroy (ctx->cairo);
194 cairo_surface_finish (ctx->surface);
195 cairo_surface_destroy (ctx->surface);
196 free (ctx);
197 return GGRAPH_OK;
198 }
199
200 GGRAPH_DECLARE int
gGraphCreatePdfContext(const char * path,int page_width,int page_height,int width,int height,const void ** context)201 gGraphCreatePdfContext (const char *path, int page_width, int page_height,
202 int width, int height, const void **context)
203 {
204 /* creating an PDF Graphics Context */
205 int base_x = (page_width - width) / 2;
206 int base_y = (page_height - height) / 2;
207 gGraphContextPtr ctx;
208
209 *context = NULL;
210
211 ctx = malloc (sizeof (gGraphContext));
212 if (!ctx)
213 return GGRAPH_INSUFFICIENT_MEMORY;
214 ctx->signature = GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE;
215 ctx->surface =
216 cairo_pdf_surface_create (path, (double) page_width,
217 (double) page_height);
218 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
219 ;
220 else
221 goto error1;
222 ctx->cairo = cairo_create (ctx->surface);
223 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
224 goto error2;
225
226 /* setting up a default Black Pen */
227 ctx->current_pen.red = 0.0;
228 ctx->current_pen.green = 0.0;
229 ctx->current_pen.blue = 0.0;
230 ctx->current_pen.alpha = 1.0;
231 ctx->current_pen.width = 1.0;
232 ctx->current_pen.lengths[0] = 1.0;
233 ctx->current_pen.lengths_count = 1;
234
235 /* setting up a default Black Brush */
236 ctx->current_brush.is_solid_color = 1;
237 ctx->current_brush.is_linear_gradient = 0;
238 ctx->current_brush.is_pattern = 0;
239 ctx->current_brush.red = 0.0;
240 ctx->current_brush.green = 0.0;
241 ctx->current_brush.blue = 0.0;
242 ctx->current_brush.alpha = 1.0;
243 ctx->current_brush.pattern = NULL;
244
245 /* priming a transparent background */
246 cairo_rectangle (ctx->cairo, 0, 0, width, height);
247 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
248 cairo_fill (ctx->cairo);
249
250 /* setting up default Font options */
251 ctx->font_red = 0.0;
252 ctx->font_green = 0.0;
253 ctx->font_blue = 0.0;
254 ctx->font_alpha = 1.0;
255 ctx->is_font_outlined = 0;
256 ctx->font_outline_width = 0.0;
257
258 cairo_translate (ctx->cairo, base_x, base_y);
259 *context = ctx;
260 return GGRAPH_OK;
261 error2:
262 cairo_destroy (ctx->cairo);
263 cairo_surface_destroy (ctx->surface);
264 return GGRAPH_ERROR;
265 error1:
266 cairo_surface_destroy (ctx->surface);
267 return GGRAPH_ERROR;
268 }
269
270 GGRAPH_DECLARE int
gGraphDestroyPdfContext(const void * context)271 gGraphDestroyPdfContext (const void *context)
272 {
273 /* freeing an PDF Graphics Context */
274 gGraphContextPtr ctx = (gGraphContextPtr) context;
275 if (!ctx)
276 return GGRAPH_INVALID_PAINT_CONTEXT;
277 if (ctx->signature != GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
278 return GGRAPH_INVALID_PAINT_CONTEXT;
279 cairo_surface_show_page (ctx->surface);
280 cairo_destroy (ctx->cairo);
281 cairo_surface_finish (ctx->surface);
282 cairo_surface_destroy (ctx->surface);
283 free (ctx);
284 return GGRAPH_OK;
285 }
286
287 GGRAPH_DECLARE int
gGraphSetPen(const void * context,unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha,double width,int style)288 gGraphSetPen (const void *context, unsigned char red, unsigned char green,
289 unsigned char blue, unsigned char alpha, double width, int style)
290 {
291 /* creating a Color Pen */
292 double d_red = (double) red / 255.0;
293 double d_green = (double) green / 255.0;
294 double d_blue = (double) blue / 255.0;
295 double d_alpha = (double) alpha / 255.0;
296 gGraphContextPtr ctx = (gGraphContextPtr) context;
297 if (!ctx)
298 return GGRAPH_INVALID_PAINT_CONTEXT;
299 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
300 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
301 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
302 ;
303 else
304 return GGRAPH_INVALID_PAINT_CONTEXT;
305
306 ctx->current_pen.width = width;
307 ctx->current_pen.red = d_red;
308 ctx->current_pen.green = d_green;
309 ctx->current_pen.blue = d_blue;
310 ctx->current_pen.alpha = d_alpha;
311 switch (style)
312 {
313 case GGRAPH_PENSTYLE_DOT:
314 ctx->current_pen.lengths[0] = 2;
315 ctx->current_pen.lengths[1] = 2;
316 ctx->current_pen.lengths_count = 2;
317 break;
318 case GGRAPH_PENSTYLE_LONG_DASH:
319 ctx->current_pen.lengths[0] = 16;
320 ctx->current_pen.lengths[1] = 8;
321 ctx->current_pen.lengths_count = 2;
322 break;
323 case GGRAPH_PENSTYLE_SHORT_DASH:
324 ctx->current_pen.lengths[0] = 8;
325 ctx->current_pen.lengths[1] = 4;
326 ctx->current_pen.lengths_count = 2;
327 break;
328 case GGRAPH_PENSTYLE_DOT_DASH:
329 ctx->current_pen.lengths[0] = 8;
330 ctx->current_pen.lengths[1] = 4;
331 ctx->current_pen.lengths[2] = 2;
332 ctx->current_pen.lengths[3] = 4;
333 ctx->current_pen.lengths_count = 4;
334 break;
335 default:
336 ctx->current_pen.lengths[0] = 1;
337 ctx->current_pen.lengths[1] = 0;
338 ctx->current_pen.lengths_count = 2;
339 };
340 return GGRAPH_OK;
341 }
342
343 GGRAPH_DECLARE int
gGraphSetBrush(const void * context,unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)344 gGraphSetBrush (const void *context, unsigned char red, unsigned char green,
345 unsigned char blue, unsigned char alpha)
346 {
347 /* setting up a Color Brush */
348 double d_red = (double) red / 255.0;
349 double d_green = (double) green / 255.0;
350 double d_blue = (double) blue / 255.0;
351 double d_alpha = (double) alpha / 255.0;
352 gGraphContextPtr ctx = (gGraphContextPtr) context;
353 if (!ctx)
354 return GGRAPH_INVALID_PAINT_CONTEXT;
355 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
356 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
357 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
358 ;
359 else
360 return GGRAPH_INVALID_PAINT_CONTEXT;
361
362 ctx->current_brush.is_solid_color = 1;
363 ctx->current_brush.is_linear_gradient = 0;
364 ctx->current_brush.is_pattern = 0;
365 ctx->current_brush.red = d_red;
366 ctx->current_brush.green = d_green;
367 ctx->current_brush.blue = d_blue;
368 ctx->current_brush.alpha = d_alpha;
369 return GGRAPH_OK;
370 }
371
372 GGRAPH_DECLARE int
gGraphSetLinearGradientBrush(const void * context,double x,double y,double width,double height,unsigned char red1,unsigned char green1,unsigned char blue1,unsigned char alpha1,unsigned char red2,unsigned char green2,unsigned char blue2,unsigned char alpha2)373 gGraphSetLinearGradientBrush (const void *context, double x, double y,
374 double width, double height, unsigned char red1,
375 unsigned char green1, unsigned char blue1,
376 unsigned char alpha1, unsigned char red2,
377 unsigned char green2, unsigned char blue2,
378 unsigned char alpha2)
379 {
380 /* setting up a Linear Gradient Brush */
381 double d_red = (double) red1 / 255.0;
382 double d_green = (double) green1 / 255.0;
383 double d_blue = (double) blue1 / 255.0;
384 double d_alpha = (double) alpha1 / 255.0;
385 gGraphContextPtr ctx = (gGraphContextPtr) context;
386 if (!ctx)
387 return GGRAPH_INVALID_PAINT_CONTEXT;
388 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
389 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
390 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
391 ;
392 else
393 return GGRAPH_INVALID_PAINT_CONTEXT;
394
395 ctx->current_brush.is_solid_color = 0;
396 ctx->current_brush.is_linear_gradient = 1;
397 ctx->current_brush.is_pattern = 0;
398 ctx->current_brush.red = d_red;
399 ctx->current_brush.green = d_green;
400 ctx->current_brush.blue = d_blue;
401 ctx->current_brush.alpha = d_alpha;
402 ctx->current_brush.x0 = x;
403 ctx->current_brush.y0 = y;
404 ctx->current_brush.x1 = x + width;
405 ctx->current_brush.y1 = y + height;
406 d_red = (double) red2 / 255.0;
407 d_green = (double) green2 / 255.0;
408 d_blue = (double) blue2 / 255.0;
409 d_alpha = (double) alpha2 / 255.0;
410 ctx->current_brush.red2 = d_red;
411 ctx->current_brush.green2 = d_green;
412 ctx->current_brush.blue2 = d_blue;
413 ctx->current_brush.alpha2 = d_alpha;
414 return GGRAPH_OK;
415 }
416
417 GGRAPH_DECLARE int
gGraphSetPatternBrush(const void * context,const void * brush)418 gGraphSetPatternBrush (const void *context, const void *brush)
419 {
420 /* setting up a Pattern Brush */
421 gGraphPatternBrushPtr pattern = (gGraphPatternBrushPtr) brush;
422 gGraphContextPtr ctx = (gGraphContextPtr) context;
423
424 if (!ctx)
425 return GGRAPH_INVALID_PAINT_CONTEXT;
426 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
427 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
428 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
429 ;
430 else
431 return GGRAPH_INVALID_PAINT_CONTEXT;
432
433 if (!pattern)
434 return GGRAPH_INVALID_PAINT_BRUSH;
435 if (pattern->signature != GG_GRAPHICS_BRUSH_MAGIC_SIGNATURE)
436 return GGRAPH_INVALID_PAINT_BRUSH;
437
438 ctx->current_brush.is_solid_color = 0;
439 ctx->current_brush.is_linear_gradient = 0;
440 ctx->current_brush.is_pattern = 1;
441
442 ctx->current_brush.pattern = pattern->pattern;
443 return GGRAPH_OK;
444 }
445
446 static void
set_current_brush(gGraphContextPtr ctx)447 set_current_brush (gGraphContextPtr ctx)
448 {
449 /* setting up the current Brush */
450 if (ctx->current_brush.is_solid_color)
451 {
452 /* using a Solid Color Brush */
453 cairo_set_source_rgba (ctx->cairo, ctx->current_brush.red,
454 ctx->current_brush.green,
455 ctx->current_brush.blue,
456 ctx->current_brush.alpha);
457 }
458 else if (ctx->current_brush.is_linear_gradient)
459 {
460 /* using a Linear Gradient Brush */
461 cairo_pattern_t *pattern =
462 cairo_pattern_create_linear (ctx->current_brush.x0,
463 ctx->current_brush.y0,
464 ctx->current_brush.x1,
465 ctx->current_brush.y1);
466 cairo_pattern_add_color_stop_rgba (pattern, 0.0,
467 ctx->current_brush.red,
468 ctx->current_brush.green,
469 ctx->current_brush.blue,
470 ctx->current_brush.alpha);
471 cairo_pattern_add_color_stop_rgba (pattern, 1.0,
472 ctx->current_brush.red2,
473 ctx->current_brush.green2,
474 ctx->current_brush.blue2,
475 ctx->current_brush.alpha2);
476 cairo_set_source (ctx->cairo, pattern);
477 cairo_pattern_destroy (pattern);
478 }
479 else if (ctx->current_brush.is_pattern)
480 {
481 /* using a Pattern Brush */
482 cairo_set_source (ctx->cairo, ctx->current_brush.pattern);
483 }
484 }
485
486 GGRAPH_DECLARE int
gGraphFillPath(const void * context,int preserve)487 gGraphFillPath (const void *context, int preserve)
488 {
489 /* Filling a path */
490 gGraphContextPtr ctx = (gGraphContextPtr) context;
491 if (!ctx)
492 return GGRAPH_INVALID_PAINT_CONTEXT;
493 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
494 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
495 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
496 ;
497 else
498 return GGRAPH_INVALID_PAINT_CONTEXT;
499
500 set_current_brush (ctx);
501 if (preserve == GGRAPH_PRESERVE_PATH)
502 cairo_fill_preserve (ctx->cairo);
503 else
504 cairo_fill (ctx->cairo);
505 return GGRAPH_OK;
506 }
507
508 static void
set_current_pen(gGraphContextPtr ctx)509 set_current_pen (gGraphContextPtr ctx)
510 {
511 /* setting up the current Pen */
512 cairo_set_line_width (ctx->cairo, ctx->current_pen.width);
513 cairo_set_source_rgba (ctx->cairo, ctx->current_pen.red,
514 ctx->current_pen.green, ctx->current_pen.blue,
515 ctx->current_pen.alpha);
516 cairo_set_line_cap (ctx->cairo, CAIRO_LINE_CAP_BUTT);
517 cairo_set_line_join (ctx->cairo, CAIRO_LINE_JOIN_MITER);
518 cairo_set_dash (ctx->cairo, ctx->current_pen.lengths,
519 ctx->current_pen.lengths_count, 0.0);
520 }
521
522 GGRAPH_DECLARE int
gGraphStrokePath(const void * context,int preserve)523 gGraphStrokePath (const void *context, int preserve)
524 {
525 /* Stroking a path */
526 gGraphContextPtr ctx = (gGraphContextPtr) context;
527 if (!ctx)
528 return GGRAPH_INVALID_PAINT_CONTEXT;
529 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
530 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
531 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
532 ;
533 else
534 return GGRAPH_INVALID_PAINT_CONTEXT;
535
536 set_current_pen (ctx);
537 if (preserve == GGRAPH_PRESERVE_PATH)
538 cairo_stroke_preserve (ctx->cairo);
539 else
540 cairo_stroke (ctx->cairo);
541 return GGRAPH_OK;
542 }
543
544 GGRAPH_DECLARE int
gGraphMoveToPoint(const void * context,double x,double y)545 gGraphMoveToPoint (const void *context, double x, double y)
546 {
547 /* Moving to a Path Point */
548 gGraphContextPtr ctx = (gGraphContextPtr) context;
549 if (!ctx)
550 return GGRAPH_INVALID_PAINT_CONTEXT;
551 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
552 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
553 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
554 ;
555 else
556 return GGRAPH_INVALID_PAINT_CONTEXT;
557 cairo_move_to (ctx->cairo, x, y);
558 return GGRAPH_OK;
559 }
560
561 GGRAPH_DECLARE int
gGraphAddLineToPath(const void * context,double x,double y)562 gGraphAddLineToPath (const void *context, double x, double y)
563 {
564 /* Adding a Lint to a Path */
565 gGraphContextPtr ctx = (gGraphContextPtr) context;
566 if (!ctx)
567 return GGRAPH_INVALID_PAINT_CONTEXT;
568 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
569 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
570 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
571 ;
572 else
573 return GGRAPH_INVALID_PAINT_CONTEXT;
574 cairo_line_to (ctx->cairo, x, y);
575 return GGRAPH_OK;
576 }
577
578 GGRAPH_DECLARE int
gGraphCloseSubpath(const void * context)579 gGraphCloseSubpath (const void *context)
580 {
581 /* Closing a SubPath */
582 gGraphContextPtr ctx = (gGraphContextPtr) context;
583 if (!ctx)
584 return GGRAPH_INVALID_PAINT_CONTEXT;
585 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
586 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
587 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
588 ;
589 else
590 return GGRAPH_INVALID_PAINT_CONTEXT;
591 cairo_close_path (ctx->cairo);
592 return GGRAPH_OK;
593 }
594
595 GGRAPH_DECLARE int
gGraphStrokeLine(const void * context,double x0,double y0,double x1,double y1)596 gGraphStrokeLine (const void *context, double x0, double y0, double x1,
597 double y1)
598 {
599 /* Stroking a line */
600 gGraphContextPtr ctx = (gGraphContextPtr) context;
601 if (!ctx)
602 return GGRAPH_INVALID_PAINT_CONTEXT;
603 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
604 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
605 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
606 ;
607 else
608 return GGRAPH_INVALID_PAINT_CONTEXT;
609 cairo_move_to (ctx->cairo, x0, y0);
610 cairo_line_to (ctx->cairo, x1, y1);
611 set_current_pen (ctx);
612 cairo_stroke (ctx->cairo);
613 return GGRAPH_OK;
614 }
615
616 GGRAPH_DECLARE int
gGraphDrawEllipse(const void * context,double x,double y,double width,double height)617 gGraphDrawEllipse (const void *context, double x, double y, double width,
618 double height)
619 {
620 /* Drawing a filled ellipse */
621 gGraphContextPtr ctx = (gGraphContextPtr) context;
622 if (!ctx)
623 return GGRAPH_INVALID_PAINT_CONTEXT;
624 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
625 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
626 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
627 ;
628 else
629 return GGRAPH_INVALID_PAINT_CONTEXT;
630 cairo_save (ctx->cairo);
631 cairo_translate (ctx->cairo, x + (width / 2.0), y + (height / 2.0));
632 cairo_scale (ctx->cairo, width / 2.0, height / 2.0);
633 cairo_arc (ctx->cairo, 0.0, 0.0, 1.0, 0.0, 2.0 * M_PI);
634 cairo_restore (ctx->cairo);
635 set_current_brush (ctx);
636 cairo_fill_preserve (ctx->cairo);
637 set_current_pen (ctx);
638 cairo_stroke (ctx->cairo);
639 return GGRAPH_OK;
640 }
641
642 GGRAPH_DECLARE int
gGraphDrawCircleSector(const void * context,double center_x,double center_y,double radius,double from_angle,double to_angle)643 gGraphDrawCircleSector (const void *context, double center_x,
644 double center_y, double radius, double from_angle,
645 double to_angle)
646 {
647 /* drawing a filled circular sector */
648 gGraphContextPtr ctx = (gGraphContextPtr) context;
649 if (!ctx)
650 return GGRAPH_INVALID_PAINT_CONTEXT;
651 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
652 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
653 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
654 ;
655 else
656 return GGRAPH_INVALID_PAINT_CONTEXT;
657 cairo_move_to (ctx->cairo, center_x, center_y);
658 cairo_arc (ctx->cairo, center_x, center_y, radius, from_angle, to_angle);
659 cairo_line_to (ctx->cairo, center_x, center_y);
660 set_current_brush (ctx);
661 cairo_fill_preserve (ctx->cairo);
662 set_current_pen (ctx);
663 cairo_stroke (ctx->cairo);
664 return GGRAPH_OK;
665 }
666
667 GGRAPH_DECLARE int
gGraphDrawRectangle(const void * context,double x,double y,double width,double height)668 gGraphDrawRectangle (const void *context, double x, double y, double width,
669 double height)
670 {
671 /* Drawing a filled rectangle */
672 gGraphContextPtr ctx = (gGraphContextPtr) context;
673 if (!ctx)
674 return GGRAPH_INVALID_PAINT_CONTEXT;
675 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
676 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
677 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
678 ;
679 else
680 return GGRAPH_INVALID_PAINT_CONTEXT;
681 cairo_rectangle (ctx->cairo, x, y, width, height);
682 set_current_brush (ctx);
683 cairo_fill_preserve (ctx->cairo);
684 set_current_pen (ctx);
685 cairo_stroke (ctx->cairo);
686 return GGRAPH_OK;
687 }
688
689 GGRAPH_DECLARE int
gGraphDrawRoundedRectangle(const void * context,double x,double y,double width,double height,double radius)690 gGraphDrawRoundedRectangle (const void *context, double x, double y,
691 double width, double height, double radius)
692 {
693 /* Drawing a filled rectangle with rounded corners */
694 double degrees = M_PI / 180.0;
695 gGraphContextPtr ctx = (gGraphContextPtr) context;
696 if (!ctx)
697 return GGRAPH_INVALID_PAINT_CONTEXT;
698 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
699 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
700 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
701 ;
702 else
703 return GGRAPH_INVALID_PAINT_CONTEXT;
704 cairo_new_sub_path (ctx->cairo);
705 cairo_arc (ctx->cairo, x + width - radius, y + radius, radius,
706 -90 * degrees, 0 * degrees);
707 cairo_arc (ctx->cairo, x + width - radius, y + height - radius, radius,
708 0 * degrees, 90 * degrees);
709 cairo_arc (ctx->cairo, x + radius, y + height - radius, radius,
710 90 * degrees, 180 * degrees);
711 cairo_arc (ctx->cairo, x + radius, y + radius, radius, 180 * degrees,
712 270 * degrees);
713 cairo_close_path (ctx->cairo);
714 set_current_brush (ctx);
715 cairo_fill_preserve (ctx->cairo);
716 set_current_pen (ctx);
717 cairo_stroke (ctx->cairo);
718 return GGRAPH_OK;
719 }
720
721 GGRAPH_DECLARE int
gGraphGetContextRgbArray(const void * context,unsigned char ** rgbArray)722 gGraphGetContextRgbArray (const void *context, unsigned char **rgbArray)
723 {
724 /* creating an RGB buffer from the given Context */
725 int width;
726 int height;
727 int x;
728 int y;
729 unsigned char *p_in;
730 unsigned char *p_out;
731 unsigned char *rgb;
732 int little_endian = gg_endian_arch ();
733 gGraphContextPtr ctx = (gGraphContextPtr) context;
734
735 *rgbArray = NULL;
736 if (!ctx)
737 return GGRAPH_INVALID_PAINT_CONTEXT;
738 if (ctx->signature != GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE)
739 return GGRAPH_INVALID_PAINT_CONTEXT;
740
741 width = cairo_image_surface_get_width (ctx->surface);
742 height = cairo_image_surface_get_height (ctx->surface);
743 rgb = malloc (width * height * 3);
744 if (!rgb)
745 return GGRAPH_INSUFFICIENT_MEMORY;
746
747 p_in = cairo_image_surface_get_data (ctx->surface);
748 p_out = rgb;
749 for (y = 0; y < height; y++)
750 {
751 for (x = 0; x < width; x++)
752 {
753 unsigned char r;
754 unsigned char g;
755 unsigned char b;
756 if (little_endian)
757 {
758 b = *p_in++;
759 g = *p_in++;
760 r = *p_in++;
761 p_in++; /* skipping Alpha */
762 }
763 else
764 {
765 p_in++; /* skipping Alpha */
766 r = *p_in++;
767 g = *p_in++;
768 b = *p_in++;
769 }
770 *p_out++ = r;
771 *p_out++ = g;
772 *p_out++ = b;
773 }
774 }
775 *rgbArray = rgb;
776 return GGRAPH_OK;
777 }
778
779 GGRAPH_DECLARE int
gGraphGetContextAlphaArray(const void * context,unsigned char ** alphaArray)780 gGraphGetContextAlphaArray (const void *context, unsigned char **alphaArray)
781 {
782 /* creating an Alpha buffer from the given Context */
783 int width;
784 int height;
785 int x;
786 int y;
787 unsigned char *p_in;
788 unsigned char *p_out;
789 unsigned char *alpha;
790 gGraphContextPtr ctx = (gGraphContextPtr) context;
791
792 *alphaArray = NULL;
793 if (!ctx)
794 return GGRAPH_INVALID_PAINT_CONTEXT;
795 if (ctx->signature != GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE)
796 return GGRAPH_INVALID_PAINT_CONTEXT;
797
798 width = cairo_image_surface_get_width (ctx->surface);
799 height = cairo_image_surface_get_height (ctx->surface);
800 alpha = malloc (width * height);
801 if (!alpha)
802 return GGRAPH_INSUFFICIENT_MEMORY;
803
804 p_in = cairo_image_surface_get_data (ctx->surface);
805 p_out = alpha;
806 for (y = 0; y < height; y++)
807 {
808 for (x = 0; x < width; x++)
809 {
810 p_in += 3; /* skipping RGB */
811 *p_out++ = *p_in++;
812 }
813 }
814 *alphaArray = alpha;
815 return GGRAPH_OK;
816 }
817
818 GGRAPH_DECLARE int
gGraphDrawBitmap(const void * context,const void * bitmap,int x,int y)819 gGraphDrawBitmap (const void *context, const void *bitmap, int x, int y)
820 {
821 /* drawing a symbol bitmap */
822 gGraphBitmapPtr bmp = (gGraphBitmapPtr) bitmap;
823 gGraphContextPtr ctx = (gGraphContextPtr) context;
824
825 if (!ctx)
826 return GGRAPH_INVALID_PAINT_CONTEXT;
827 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
828 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
829 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
830 ;
831 else
832 return GGRAPH_INVALID_PAINT_CONTEXT;
833
834 if (!bmp)
835 return GGRAPH_INVALID_PAINT_BITMAP;
836 if (bmp->signature != GG_GRAPHICS_BITMAP_MAGIC_SIGNATURE)
837 return GGRAPH_INVALID_PAINT_BITMAP;
838
839 cairo_save (ctx->cairo);
840 cairo_scale (ctx->cairo, 1, 1);
841 cairo_translate (ctx->cairo, x, y);
842 cairo_set_source (ctx->cairo, bmp->pattern);
843 cairo_rectangle (ctx->cairo, 0, 0, bmp->width, bmp->height);
844 cairo_fill (ctx->cairo);
845 cairo_restore (ctx->cairo);
846 return GGRAPH_OK;
847 }
848
849 static void
adjust_for_endianness(unsigned char * rgbaArray,int width,int height)850 adjust_for_endianness (unsigned char *rgbaArray, int width, int height)
851 {
852 /* Adjusting from RGBA to ARGB respecting platform endianness */
853 int x;
854 int y;
855 unsigned char red;
856 unsigned char green;
857 unsigned char blue;
858 unsigned char alpha;
859 unsigned char *p_in = rgbaArray;
860 unsigned char *p_out = rgbaArray;
861 int little_endian = gg_endian_arch ();
862
863 for (y = 0; y < height; y++)
864 {
865 for (x = 0; x < width; x++)
866 {
867 red = *p_in++;
868 green = *p_in++;
869 blue = *p_in++;
870 alpha = *p_in++;
871 if (alpha == 0)
872 {
873 *p_out++ = 0;
874 *p_out++ = 0;
875 *p_out++ = 0;
876 *p_out++ = 0;
877 }
878 else
879 {
880 if (little_endian)
881 {
882 *p_out++ = blue;
883 *p_out++ = green;
884 *p_out++ = red;
885 *p_out++ = alpha;
886 }
887 else
888 {
889 *p_out++ = alpha;
890 *p_out++ = red;
891 *p_out++ = green;
892 *p_out++ = blue;
893 }
894 }
895 }
896 }
897 }
898
899 GGRAPH_DECLARE int
gGraphCreateBitmap(unsigned char * rgbaArray,int width,int height,const void ** bitmap)900 gGraphCreateBitmap (unsigned char *rgbaArray, int width, int height,
901 const void **bitmap)
902 {
903 /* creating a symbol bitmap */
904 gGraphBitmapPtr bmp;
905
906 *bitmap = NULL;
907 if (!rgbaArray)
908 return GGRAPH_ERROR;
909
910 adjust_for_endianness (rgbaArray, width, height);
911 bmp = malloc (sizeof (gGraphBitmap));
912 if (!bmp)
913 return GGRAPH_INSUFFICIENT_MEMORY;
914 bmp->signature = GG_GRAPHICS_BITMAP_MAGIC_SIGNATURE;
915 bmp->width = width;
916 bmp->height = height;
917 bmp->bitmap =
918 cairo_image_surface_create_for_data (rgbaArray, CAIRO_FORMAT_ARGB32,
919 width, height, width * 4);
920 bmp->pattern = cairo_pattern_create_for_surface (bmp->bitmap);
921 *bitmap = bmp;
922 return GGRAPH_OK;
923 }
924
925 GGRAPH_DECLARE int
gGraphDestroyBitmap(const void * bitmap)926 gGraphDestroyBitmap (const void *bitmap)
927 {
928 /* destroying a symbol bitmap */
929 gGraphBitmapPtr bmp = (gGraphBitmapPtr) bitmap;
930
931 if (!bmp)
932 return GGRAPH_INVALID_PAINT_BITMAP;
933 if (bmp->signature != GG_GRAPHICS_BITMAP_MAGIC_SIGNATURE)
934 return GGRAPH_INVALID_PAINT_BITMAP;
935
936 cairo_pattern_destroy (bmp->pattern);
937 cairo_surface_destroy (bmp->bitmap);
938 free (bmp);
939 return GGRAPH_OK;
940 }
941
942 GGRAPH_DECLARE int
gGraphCreateBrush(unsigned char * rgbaArray,int width,int height,const void ** brush)943 gGraphCreateBrush (unsigned char *rgbaArray, int width, int height,
944 const void **brush)
945 {
946 /* creating a pattern brush */
947 gGraphPatternBrushPtr pattern;
948
949 *brush = NULL;
950 if (!rgbaArray)
951 return GGRAPH_ERROR;
952
953 adjust_for_endianness (rgbaArray, width, height);
954 pattern = malloc (sizeof (gGraphPatternBrush));
955 if (!pattern)
956 return GGRAPH_INSUFFICIENT_MEMORY;
957 pattern->signature = GG_GRAPHICS_BRUSH_MAGIC_SIGNATURE;
958 pattern->width = width;
959 pattern->height = height;
960 pattern->bitmap =
961 cairo_image_surface_create_for_data (rgbaArray, CAIRO_FORMAT_ARGB32,
962 width, height, width * 4);
963 pattern->pattern = cairo_pattern_create_for_surface (pattern->bitmap);
964 cairo_pattern_set_extend (pattern->pattern, CAIRO_EXTEND_REPEAT);
965 *brush = pattern;
966 return GGRAPH_OK;
967 }
968
969 GGRAPH_DECLARE int
gGraphDestroyBrush(const void * brush)970 gGraphDestroyBrush (const void *brush)
971 {
972 /* destroying a pattern brush */
973 gGraphPatternBrushPtr pattern = (gGraphPatternBrushPtr) brush;
974
975 if (!pattern)
976 return GGRAPH_INVALID_PAINT_BRUSH;
977 if (pattern->signature != GG_GRAPHICS_BRUSH_MAGIC_SIGNATURE)
978 return GGRAPH_INVALID_PAINT_BRUSH;
979
980 cairo_pattern_destroy (pattern->pattern);
981 cairo_surface_destroy (pattern->bitmap);
982 free (pattern);
983 return GGRAPH_OK;
984 }
985
986 GGRAPH_DECLARE int
gGraphCreateFont(double size,int style,int weight,const void ** font)987 gGraphCreateFont (double size, int style, int weight, const void **font)
988 {
989 /* creating a font */
990 gGraphFontPtr fnt;
991
992 *font = NULL;
993 fnt = malloc (sizeof (gGraphFont));
994 if (!fnt)
995 return GGRAPH_INSUFFICIENT_MEMORY;
996 fnt->signature = GG_GRAPHICS_FONT_MAGIC_SIGNATURE;
997 if (size < 1.0)
998 fnt->size = 1.0;
999 else if (size > 32.0)
1000 fnt->size = 32.0;
1001 else
1002 fnt->size = size;
1003 if (style == GGRAPH_FONTSTYLE_ITALIC)
1004 fnt->style = GGRAPH_FONTSTYLE_ITALIC;
1005 else
1006 fnt->style = GGRAPH_FONTSTYLE_NORMAL;
1007 if (weight == GGRAPH_FONTWEIGHT_BOLD)
1008 fnt->weight = GGRAPH_FONTWEIGHT_BOLD;
1009 else
1010 fnt->weight = GGRAPH_FONTWEIGHT_NORMAL;
1011 fnt->is_outlined = 0;
1012 fnt->outline_width = 0.0;
1013 fnt->red = 0.0;
1014 fnt->green = 0.0;
1015 fnt->blue = 0.0;
1016 fnt->alpha = 1.0;
1017 *font = fnt;
1018 return GGRAPH_OK;
1019 }
1020
1021 GGRAPH_DECLARE int
gGraphDestroyFont(const void * font)1022 gGraphDestroyFont (const void *font)
1023 {
1024 /* destroying a font */
1025 gGraphFontPtr fnt = (gGraphFontPtr) font;
1026
1027 if (!fnt)
1028 return GGRAPH_INVALID_PAINT_FONT;
1029 if (fnt->signature != GG_GRAPHICS_FONT_MAGIC_SIGNATURE)
1030 return GGRAPH_INVALID_PAINT_FONT;
1031
1032 free (fnt);
1033 return GGRAPH_OK;
1034 }
1035
1036 GGRAPH_DECLARE int
gGraphFontSetColor(const void * font,unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)1037 gGraphFontSetColor (const void *font, unsigned char red, unsigned char green,
1038 unsigned char blue, unsigned char alpha)
1039 {
1040 /* setting up the font color */
1041 gGraphFontPtr fnt = (gGraphFontPtr) font;
1042
1043 if (!fnt)
1044 return GGRAPH_INVALID_PAINT_FONT;
1045 if (fnt->signature != GG_GRAPHICS_FONT_MAGIC_SIGNATURE)
1046 return GGRAPH_INVALID_PAINT_FONT;
1047
1048 fnt->red = (double) red / 255.0;
1049 fnt->green = (double) green / 255.0;
1050 fnt->blue = (double) blue / 255.0;
1051 fnt->alpha = (double) alpha / 255.0;
1052 return GGRAPH_OK;
1053 }
1054
1055 GGRAPH_DECLARE int
gGraphFontSetOutline(const void * font,double width)1056 gGraphFontSetOutline (const void *font, double width)
1057 {
1058 /* setting up the font outline */
1059 gGraphFontPtr fnt = (gGraphFontPtr) font;
1060
1061 if (!fnt)
1062 return GGRAPH_INVALID_PAINT_FONT;
1063 if (fnt->signature != GG_GRAPHICS_FONT_MAGIC_SIGNATURE)
1064 return GGRAPH_INVALID_PAINT_FONT;
1065
1066 if (width <= 0.0)
1067 {
1068 fnt->is_outlined = 0;
1069 fnt->outline_width = 0.0;
1070 }
1071 else
1072 {
1073 fnt->is_outlined = 1;
1074 fnt->outline_width = width;
1075 }
1076 return GGRAPH_OK;
1077 }
1078
1079 GGRAPH_DECLARE int
gGraphSetFont(const void * context,const void * font)1080 gGraphSetFont (const void *context, const void *font)
1081 {
1082 /* setting up the current font */
1083 int style = CAIRO_FONT_SLANT_NORMAL;
1084 int weight = CAIRO_FONT_WEIGHT_NORMAL;
1085 double size;
1086 gGraphFontPtr fnt = (gGraphFontPtr) font;
1087 gGraphContextPtr ctx = (gGraphContextPtr) context;
1088
1089 if (!ctx)
1090 return GGRAPH_INVALID_PAINT_CONTEXT;
1091 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
1092 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
1093 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
1094 ;
1095 else
1096 return GGRAPH_INVALID_PAINT_CONTEXT;
1097
1098 if (!fnt)
1099 return GGRAPH_INVALID_PAINT_FONT;
1100 if (fnt->signature != GG_GRAPHICS_FONT_MAGIC_SIGNATURE)
1101 return GGRAPH_INVALID_PAINT_FONT;
1102
1103 if (fnt->style == GGRAPH_FONTSTYLE_ITALIC)
1104 style = CAIRO_FONT_SLANT_ITALIC;
1105 if (fnt->weight == GGRAPH_FONTWEIGHT_BOLD)
1106 weight = CAIRO_FONT_WEIGHT_BOLD;
1107 cairo_select_font_face (ctx->cairo, "monospace", style, weight);
1108 size = fnt->size;
1109 if (fnt->is_outlined)
1110 size += fnt->outline_width;
1111 cairo_set_font_size (ctx->cairo, size);
1112 ctx->font_red = fnt->red;
1113 ctx->font_green = fnt->green;
1114 ctx->font_blue = fnt->blue;
1115 ctx->font_alpha = fnt->alpha;
1116 ctx->is_font_outlined = fnt->is_outlined;
1117 ctx->font_outline_width = fnt->outline_width;
1118
1119 return GGRAPH_OK;
1120 }
1121
1122 GGRAPH_DECLARE int
gGraphGetTextExtent(const void * context,const char * text,double * pre_x,double * pre_y,double * width,double * height,double * post_x,double * post_y)1123 gGraphGetTextExtent (const void *context, const char *text, double *pre_x,
1124 double *pre_y, double *width, double *height,
1125 double *post_x, double *post_y)
1126 {
1127 /* measuring the text extent (using the current font) */
1128 cairo_text_extents_t extents;
1129 gGraphContextPtr ctx = (gGraphContextPtr) context;
1130
1131 if (!ctx)
1132 return GGRAPH_INVALID_PAINT_CONTEXT;
1133 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
1134 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
1135 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
1136 ;
1137 else
1138 return GGRAPH_INVALID_PAINT_CONTEXT;
1139
1140 cairo_text_extents (ctx->cairo, text, &extents);
1141 *pre_x = extents.x_bearing;
1142 *pre_y = extents.y_bearing;
1143 *width = extents.width;
1144 *height = extents.height;
1145 *post_x = extents.x_advance;
1146 *post_y = extents.y_advance;
1147 return GGRAPH_OK;
1148 }
1149
1150 GGRAPH_DECLARE int
gGraphDrawText(const void * context,const char * text,double x,double y,double angle)1151 gGraphDrawText (const void *context, const char *text, double x, double y,
1152 double angle)
1153 {
1154 /* drawing a text string (using the current font) */
1155 gGraphContextPtr ctx = (gGraphContextPtr) context;
1156
1157 if (!ctx)
1158 return GGRAPH_INVALID_PAINT_CONTEXT;
1159 if (ctx->signature == GG_GRAPHICS_CONTEXT_MAGIC_SIGNATURE ||
1160 ctx->signature == GG_GRAPHICS_SVG_CONTEXT_MAGIC_SIGNATURE ||
1161 ctx->signature == GG_GRAPHICS_PDF_CONTEXT_MAGIC_SIGNATURE)
1162 ;
1163 else
1164 return GGRAPH_INVALID_PAINT_CONTEXT;
1165
1166 cairo_save (ctx->cairo);
1167 cairo_translate (ctx->cairo, x, y);
1168 cairo_rotate (ctx->cairo, angle);
1169 if (ctx->is_font_outlined)
1170 {
1171 /* outlined font */
1172 cairo_move_to (ctx->cairo, 0.0, 0.0);
1173 cairo_text_path (ctx->cairo, text);
1174 cairo_set_source_rgba (ctx->cairo, ctx->font_red, ctx->font_green,
1175 ctx->font_blue, ctx->font_alpha);
1176 cairo_fill_preserve (ctx->cairo);
1177 cairo_set_source_rgba (ctx->cairo, 1.0, 1.0, 1.0, ctx->font_alpha);
1178 cairo_set_line_width (ctx->cairo, ctx->font_outline_width);
1179 cairo_stroke (ctx->cairo);
1180 }
1181 else
1182 {
1183 /* no outline */
1184 cairo_set_source_rgba (ctx->cairo, ctx->font_red, ctx->font_green,
1185 ctx->font_blue, ctx->font_alpha);
1186 cairo_move_to (ctx->cairo, 0.0, 0.0);
1187 cairo_show_text (ctx->cairo, text);
1188 }
1189 cairo_restore (ctx->cairo);
1190 return GGRAPH_OK;
1191 }
1192