2 * $Id: gp_cairo.c,v 1.16.2.3 2009/03/18 17:32:17 sfeam Exp $
5 /* GNUPLOT - gp_cairo.c */
8 * Copyright 2005,2006 Timothee Lecomte
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
37 * Alternatively, the contents of this file may be used under the terms of the
38 * GNU General Public License Version 2 or later (the "GPL"), in which case the
39 * provisions of GPL are applicable instead of those above. If you wish to allow
40 * use of your version of this file only under the terms of the GPL and not
41 * to allow others to use your version of this file under the above gnuplot
42 * license, indicate your decision by deleting the provisions above and replace
43 * them with the notice and other provisions required by the GPL. If you do not
44 * delete the provisions above, a recipient may use your version of this file
45 * under either the GPL or the gnuplot license.
48 /* -----------------------------------------------------
49 * This code uses the cairo library, a 2D graphics library with
50 * support for multiple output devices.
51 * Cairo is distributed under the LGPL licence.
53 * See http://www.cairographics.org for details.
55 * It also uses the pango library, a text-layout rendering library.
56 * Pango is distributed under the LGPL licence.
58 * See http://www.pango.org for details.
59 * -----------------------------------------------------*/
61 /* ------------------------------------------------------
62 * This file implements all cairo related functions,
63 * which provide drawing facilities.
65 * In particular, we have here :
66 * - all the basic calls (lines, polygons for pm3d, custom patterns),
68 * - enhanced text mode
70 * The text rendering is done via pango.
71 * ------------------------------------------------------*/
74 #include "gp_cairo_term.h"
78 #include <pango/pangocairo.h>
81 /* undef this to see what happens without the Symbol-to-unicode processing */
84 /* ======== enhanced text mode ======== */
85 /* copies of internal variables */
86 static char gp_cairo_enhanced_font[100] = "";
87 static const char* gp_cairo_enhanced_get_fontname();
88 static double gp_cairo_enhanced_fontsize = 0;
89 static double gp_cairo_enhanced_base = 0;
90 static TBOOLEAN gp_cairo_enhanced_widthflag = TRUE;
91 static TBOOLEAN gp_cairo_enhanced_showflag = TRUE;
92 static int gp_cairo_enhanced_overprint = FALSE;
93 static TBOOLEAN gp_cairo_enhanced_opened_string = FALSE; /* try to cut out empty ()'s */
94 /* pointer to the plot structure */
95 static plot_struct *gp_cairo_enhanced_plot = NULL;
96 /* utf8 text to draw and its attributes */
97 static gchar gp_cairo_utf8[2048] = "";
98 static PangoAttrList *gp_cairo_enhanced_AttrList = NULL;
99 /* save/restore facilitiy */
100 static TBOOLEAN gp_cairo_enhanced_restore_now = FALSE;
101 static TBOOLEAN gp_cairo_enhanced_save = FALSE;
102 static gchar gp_cairo_save_utf8[2048] = "";
103 static PangoAttrList *gp_cairo_enhanced_save_AttrList = NULL;
104 /* underprint/overprint facility */
105 static gchar gp_cairo_underprinted_utf8[2048] = "";
106 static PangoAttrList *gp_cairo_enhanced_underprinted_AttrList = NULL;
107 /* converts text from symbol encoding to utf8 encoding */
108 static gchar* gp_cairo_convert_symbol_to_unicode(plot_struct *plot, const char* string);
109 /* add standard attributes (fontsize,fontfamily, rise) to
110 * the specified characters in a PangoAttrList */
111 static void gp_cairo_add_attr( PangoAttrList * AttrList, int start, int end );
112 /* add a blank character to the text string and an associated custom shape to the attribute list */
113 static void gp_cairo_add_shape( PangoRectangle rect,int position);
116 /* set a cairo pattern or solid fill depending on parameters */
117 static void gp_cairo_fill(plot_struct *plot, int fillstyle, int fillpar);
118 static void gp_cairo_fill_pattern(plot_struct *plot, int fillpar);
121 * FIXME could be shared with all gnuplot terminals */
122 static rgb_color gp_cairo_colorlist[12] = {
129 {1,0,1}, /* magenta */
131 {1,1,0}, /* yellow */
133 {1,0.3,0}, /* orange */
134 {0.5,0.5,0.5} /* grey */
137 /* correspondance between gnuplot linetypes and terminal colors */
138 rgb_color gp_cairo_linetype2color( int linetype )
140 if (linetype<=LT_NODRAW)
141 linetype = LT_NODRAW; /* background color*/
143 return gp_cairo_colorlist[ linetype%9 +3 ];
146 /* initialize all fields of the plot structure */
147 void gp_cairo_initialize_plot(plot_struct *plot)
149 plot->xscale = 1.0; plot->yscale = 1.0;
150 plot->device_xmax = 1; plot->device_ymax = 1;
151 plot->xmax = 1; plot->ymax = 1;
153 plot->justify_mode = LEFT;
155 plot->linewidth = 1.0;
157 plot->pointsize = 1.0;
158 plot->text_angle = 0.0;
159 plot->color.r = 0.0; plot->color.g = 0.0; plot->color.b = 0.0;
161 plot->opened_path = FALSE;
163 strncpy(plot->fontname, "", sizeof(plot->fontname));
164 plot->fontsize = 1.0;
165 plot->encoding = S_ENC_DEFAULT;
167 plot->success = FALSE;
169 plot->antialiasing = TRUE;
171 plot->oversampling = TRUE;
172 plot->oversampling_scale = GP_CAIRO_SCALE;
178 plot->polygon_path_last = NULL;
180 plot->interrupt = FALSE;
184 /* set the transformation matrix of the context, and other details */
185 /* NOTE : depends on the setting of xscale and yscale */
186 void gp_cairo_initialize_context(plot_struct *plot)
188 cairo_matrix_t matrix;
190 if (plot->oversampling)
191 plot->oversampling_scale = GP_CAIRO_SCALE;
193 plot->oversampling_scale = 1;
195 if (plot->antialiasing)
196 cairo_set_antialias(plot->cr,CAIRO_ANTIALIAS_DEFAULT);
198 cairo_set_antialias(plot->cr,CAIRO_ANTIALIAS_NONE);
200 cairo_matrix_init(&matrix,
201 plot->xscale/plot->oversampling_scale,
203 plot->yscale/plot->oversampling_scale,
205 cairo_set_matrix(plot->cr, &matrix);
208 cairo_set_line_cap (plot->cr, CAIRO_LINE_CAP_SQUARE/*BUTT*/);
212 void gp_cairo_set_color(plot_struct *plot, rgb_color color)
214 FPRINTF((stderr,"set_color %lf %lf %lf\n",color.r, color.g, color.b));
216 /*stroke any open path */
217 gp_cairo_stroke(plot);
223 void gp_cairo_set_linestyle(plot_struct *plot, int linestyle)
225 FPRINTF((stderr,"set_linestyle %d\n",linestyle));
227 /*stroke any open path */
228 gp_cairo_stroke(plot);
229 /* draw any open polygon set */
230 gp_cairo_end_polygon(plot);
232 plot->linestyle = linestyle;
236 void gp_cairo_set_linetype(plot_struct *plot, int linetype)
238 FPRINTF((stderr,"set_linetype %d\n",linetype));
240 /*stroke any open path */
241 gp_cairo_stroke(plot);
242 /* draw any open polygon set */
243 gp_cairo_end_polygon(plot);
245 plot->linetype = linetype;
249 void gp_cairo_set_pointsize(plot_struct *plot, double pointsize)
251 FPRINTF((stderr,"set_pointsize %lf\n",pointsize));
253 plot->pointsize = pointsize;
257 void gp_cairo_set_justify(plot_struct *plot, JUSTIFY mode)
259 FPRINTF((stderr,"set_justify\n"));
261 plot->justify_mode = mode;
265 void gp_cairo_set_font(plot_struct *plot, const char *name, int fontsize)
267 FPRINTF((stderr,"set_font\n"));
269 strncpy( plot->fontname, name, sizeof(plot->fontname) );
270 plot->fontsize = fontsize;
274 void gp_cairo_set_linewidth(plot_struct *plot, double linewidth)
276 FPRINTF((stderr,"set_linewidth %lf\n",linewidth));
278 /*stroke any open path */
279 gp_cairo_stroke(plot);
280 /* draw any open polygon set */
281 gp_cairo_end_polygon(plot);
283 plot->linewidth = linewidth;
287 void gp_cairo_set_textangle(plot_struct *plot, double angle)
289 FPRINTF((stderr,"set_textangle %lf\n",angle));
291 plot->text_angle =angle;
294 /* By default, Cairo uses an antialiasing algorithm which
295 * will let a seam between polygons which
296 * share common edges.
297 * Several solutions allow to workaround this behaviour :
298 * - don't antialias the polygons
299 * Problem : aliased lines are ugly
300 * - stroke on each edge
301 * Problem : stroking is a very time-consuming operation
302 * - draw without antialiasing to a separate context of a bigger size
303 * Problem : not really in the spirit of the rest of the drawing.
304 * - dilatate the polygon so that they overlap slightly
305 * It is really more time-consuming that it may seem. It implies dealing
306 * with each corner, find on which direction to move it (making
307 * the difference between the inside and the outside of the polygon).
308 * - using CAIRO_OPERATOR_SATURATE
309 * Problem : for each set of polygons, we have to draw front-to-back
310 * on a separate context and then copy back to this one.
311 * Time-consuming but probably less than stroking all the edges.
313 * The last solution is implemented here.
314 * We will only use the method when more than 2 successice polygons are drawn.
316 void gp_cairo_draw_polygon(plot_struct *plot, int n, gpiPoint *corners)
321 /* begin by stroking any open path */
322 gp_cairo_stroke(plot);
324 path = (path_item*) gp_alloc(sizeof(path_item), "gp_cairo : polygon path");
327 path->corners = (gpiPoint*) gp_alloc(n*sizeof(gpiPoint), "gp_cairo : polygon corners");
329 *(path->corners + i) = *corners++;
331 path->color = plot->color;
333 if (plot->polygon_path_last == NULL) {
334 FPRINTF((stderr,"creating a polygon path\n"));
335 path->previous = NULL;
336 plot->polygon_path_last = path;
338 FPRINTF((stderr,"adding a polygon to the polygon path\n"));
339 path->previous = plot->polygon_path_last;
340 plot->polygon_path_last = path;
345 void gp_cairo_end_polygon(plot_struct *plot)
352 cairo_t *context_sav;
353 cairo_surface_t *surface;
354 cairo_matrix_t matrix;
355 cairo_matrix_t matrix2;
356 cairo_pattern_t *pattern;
358 if (plot->polygon_path_last == NULL)
361 path = plot->polygon_path_last;
362 color_sav = plot->color;
364 /* if there's only one polygon, draw it directly */
365 if (path->previous == NULL) {
366 FPRINTF((stderr,"processing one polygon\n"));
367 cairo_move_to(plot->cr, path->corners[0].x, path->corners[0].y);
368 for (i=1;i<path->n;++i)
369 cairo_line_to(plot->cr, path->corners[i].x, path->corners[i].y);
370 cairo_close_path(plot->cr);
371 plot->color = path->color;
372 gp_cairo_fill( plot, path->corners->style & 0xf, path->corners->style >> 4 );
373 cairo_fill(plot->cr);
376 plot->polygon_path_last = NULL;
377 plot->color = color_sav;
381 FPRINTF((stderr,"processing several polygons\n"));
383 /* this is meant to test Full-Scene-Anti-Aliasing by supersampling,
384 * in association with CAIRO_ANTIALIAS_NONE a few lines below */
387 /* otherwise, draw front-to-back to a separate context,
388 * using CAIRO_OPERATOR_SATURATE */
389 context_sav = plot->cr;
390 surface = cairo_surface_create_similar(cairo_get_target(plot->cr),
391 CAIRO_CONTENT_COLOR_ALPHA,
392 plot->device_xmax*SCALE,
393 plot->device_ymax*SCALE);
394 context = cairo_create(surface);
395 cairo_set_operator(context,CAIRO_OPERATOR_SATURATE);
396 if (plot->antialiasing)
397 cairo_set_antialias(context,CAIRO_ANTIALIAS_DEFAULT);
399 cairo_set_antialias(context,CAIRO_ANTIALIAS_NONE);
401 /* transformation matrix between gnuplot and cairo coordinates */
402 cairo_matrix_init(&matrix,
403 plot->xscale/SCALE/plot->oversampling_scale,
405 plot->yscale/SCALE/plot->oversampling_scale,
407 cairo_set_matrix(context, &matrix);
410 path = plot->polygon_path_last;
412 while (path != NULL) {
413 /* check for interrupt */
417 cairo_move_to(plot->cr, path->corners[0].x, path->corners[0].y);
418 for (i=1;i<(path->n);++i)
419 cairo_line_to(plot->cr, path->corners[i].x, path->corners[i].y);
420 cairo_close_path(plot->cr);
421 /* set the fill pattern */
422 plot->color = path->color;
423 gp_cairo_fill( plot, path->corners->style & 0xf, path->corners->style >> 4 );
424 cairo_fill(plot->cr);
425 /* free the ressources, and go to the next point */
427 path2 = path->previous;
432 plot->polygon_path_last = NULL;
434 pattern = cairo_pattern_create_for_surface( surface );
435 cairo_destroy( context );
437 /* compensate the transformation matrix of the main context */
438 cairo_matrix_init(&matrix2,
439 plot->xscale*SCALE/plot->oversampling_scale,
441 plot->yscale*SCALE/plot->oversampling_scale,
443 cairo_pattern_set_matrix( pattern, &matrix2 );
445 plot->cr = context_sav;
446 plot->color = color_sav;
447 cairo_surface_destroy( surface );
448 cairo_set_source( plot->cr, pattern );
449 cairo_pattern_destroy( pattern );
450 cairo_paint( plot->cr );
453 void gp_cairo_stroke(plot_struct *plot)
455 double dashes[2] = {0,0};
457 if (!plot->opened_path)
460 FPRINTF((stderr,"stroke - color %lf %lf %lf\n",plot->color.r, plot->color.g, plot->color.b));
463 cairo_line_to (plot->cr, plot->current_x, plot->current_y);
465 dashes[0] = 2.0*plot->oversampling_scale;
466 dashes[1] = 2.0*plot->oversampling_scale;
468 cairo_save(plot->cr);
470 if (plot->linetype == LT_NODRAW)
471 cairo_set_operator(plot->cr, CAIRO_OPERATOR_XOR);
473 if (plot->linestyle == GP_CAIRO_DASH)
474 cairo_set_dash(plot->cr, dashes, 2 /*num_dashes*/, 0 /*offset*/);
476 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
477 cairo_set_line_width(plot->cr, plot->linewidth*plot->oversampling_scale);
479 cairo_stroke(plot->cr);
481 cairo_restore(plot->cr);
483 plot->opened_path = FALSE;
487 void gp_cairo_move(plot_struct *plot, int x, int y)
489 FPRINTF((stderr,"move\n"));
491 /* begin by stroking any open path */
492 gp_cairo_stroke(plot);
493 /* also draw any open polygon set */
494 gp_cairo_end_polygon(plot);
498 plot->orig_current_x = x;
499 plot->orig_current_y = y;
503 void gp_cairo_vector(plot_struct *plot, int x, int y)
505 double x1 = x, y1 = y;
507 double weight1 = (double) plot->hinting/100;
508 double weight2 = 1.0 - weight1;
510 FPRINTF((stderr,"vector\n"));
512 /* begin by drawing any open polygon set */
513 gp_cairo_end_polygon(plot);
515 /* hinting magic when we are using antialiasing+oversampling */
516 if (plot->antialiasing && plot->oversampling) {
517 if (plot->hinting < 0 || plot->hinting > 100) {
518 fprintf(stderr,"wxt terminal : hinting error, setting to default\n");
522 /* detect and handle vertical lines */
523 /* the second test is there to avoid artefacts when you choose
524 * a high sampling ('set samples 10000'), so that a smooth function
525 * may be drawn as lines between very close points */
526 if (plot->orig_current_x == x1 && fabs(plot->orig_current_y - y1)>plot->oversampling_scale) {
527 new_pos = rint(plot->current_x*plot->xscale/plot->oversampling_scale);
528 new_pos *= plot->oversampling_scale/plot->xscale;
529 plot->current_x = weight1*new_pos + weight2*plot->current_x;
530 x1 = plot->current_x;
531 new_pos = rint(plot->current_y*plot->yscale/plot->oversampling_scale);
532 new_pos *= plot->oversampling_scale/plot->yscale;
533 plot->current_y = weight1*new_pos + weight2*plot->current_y;
534 new_pos = rint(y1*plot->yscale/plot->oversampling_scale);
535 new_pos *= plot->oversampling_scale/plot->yscale;
536 y1 = weight1*new_pos + weight2*y1;
538 /* do the same for horizontal lines */
539 if (plot->orig_current_y == y1 && fabs(plot->orig_current_x - x1)>plot->oversampling_scale) {
540 new_pos = rint(plot->current_y*plot->yscale/plot->oversampling_scale);
541 new_pos *= plot->oversampling_scale/plot->yscale;
542 plot->current_y = weight1*new_pos + weight2*plot->current_y;
543 y1 = plot->current_y;
544 new_pos = rint(plot->current_x*plot->xscale/plot->oversampling_scale);
545 new_pos *= plot->oversampling_scale/plot->xscale;
546 plot->current_x = weight1*new_pos + weight2*plot->current_x;
547 new_pos = rint(x1*plot->xscale/plot->oversampling_scale);
548 new_pos *= plot->oversampling_scale/plot->xscale;
549 x1 = weight1*new_pos + weight2*x1;
553 if (!plot->opened_path) {
554 plot->opened_path = TRUE;
555 cairo_move_to (plot->cr, plot->current_x, plot->current_y);
557 cairo_line_to (plot->cr, plot->current_x, plot->current_y);
559 plot->current_x = x1;
560 plot->current_y = y1;
561 plot->orig_current_x = x;
562 plot->orig_current_y = y;
565 /* pango needs a string encoded in utf-8. We use g_convert from glib.
566 * gp_cairo_get_encoding() gives the encoding set via 'set enconding'
567 * memory allocated for the string has to be freed */
568 gchar * gp_cairo_convert(plot_struct *plot, const char* string)
571 GError *error = NULL;
572 const char *charset = NULL;
575 charset = gp_cairo_get_encoding(plot);
577 string_utf8 = g_convert(string, -1, "UTF-8", charset, &bytes_read, NULL, &error);
579 /* handle error case */
581 /* fatal error in conversion */
582 if (error->code != G_CONVERT_ERROR_ILLEGAL_SEQUENCE) {
583 fprintf(stderr, "Unable to convert \"%s\": %s\n", string, error->message);
584 g_error_free (error);
587 /* The sequence is invalid in the chosen charset.
588 * we will try to fall back to iso_8859_1, and if it doesn't work,
589 * we'll use bytes_read to convert up to the faulty character,
590 * and throw the rest. */
591 g_error_free (error);
593 string_utf8 = g_convert(string, -1, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
595 fprintf(stderr, "Unable to convert \"%s\": the sequence is invalid "\
596 "in the current charset (%s), %d bytes read out of %d\n",
597 string, charset, bytes_read, strlen(string));
598 string_utf8 = g_convert(string, bytes_read, "UTF-8", charset, NULL, NULL, NULL);
599 g_error_free (error);
601 fprintf(stderr, "Unable to convert \"%s\": the sequence is invalid "\
602 "in the current charset (%s), falling back to iso_8859_1\n",
610 void gp_cairo_draw_text(plot_struct *plot, int x1, int y1, const char* string)
613 double arg = plot->text_angle * M_PI/180;
614 double vert_just, delta, deltax, deltay;
615 PangoRectangle ink_rect;
616 PangoRectangle logical_rect;
618 PangoFontDescription *desc;
621 TBOOLEAN symbol_font_parsed = FALSE;
622 #endif /*MAP_SYMBOL*/
625 /* begin by stroking any open path */
626 gp_cairo_stroke(plot);
627 /* also draw any open polygon set */
628 gp_cairo_end_polygon(plot);
631 /* we have to treat Symbol font as a special case */
632 if (!strcmp(plot->fontname,"Symbol")) {
633 FPRINTF((stderr,"Parsing a Symbol string\n"));
634 string_utf8 = gp_cairo_convert_symbol_to_unicode(plot, string);
635 strncpy(plot->fontname, "Sans", sizeof(plot->fontname));
636 symbol_font_parsed = TRUE;
638 #endif /*MAP_SYMBOL*/
640 /* convert the input string to utf8 */
641 string_utf8 = gp_cairo_convert(plot, string);
644 /* Create a PangoLayout, set the font and text */
645 layout = pango_cairo_create_layout (plot->cr);
647 pango_layout_set_text (layout, string_utf8, -1);
649 desc = pango_font_description_new ();
650 pango_font_description_set_family (desc, (const char*) plot->fontname);
652 /* restore the Symbol font setting */
653 if (symbol_font_parsed)
654 strncpy(plot->fontname, "Symbol", sizeof(plot->fontname));
655 #endif /*MAP_SYMBOL*/
656 pango_font_description_set_size (desc, (int) (plot->fontsize*PANGO_SCALE*plot->oversampling_scale) );
657 pango_layout_set_font_description (layout, desc);
658 pango_font_description_free (desc);
660 pango_layout_get_extents(layout, &ink_rect, &logical_rect);
662 /* vert_just = ((double)ink_rect.height/2 +(double)ink_rect.y) / PANGO_SCALE; */
663 vert_just = term->v_char / 2;
668 x -= vert_just * sin(arg);
669 y -= vert_just * cos(arg);
671 delta = ((double)logical_rect.width/2) / PANGO_SCALE;
673 deltax = delta * cos(arg);
674 deltay = delta * sin(arg);
676 switch (plot->justify_mode) {
689 #if 0 /* helper point */
690 gp_cairo_cairo_draw_point( x1, y1, 0);
691 #endif /* helper point */
693 cairo_save (plot->cr);
694 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
695 cairo_move_to (plot->cr, x-0.5, y-0.5);
696 cairo_rotate(plot->cr, -arg);
698 /* Inform Pango to re-layout the text with the new transformation */
699 pango_cairo_update_layout (plot->cr, layout);
700 pango_cairo_show_layout (plot->cr, layout);
702 #if 0 /* helper boxes to understand how text is positionned */
703 cairo_rotate(plot->cr, arg);
704 cairo_translate(plot->cr, x, y);
705 cairo_rotate(plot->cr, -arg);
707 PangoRectangle ink, logical;
708 double lw = cairo_get_line_width (plot->cr);
709 pango_layout_get_extents (layout, &ink, &logical);
711 cairo_set_source_rgba (plot->cr, 1.0, 0.0, 0.0, 0.75);
712 cairo_rectangle (plot->cr,
713 (double)logical.x / PANGO_SCALE - lw / 2,
714 (double)logical.y / PANGO_SCALE - lw / 2,
715 (double)logical.width / PANGO_SCALE + lw,
716 (double)logical.height / PANGO_SCALE + lw);
717 cairo_stroke (plot->cr);
719 cairo_set_source_rgba (plot->cr, 0.0, 1.0, 0.0, 0.75);
720 cairo_rectangle (plot->cr,
721 (double)ink.x / PANGO_SCALE - lw / 2,
722 (double)ink.y / PANGO_SCALE - lw / 2,
723 (double)ink.width / PANGO_SCALE + lw,
724 (double)ink.height / PANGO_SCALE + lw);
725 cairo_stroke (plot->cr);
726 #endif /* helper boxes to understand how text is positionned */
728 /* free the layout object */
729 g_object_unref (layout);
730 cairo_restore (plot->cr);
734 void gp_cairo_draw_point(plot_struct *plot, int x1, int y1, int style)
739 double weight1 = (double) plot->hinting/100;
740 double weight2 = 1.0 - weight1;
741 double size = plot->pointsize*3*plot->oversampling_scale;
743 /* begin by stroking any open path */
744 gp_cairo_stroke(plot);
745 /* also draw any open polygon set */
746 gp_cairo_end_polygon(plot);
748 /* hinting magic when we are using antialiasing+oversampling */
749 if (plot->antialiasing && plot->oversampling) {
750 if (plot->hinting < 0 || plot->hinting > 100) {
751 fprintf(stderr,"wxt terminal : hinting error, setting to default\n");
755 new_pos = rint(x*plot->xscale/plot->oversampling_scale);
756 new_pos *= plot->oversampling_scale/plot->xscale;
757 x = weight1*new_pos + weight2*x;
759 new_pos = rint(y*plot->yscale/plot->oversampling_scale);
760 new_pos *= plot->oversampling_scale/plot->yscale;
761 y = weight1*new_pos + weight2*y;
764 cairo_save(plot->cr);
765 cairo_set_line_width(plot->cr, 1.0*plot->oversampling_scale);
766 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
768 /* always draw a dot. Nothing more is needed for style=-1 */
769 cairo_arc (plot->cr, x, y, 0.5*plot->oversampling_scale, 0, 2*M_PI);
770 cairo_fill (plot->cr);
774 cairo_move_to(plot->cr, x-size, y);
775 cairo_line_to(plot->cr, x+size,y);
776 cairo_stroke(plot->cr);
777 cairo_move_to(plot->cr, x, y-size);
778 cairo_line_to(plot->cr, x,y+size);
779 cairo_stroke(plot->cr);
781 case 1: /* plot->cross */
782 cairo_move_to(plot->cr, x-size, y-size);
783 cairo_line_to(plot->cr, x+size,y+size);
784 cairo_stroke(plot->cr);
785 cairo_move_to(plot->cr, x-size, y+size);
786 cairo_line_to(plot->cr, x+size,y-size);
787 cairo_stroke(plot->cr);
790 cairo_move_to(plot->cr, x-size, y);
791 cairo_line_to(plot->cr, x+size,y);
792 cairo_stroke(plot->cr);
793 cairo_move_to(plot->cr, x, y-size);
794 cairo_line_to(plot->cr, x,y+size);
795 cairo_stroke(plot->cr);
796 cairo_move_to(plot->cr, x-size, y-size);
797 cairo_line_to(plot->cr, x+size,y+size);
798 cairo_stroke(plot->cr);
799 cairo_move_to(plot->cr, x-size, y+size);
800 cairo_line_to(plot->cr, x+size,y-size);
801 cairo_stroke(plot->cr);
804 cairo_move_to(plot->cr, x-size, y-size);
805 cairo_line_to(plot->cr, x-size,y+size);
806 cairo_line_to(plot->cr, x+size,y+size);
807 cairo_line_to(plot->cr, x+size,y-size);
808 cairo_close_path(plot->cr);
809 cairo_stroke(plot->cr);
811 case 4: /* filled box */
812 cairo_move_to(plot->cr, x-size, y-size);
813 cairo_line_to(plot->cr, x-size,y+size);
814 cairo_line_to(plot->cr, x+size,y+size);
815 cairo_line_to(plot->cr, x+size,y-size);
816 cairo_close_path(plot->cr);
817 cairo_fill_preserve(plot->cr);
818 cairo_stroke(plot->cr);
821 cairo_arc (plot->cr, x, y, size, 0, 2*M_PI);
822 cairo_stroke (plot->cr);
824 case 6: /* filled circle */
825 cairo_arc (plot->cr, x, y, size, 0, 2*M_PI);
826 cairo_fill_preserve(plot->cr);
827 cairo_stroke(plot->cr);
829 case 7: /* triangle */
830 cairo_move_to(plot->cr, x-size, y+size-plot->oversampling_scale);
831 cairo_line_to(plot->cr, x,y-size);
832 cairo_line_to(plot->cr, x+size,y+size-plot->oversampling_scale);
833 cairo_close_path(plot->cr);
834 cairo_stroke(plot->cr);
836 case 8: /* filled triangle */
837 cairo_move_to(plot->cr, x-size, y+size-plot->oversampling_scale);
838 cairo_line_to(plot->cr, x,y-size);
839 cairo_line_to(plot->cr, x+size,y+size-plot->oversampling_scale);
840 cairo_close_path(plot->cr);
841 cairo_fill_preserve(plot->cr);
842 cairo_stroke(plot->cr);
844 case 9: /* upside down triangle */
845 cairo_move_to(plot->cr, x-size, y-size+plot->oversampling_scale);
846 cairo_line_to(plot->cr, x,y+size);
847 cairo_line_to(plot->cr, x+size,y-size+plot->oversampling_scale);
848 cairo_close_path(plot->cr);
849 cairo_stroke(plot->cr);
851 case 10: /* filled upside down triangle */
852 cairo_move_to(plot->cr, x-size, y-size+plot->oversampling_scale);
853 cairo_line_to(plot->cr, x,y+size);
854 cairo_line_to(plot->cr, x+size,y-size+plot->oversampling_scale);
855 cairo_close_path(plot->cr);
856 cairo_fill_preserve(plot->cr);
857 cairo_stroke(plot->cr);
859 case 11: /* diamond */
860 cairo_move_to(plot->cr, x-size, y);
861 cairo_line_to(plot->cr, x,y+size);
862 cairo_line_to(plot->cr, x+size,y);
863 cairo_line_to(plot->cr, x,y-size);
864 cairo_close_path(plot->cr);
865 cairo_stroke(plot->cr);
867 case 12: /* filled diamond */
868 cairo_move_to(plot->cr, x-size, y);
869 cairo_line_to(plot->cr, x,y+size);
870 cairo_line_to(plot->cr, x+size,y);
871 cairo_line_to(plot->cr, x,y-size);
872 cairo_close_path(plot->cr);
873 cairo_fill_preserve(plot->cr);
874 cairo_stroke(plot->cr);
879 cairo_restore(plot->cr);
884 void gp_cairo_draw_fillbox(plot_struct *plot, int x, int y, int width, int height, int style)
886 int fillpar = style >> 4;
887 int fillstyle = style & 0xf;
889 /* begin by stroking any open path */
890 gp_cairo_stroke(plot);
891 /* also draw any open polygon set */
892 gp_cairo_end_polygon(plot);
894 FPRINTF((stderr,"fillbox fillpar = %d, fillstyle = %d\n",fillpar, fillstyle));
895 gp_cairo_fill( plot, fillstyle, fillpar);
897 cairo_move_to(plot->cr, x, y);
898 cairo_rel_line_to(plot->cr,0, -height);
899 cairo_rel_line_to(plot->cr, width-1, 0);
900 cairo_rel_line_to(plot->cr, 0, height);
901 cairo_rel_line_to(plot->cr, -width+1, 0);
902 cairo_close_path(plot->cr);
903 cairo_fill(plot->cr);
908 /* corner[0] = (x1,y1) is the upper left corner (in terms of plot location) of
909 * the outer edge of the image. Similarly, corner[1] = (x2,y2) is the lower
910 * right corner of the outer edge of the image. (Outer edge means the
911 * outer extent of the corner pixels, not the middle of the corner pixels).
912 * corner[2] and corner[3] = (x3,y3) and (x4,y4) define a clipping box in
913 * the primary plot into which all or part of the image will be rendered.
915 void gp_cairo_draw_image(plot_struct *plot, coordval * image, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int M, int N, t_imagecolor color_mode)
918 unsigned int *image255, *image255copy;
919 double scale_x, scale_y;
922 cairo_surface_t *image_surface;
923 cairo_pattern_t *pattern;
924 cairo_matrix_t matrix;
926 /* begin by stroking any open path */
927 gp_cairo_stroke(plot);
928 /* also draw any open polygon set */
929 gp_cairo_end_polygon(plot);
931 /* cairo image buffer, upper bits are alpha, then r, g and b
932 * Depends on endianess */
933 image255 = (unsigned int*) gp_alloc(M*N*sizeof(unsigned int), "gp_cairo : draw image");
934 image255copy = image255;
936 /* TrueColor 24-bit plot->color mode */
937 if (color_mode == IC_RGB) {
938 for (n=0; n<N; n++) {
939 for (m=0; m<M; m++) {
943 rgb255_from_rgb1( rgb1, &rgb255 );
944 *image255copy++ = (0xFF<<24) + (rgb255.r<<16) + (rgb255.g<<8) + rgb255.b;
947 /* Palette plot->color lookup from gray value */
949 for (n=0; n<N; n++) {
950 for (m=0; m<M; m++) {
951 rgb255maxcolors_from_gray( *image++, &rgb255 );
952 *image255copy++ = (0xFF<<24) + (rgb255.r<<16) + (rgb255.g<<8) + rgb255.b;
957 image_surface = cairo_image_surface_create_for_data((unsigned char*) image255,
958 CAIRO_FORMAT_ARGB32, M, N, 4*M);
960 scale_x = (double)M/fabs( x2 - x1 );
961 scale_y = (double)N/fabs( y2 - y1 );
963 FPRINTF((stderr,"M %d N %lf x1 %d y1 %d\n", M, N, x1, y1));
964 cairo_save( plot->cr );
966 /* Set clipping boundaries for image copy.
967 * The bounds were originally possed in corners[2] and corners[3]
969 cairo_move_to(plot->cr, x3, y3);
970 cairo_line_to(plot->cr, x3, y4);
971 cairo_line_to(plot->cr, x4, y4);
972 cairo_line_to(plot->cr, x4, y3);
973 cairo_close_path(plot->cr);
974 cairo_clip(plot->cr);
976 pattern = cairo_pattern_create_for_surface( image_surface );
977 /* scale and keep sharp edges */
978 cairo_pattern_set_filter( pattern, CAIRO_FILTER_FAST );
979 cairo_matrix_init_scale( &matrix, scale_x, scale_y );
980 /* x1 and y1 give the user-space coordinate
981 * at which the surface origin should appear.
982 * (The surface origin is its upper-left corner
983 * before any transformation has been applied.) */
984 cairo_matrix_translate( &matrix, -x1, -y1 );
985 cairo_pattern_set_matrix( pattern, &matrix );
986 cairo_set_source( plot->cr, pattern );
988 cairo_paint( plot->cr );
990 cairo_restore( plot->cr );
992 cairo_pattern_destroy( pattern );
993 cairo_surface_destroy( image_surface );
996 #endif /*WITH_IMAGE*/
998 /* =======================================================================
999 * Enhanced text mode support
1000 * =====================================================================*/
1002 void gp_cairo_add_attr( PangoAttrList * AttrList, int start, int end )
1004 PangoAttribute *p_attr_rise, *p_attr_size, *p_attr_family;
1006 p_attr_size = pango_attr_size_new ((int) (gp_cairo_enhanced_fontsize*PANGO_SCALE));
1007 p_attr_size->start_index = start;
1008 p_attr_size->end_index = end;
1009 pango_attr_list_insert (AttrList, p_attr_size);
1011 p_attr_rise = pango_attr_rise_new ((int) (gp_cairo_enhanced_base*PANGO_SCALE));
1012 p_attr_rise->start_index = start;
1013 p_attr_rise->end_index = end;
1014 pango_attr_list_insert (AttrList, p_attr_rise);
1016 p_attr_family = pango_attr_family_new (gp_cairo_enhanced_get_fontname());
1017 p_attr_family->start_index = start;
1018 p_attr_family->end_index = end;
1019 pango_attr_list_insert (AttrList, p_attr_family);
1022 /* add a blank character to the text string with a custom shape */
1023 void gp_cairo_add_shape( PangoRectangle rect,int position)
1025 PangoAttribute *p_attr_shape;
1027 FPRINTF((stderr, "adding blank custom shape\n"));
1029 strncat(gp_cairo_utf8, " ", sizeof(gp_cairo_utf8)-strlen(gp_cairo_utf8));
1030 p_attr_shape = pango_attr_shape_new (&rect,&rect);
1031 p_attr_shape->start_index = position;
1032 p_attr_shape->end_index = position+1;
1033 pango_attr_list_insert (gp_cairo_enhanced_AttrList, p_attr_shape);
1036 /* gp_cairo_enhanced_flush() draws enhanced_text, which has been filled by _writec()*/
1037 void gp_cairo_enhanced_flush()
1039 PangoRectangle save_logical_rect;
1040 PangoLayout *save_layout;
1042 PangoLayout *current_layout;
1043 PangoRectangle current_ink_rect;
1044 PangoRectangle current_logical_rect;
1045 PangoFontDescription *current_desc;
1047 PangoRectangle underprinted_logical_rect;
1048 int overprinted_width = 0;
1049 PangoLayout *underprinted_layout;
1051 PangoLayout *hide_layout;
1053 PangoRectangle hide_ink_rect;
1054 PangoRectangle hide_logical_rect;
1055 PangoFontDescription *hide_desc;
1056 PangoLayout *zerowidth_layout;
1057 PangoFontDescription *zerowidth_desc;
1058 PangoRectangle zerowidth_logical_rect;
1059 /* PangoRectangle zerowidth_ink_rect; */
1061 int save_start, save_end;
1062 int underprinted_start, underprinted_end;
1064 gchar* enhanced_text_utf8;
1067 TBOOLEAN symbol_font_parsed = FALSE;
1068 #endif /*MAP_SYMBOL*/
1070 if (!gp_cairo_enhanced_opened_string)
1073 /* mark the end of the string */
1074 *enhanced_cur_text = '\0';
1076 FPRINTF((stderr, "enhanced flush str=\"%s\" font=%s op=%d sf=%d wf=%d base=%f os=%d\n",
1078 gp_cairo_enhanced_font,
1079 gp_cairo_enhanced_overprint,
1080 gp_cairo_enhanced_showflag,
1081 gp_cairo_enhanced_widthflag,
1082 gp_cairo_enhanced_base,
1083 gp_cairo_enhanced_opened_string ));
1085 gp_cairo_enhanced_opened_string = FALSE;
1088 /* we have to treat Symbol font as a special case */
1089 if (!strcmp(gp_cairo_enhanced_font,"Symbol")) {
1090 FPRINTF((stderr,"Parsing a Symbol string\n"));
1092 enhanced_text_utf8 = gp_cairo_convert_symbol_to_unicode(gp_cairo_enhanced_plot, enhanced_text);
1094 if (!strcmp(gp_cairo_enhanced_plot->fontname,"Symbol")) {
1095 strncpy(gp_cairo_enhanced_font,
1096 gp_cairo_enhanced_plot->fontname,
1097 sizeof(gp_cairo_enhanced_font));
1099 strncpy(gp_cairo_enhanced_font,
1100 "Sans", sizeof(gp_cairo_enhanced_font));
1102 symbol_font_parsed = TRUE;
1104 #endif /*MAP_SYMBOL*/
1106 /* convert the input string to utf8 */
1107 enhanced_text_utf8 = gp_cairo_convert(gp_cairo_enhanced_plot, enhanced_text);
1110 start = strlen(gp_cairo_utf8);
1112 if (gp_cairo_enhanced_restore_now) {
1113 /* restore saved position */
1114 /* the idea is to use a space character, drawn with a negative width */
1116 /* we first compute the size of the text drawn since the 'save' command */
1118 /* Create a PangoLayout, set the font and text
1119 * with the saved attributes list, get extents */
1120 save_layout = pango_cairo_create_layout (gp_cairo_enhanced_plot->cr);
1121 pango_layout_set_text (save_layout, gp_cairo_save_utf8, -1);
1122 pango_layout_set_attributes (save_layout, gp_cairo_enhanced_save_AttrList);
1123 pango_layout_get_extents(save_layout, NULL, &save_logical_rect);
1124 g_object_unref (save_layout);
1125 pango_attr_list_unref( gp_cairo_enhanced_save_AttrList );
1126 /* invert the size, so we will go back to the saved state */
1127 save_logical_rect.width = -save_logical_rect.width;
1128 /* adding a blank character with the corresponding shape */
1129 gp_cairo_add_shape(save_logical_rect,start);
1131 strncpy(gp_cairo_save_utf8, "", sizeof(gp_cairo_save_utf8));
1132 gp_cairo_enhanced_restore_now = FALSE;
1136 if (gp_cairo_enhanced_overprint==2) {
1137 /* the idea is first to use a space character, drawn with an appropriate negative width */
1139 /* we first compute the size of the text drawn since overprint==1 was used */
1141 /* Create a PangoLayout, set the font and text with
1142 * the saved attributes list, get extents */
1143 underprinted_layout = pango_cairo_create_layout (gp_cairo_enhanced_plot->cr);
1144 pango_layout_set_text (underprinted_layout, gp_cairo_underprinted_utf8, -1);
1145 pango_layout_set_attributes (underprinted_layout, gp_cairo_enhanced_underprinted_AttrList);
1146 pango_layout_get_extents(underprinted_layout, NULL, &underprinted_logical_rect);
1147 g_object_unref (underprinted_layout);
1148 pango_attr_list_unref( gp_cairo_enhanced_underprinted_AttrList );
1150 /* compute the size of the text to overprint*/
1152 /* Create a PangoLayout, set the font and text */
1153 current_layout = pango_cairo_create_layout (gp_cairo_enhanced_plot->cr);
1154 pango_layout_set_text (current_layout, enhanced_text_utf8, -1);
1155 current_desc = pango_font_description_new ();
1156 pango_font_description_set_family (current_desc, gp_cairo_enhanced_get_fontname());
1157 pango_font_description_set_size(current_desc,(int) gp_cairo_enhanced_fontsize*PANGO_SCALE);
1158 pango_layout_set_font_description (current_layout, current_desc);
1159 pango_font_description_free (current_desc);
1160 pango_layout_get_extents(current_layout, ¤t_ink_rect, ¤t_logical_rect);
1161 g_object_unref (current_layout);
1163 /* calculate the distance to remove to center the overprinted text */
1164 underprinted_logical_rect.width = -(underprinted_logical_rect.width + current_logical_rect.width)/2;
1165 overprinted_width = current_logical_rect.width;
1167 /* adding a blank character with the corresponding shape */
1168 gp_cairo_add_shape(underprinted_logical_rect, start);
1170 strncpy(gp_cairo_underprinted_utf8, "", sizeof(gp_cairo_underprinted_utf8));
1171 /* increment the position as we added a character */
1175 if (gp_cairo_enhanced_showflag) {
1176 strncat(gp_cairo_utf8, enhanced_text_utf8, sizeof(gp_cairo_utf8)-strlen(gp_cairo_utf8));
1177 end = strlen(gp_cairo_utf8);
1179 /* add text attributes to the main list */
1180 gp_cairo_add_attr( gp_cairo_enhanced_AttrList, start, end);
1183 /* position must be modified, but text not actually drawn */
1184 /* the idea is to use a blank character, drawn with the width of the text*/
1186 current_layout = pango_cairo_create_layout (gp_cairo_enhanced_plot->cr);
1187 pango_layout_set_text (current_layout, gp_cairo_utf8, -1);
1188 pango_layout_set_attributes (current_layout, gp_cairo_enhanced_AttrList);
1189 pango_layout_get_extents(current_layout, ¤t_ink_rect, ¤t_logical_rect);
1190 g_object_unref (current_layout);
1192 /* we first compute the size of the text */
1193 /* Create a PangoLayout, set the font and text */
1194 hide_layout = pango_cairo_create_layout (gp_cairo_enhanced_plot->cr);
1195 pango_layout_set_text (hide_layout, enhanced_text_utf8, -1);
1196 hide_desc = pango_font_description_new ();
1197 pango_font_description_set_family (hide_desc, gp_cairo_enhanced_get_fontname());
1198 pango_font_description_set_size(hide_desc,(int) gp_cairo_enhanced_fontsize*PANGO_SCALE);
1199 pango_layout_set_font_description (hide_layout, hide_desc);
1200 pango_font_description_free (hide_desc);
1202 pango_layout_get_extents(hide_layout, &hide_ink_rect, &hide_logical_rect);
1203 g_object_unref (hide_layout);
1205 /* rect.y must be reworked to take previous text into account, which may be smaller */
1206 /* hide_logical_rect.y is always initialized at zero, but should be : */
1207 if (current_logical_rect.height<hide_logical_rect.height)
1208 hide_logical_rect.y = current_logical_rect.height - hide_logical_rect.height;
1210 /* adding a blank character with the corresponding shape */
1211 gp_cairo_add_shape(hide_logical_rect, start);
1213 end = start+1; /* end *must* be defined, as it is used if widthflag is false */
1216 if (!gp_cairo_enhanced_widthflag) {
1217 /* the idea is to use a blank character, drawn with the inverted width of the text*/
1218 /* we first compute the size of the text */
1220 /* Create a PangoLayout, set the font and text */
1221 zerowidth_layout = pango_cairo_create_layout (gp_cairo_enhanced_plot->cr);
1222 pango_layout_set_text (zerowidth_layout, enhanced_text_utf8, -1);
1223 zerowidth_desc = pango_font_description_new ();
1224 pango_font_description_set_family (zerowidth_desc, gp_cairo_enhanced_get_fontname());
1225 pango_font_description_set_size(zerowidth_desc,(int) gp_cairo_enhanced_fontsize*PANGO_SCALE);
1226 pango_layout_set_font_description (zerowidth_layout, zerowidth_desc);
1227 pango_font_description_free (zerowidth_desc);
1228 pango_layout_get_extents(zerowidth_layout, NULL, &zerowidth_logical_rect);
1229 g_object_unref (zerowidth_layout);
1231 /* invert the size, so we will go back to the start of the string */
1232 zerowidth_logical_rect.width = -zerowidth_logical_rect.width;
1234 /* adding a blank character with the corresponding shape */
1235 gp_cairo_add_shape(zerowidth_logical_rect,end);
1239 if (gp_cairo_enhanced_overprint==2) {
1240 /* revert the previous negative space to go back to starting point.
1241 * Take centered overprinted text width into account */
1242 underprinted_logical_rect.width = -underprinted_logical_rect.width - overprinted_width/2;
1243 /* adding a blank character with the corresponding shape */
1244 gp_cairo_add_shape(underprinted_logical_rect,end);
1247 if (gp_cairo_enhanced_save) /* we aim at restoring position later */ {
1248 save_start = strlen( gp_cairo_save_utf8);
1249 strncat(gp_cairo_save_utf8, enhanced_text_utf8, sizeof(gp_cairo_utf8)-strlen(gp_cairo_utf8));
1250 save_end = strlen( gp_cairo_save_utf8);
1252 /* add text attributes to the save list */
1253 gp_cairo_add_attr( gp_cairo_enhanced_save_AttrList, save_start, save_end);
1256 if (gp_cairo_enhanced_overprint==1) /* save underprinted text with its attributes */{
1257 underprinted_start = strlen(gp_cairo_underprinted_utf8);
1258 strncat(gp_cairo_underprinted_utf8,
1260 sizeof(gp_cairo_underprinted_utf8)-strlen(gp_cairo_underprinted_utf8));
1261 underprinted_end = strlen(gp_cairo_underprinted_utf8);
1263 gp_cairo_enhanced_underprinted_AttrList = pango_attr_list_new();
1265 /* add text attributes to the underprinted list */
1266 gp_cairo_add_attr( gp_cairo_enhanced_underprinted_AttrList,
1267 underprinted_start, underprinted_end);
1271 if (symbol_font_parsed)
1272 strncpy(gp_cairo_enhanced_font, "Symbol", sizeof(gp_cairo_enhanced_font));
1273 #endif /* MAP_SYMBOL */
1275 g_free(enhanced_text_utf8);
1278 /* brace is TRUE to keep processing to },
1279 * FALSE to do one character only
1280 * fontname & fontsize are obvious
1281 * base is the current baseline
1282 * widthflag is TRUE if the width of this should count,
1283 * FALSE for zero width boxes
1284 * showflag is TRUE if this should be shown,
1285 * FALSE if it should not be shown (like TeX \phantom)
1286 * overprint is 0 for normal operation,
1287 * 1 for the underprinted text (included in width calculation),
1288 * 2 for the overprinted text (not included in width calc, through widhtflag=false),
1289 * (overprinted text is centered horizontally on underprinted text)
1290 * 3 means "save current position",
1291 * 4 means "restore saved position" */
1292 void gp_cairo_enhanced_open(char* fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint)
1294 if (overprint == 3) {
1295 gp_cairo_enhanced_save = TRUE;
1296 gp_cairo_enhanced_restore_now = FALSE;
1297 gp_cairo_enhanced_save_AttrList = pango_attr_list_new();
1301 if (overprint == 4) {
1302 gp_cairo_enhanced_save = FALSE;
1303 gp_cairo_enhanced_restore_now = TRUE;
1307 if (!gp_cairo_enhanced_opened_string) {
1308 gp_cairo_enhanced_opened_string = TRUE;
1309 enhanced_cur_text = &enhanced_text[0];
1310 strncpy(gp_cairo_enhanced_font, fontname, sizeof(gp_cairo_enhanced_font));
1311 gp_cairo_enhanced_fontsize = fontsize*gp_cairo_enhanced_plot->oversampling_scale;
1312 gp_cairo_enhanced_base = base*gp_cairo_enhanced_plot->oversampling_scale;
1313 gp_cairo_enhanced_showflag = showflag;
1314 gp_cairo_enhanced_overprint = overprint;
1315 gp_cairo_enhanced_widthflag = widthflag;
1321 /* gp_cairo_cairo_draw_enhanced_text() uses enhanced_recursion() to analyse the string to print.
1322 * enhanced_recursion() calls _enhanced_open() to initialize the text drawing,
1323 * then it calls _enhanced_writec() which buffers the characters to draw,
1324 * and finally _enhanced_flush() to draw the buffer with the correct justification. */
1325 void gp_cairo_draw_enhanced_text(plot_struct *plot, int x, int y, const char* string)
1327 PangoRectangle ink_rect, logical_rect;
1328 PangoLayout *layout;
1329 double vert_just, arg, enh_x, enh_y, delta, deltax, deltay;
1331 /* begin by stroking any open path */
1332 gp_cairo_stroke(plot);
1333 /* also draw any open polygon set */
1334 gp_cairo_end_polygon(plot);
1336 /* flush any pending graphics */
1337 if (!strlen(string))
1340 /* set up the global variables needed by enhanced_recursion() */
1341 enhanced_fontscale = 1.0;
1342 strncpy(enhanced_escape_format, "%c", sizeof(enhanced_escape_format));
1344 gp_cairo_enhanced_plot = plot;
1345 gp_cairo_enhanced_opened_string = FALSE;
1346 gp_cairo_enhanced_overprint = FALSE;
1347 gp_cairo_enhanced_showflag = TRUE;
1348 gp_cairo_enhanced_fontsize = plot->fontsize*plot->oversampling_scale;
1349 strncpy(gp_cairo_enhanced_font, plot->fontname, sizeof(gp_cairo_enhanced_font));
1350 gp_cairo_enhanced_AttrList = pango_attr_list_new();
1352 /* Set the recursion going. We say to keep going until a
1353 * closing brace, but we don't really expect to find one.
1354 * If the return value is not the nul-terminator of the
1355 * string, that can only mean that we did find an unmatched
1356 * closing brace in the string. We inplot->crement past it (else
1357 * we get stuck in an infinite loop) and try again. */
1359 while (*(string = enhanced_recursion((char*)string, TRUE, plot->fontname,
1360 plot->fontsize, 0.0, TRUE, TRUE, 0))) {
1361 (term->enhanced_flush)();
1363 /* we can only get here if *str == '}' */
1364 enh_err_check(string);
1367 break; /* end of string */
1368 /* else carry on and process the rest of the string */
1371 /* Create a PangoLayout, set the font and text */
1372 layout = pango_cairo_create_layout (plot->cr);
1374 pango_layout_set_text (layout, gp_cairo_utf8, -1);
1376 pango_layout_set_attributes (layout, gp_cairo_enhanced_AttrList);
1378 pango_layout_get_extents(layout, &ink_rect, &logical_rect);
1379 /* vert_just = ((double)ink_rect.height/2 +(double)ink_rect.y) / PANGO_SCALE; */
1380 vert_just = term->v_char / 2;
1382 arg = plot->text_angle * M_PI/180;
1383 enh_x = x - vert_just * sin(arg);
1384 enh_y = y - vert_just * cos(arg);
1386 delta = ((double)logical_rect.width/2) / PANGO_SCALE;
1388 deltax = delta * cos(arg);
1389 deltay = delta * sin(arg);
1391 switch (plot->justify_mode) {
1404 cairo_save(plot->cr);
1405 cairo_move_to (plot->cr, enh_x, enh_y);
1406 /* angle in radians */
1407 cairo_rotate(plot->cr, -arg);
1409 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
1410 /* Inform Pango to re-layout the text with the new transformation */
1411 pango_cairo_update_layout (plot->cr, layout);
1412 pango_cairo_show_layout (plot->cr, layout);
1414 /* free the layout object */
1415 pango_attr_list_unref( gp_cairo_enhanced_AttrList );
1416 g_object_unref (layout);
1417 cairo_restore(plot->cr);
1418 strncpy(gp_cairo_utf8, "", sizeof(gp_cairo_utf8));
1422 /* obtain the right pattern or solid fill from fillstyle and fillpar.
1423 * Used to draw fillboxes and polygons */
1424 void gp_cairo_fill(plot_struct *plot, int fillstyle, int fillpar)
1426 double red = 0, green = 0, blue = 0, fact = 0;
1428 switch (fillstyle) {
1429 case FS_SOLID: /* solid fill */
1430 if (fillpar==100) /* treated as a special case to accelerate common situation */ {
1431 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
1432 FPRINTF((stderr,"solid %lf %lf %lf\n",plot->color.r, plot->color.g, plot->color.b));
1435 red = plot->color.r;
1436 green = plot->color.g;
1437 blue = plot->color.b;
1439 fact = (double)(100 - fillpar) /100;
1441 if (fact >= 0 && fact <= 1) {
1442 red += (1 - red) * fact;
1443 green += (1 - green) * fact;
1444 blue += (1 - blue) * fact;
1446 cairo_set_source_rgb(plot->cr, red, green, blue);
1447 FPRINTF((stderr,"transparent solid %lf %lf %lf\n",red, green, blue));
1449 case FS_PATTERN: /* pattern fill */
1450 gp_cairo_fill_pattern(plot,fillpar);
1451 FPRINTF((stderr,"pattern fillpar = %d %lf %lf %lf\n",fillpar, plot->color.r, plot->color.g, plot->color.b));
1453 case FS_EMPTY: /* fill with background plot->color */
1454 cairo_set_source_rgb(plot->cr, 1, 1, 1);
1455 FPRINTF((stderr,"empty\n"));
1458 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
1459 FPRINTF((stderr,"default %lf %lf %lf\n",plot->color.r, plot->color.g, plot->color.b));
1465 #define PATTERN_SIZE 8
1467 /* return a pattern used for fillboxes and polygons */
1468 void gp_cairo_fill_pattern(plot_struct *plot, int fillpar)
1470 cairo_surface_t *pattern_surface;
1471 cairo_t *pattern_cr;
1472 cairo_pattern_t *pattern;
1473 cairo_matrix_t context_matrix;
1474 cairo_matrix_t matrix;
1476 pattern_surface = cairo_surface_create_similar(cairo_get_target(plot->cr),
1477 CAIRO_CONTENT_COLOR_ALPHA,
1480 pattern_cr = cairo_create(pattern_surface);
1482 cairo_matrix_init_scale(&context_matrix,
1485 cairo_set_matrix(pattern_cr,&context_matrix);
1487 cairo_set_source_rgb( pattern_cr, 1.0, 1.0, 1.0);
1488 cairo_paint(pattern_cr);
1489 cairo_set_line_width(pattern_cr, PATTERN_SIZE/50.);
1490 cairo_set_line_cap (pattern_cr, CAIRO_LINE_CAP_BUTT);
1491 cairo_set_source_rgb(pattern_cr, plot->color.r, plot->color.g, plot->color.b);
1493 switch (fillpar%8) {
1494 case 0: /* no fill */
1497 case 1: /* cross-hatch */
1498 case 2: /* double cross-hatch */
1499 cairo_move_to(pattern_cr, 0,0);
1500 cairo_line_to(pattern_cr, 1.0,1.0);
1501 cairo_stroke(pattern_cr);
1502 cairo_move_to(pattern_cr, 0,1.0);
1503 cairo_line_to(pattern_cr, 1.0,0);
1504 cairo_stroke(pattern_cr);
1507 cairo_paint(pattern_cr);
1509 case 4: /* diagonal hatch */
1513 cairo_move_to(pattern_cr, 0.5,0.);
1514 cairo_line_to(pattern_cr, 0.5,1.);
1515 cairo_stroke(pattern_cr);
1519 pattern = cairo_pattern_create_for_surface( pattern_surface );
1520 cairo_pattern_set_extend( pattern, CAIRO_EXTEND_REPEAT );
1522 /* compensate the transformation matrix of the main context */
1523 cairo_matrix_init_scale(&matrix,
1524 1.0/plot->oversampling_scale,
1525 1.0/plot->oversampling_scale);
1527 switch (fillpar%8) {
1528 case 0: /* no fill */
1529 case 1: /* cross-hatch */
1533 case 2: /* double cross-hatch */
1534 cairo_matrix_scale( &matrix, 2.,2.);
1536 case 4: /* diagonal hatch */
1537 cairo_matrix_rotate( &matrix, M_PI/4);
1540 cairo_matrix_rotate( &matrix, -M_PI/4);
1543 cairo_matrix_rotate( &matrix, M_PI/4);
1544 cairo_matrix_scale( &matrix, 2.,2.);
1547 cairo_matrix_rotate( &matrix, -M_PI/4);
1548 cairo_matrix_scale( &matrix, 2.,2.);
1552 cairo_pattern_set_matrix(pattern,&matrix);
1554 cairo_destroy( pattern_cr );
1555 cairo_set_source( plot->cr, pattern );
1556 cairo_pattern_destroy( pattern );
1557 cairo_surface_destroy( pattern_surface );
1561 /* Sets term vars v_char, h_char, v_tic, h_tic
1562 * Depends on plot->fontsize and fontname */
1563 void gp_cairo_set_termvar(plot_struct *plot)
1565 PangoLayout *layout;
1566 PangoFontDescription *desc;
1567 PangoRectangle ink_rect;
1568 PangoRectangle logical_rect;
1570 /* Create a PangoLayout, set the font and text */
1571 layout = pango_cairo_create_layout (plot->cr);
1572 pango_layout_set_text (layout, "0123456789", -1);
1573 desc = pango_font_description_new ();
1574 pango_font_description_set_family (desc, plot->fontname);
1575 pango_font_description_set_size(desc,(int) (plot->fontsize*PANGO_SCALE*plot->oversampling_scale));
1576 pango_layout_set_font_description (layout, desc);
1577 pango_font_description_free (desc);
1578 pango_layout_get_extents(layout, &ink_rect, &logical_rect);
1579 g_object_unref (layout);
1581 /* we don't use gnuplot_x() and gnuplot_y() in the following
1582 * as the scale should have just been updated to 1.
1583 * Although PANGO works with integer, it scales them via a huge number (usually ~1000).
1584 * That's why I use ceil() instead of direct division result */
1585 term->v_char = (int) ceil( (double) logical_rect.height/PANGO_SCALE) - 1;
1586 term->h_char = (int) ceil( (double) logical_rect.width/(10*PANGO_SCALE));
1587 term->v_tic = term->v_char/2.5;
1588 term->h_tic = term->v_char/2.5;
1591 void gp_cairo_clear(plot_struct *plot)
1593 if (cairo_status (plot->cr)) {
1594 printf("Cairo is unhappy: %s\n",
1595 cairo_status_to_string (cairo_status (plot->cr)));
1598 cairo_set_source_rgb(plot->cr, 1.0, 1.0, 1.0);
1599 cairo_paint(plot->cr);
1602 /*----------------------------------------------------------------------------
1604 ----------------------------------------------------------------------------*/
1607 /* in enhanced text mode, look if enhanced mode has set the font,
1608 * otherwise return the default */
1609 const char* gp_cairo_enhanced_get_fontname()
1611 if ( strlen(gp_cairo_enhanced_font)==0 )
1612 return gp_cairo_enhanced_plot->fontname;
1614 return gp_cairo_enhanced_font;
1617 /*----------------------------------------------------------------------------
1618 coordinates functions
1619 ----------------------------------------------------------------------------*/
1623 double device_x(plot_struct *plot, double x)
1626 scaled_x = plot->xscale*x/plot->oversampling_scale ;
1627 return scaled_x + OFFSET;
1630 double device_y(plot_struct *plot, double y)
1632 double scaled_and_mirrored_y;
1633 scaled_and_mirrored_y = (plot->ymax - y)*plot->yscale/plot->oversampling_scale;
1634 return scaled_and_mirrored_y + OFFSET;
1637 double gnuplot_x(plot_struct *plot, double x)
1640 scaled_x = (x + OFFSET)/plot->xscale*plot->oversampling_scale ;
1644 double gnuplot_y(plot_struct *plot, double y)
1646 double scaled_and_mirrored_y;
1647 scaled_and_mirrored_y = plot->ymax +(-y + OFFSET)/plot->yscale*plot->oversampling_scale;
1648 return scaled_and_mirrored_y;
1652 /* return the charset as a string accepted by glib routines,
1653 * default to the locale charset,
1654 * the returned char* doesn't have to be freed. */
1655 const char* gp_cairo_get_encoding(plot_struct *plot)
1657 const char * charset;
1659 switch (plot->encoding) {
1660 case S_ENC_ISO8859_2 : return "ISO-8859-2";
1661 case S_ENC_ISO8859_15 : return "ISO-8859-15";
1662 case S_ENC_CP437 : return "cp437";
1663 case S_ENC_CP850 : return "cp850";
1664 case S_ENC_CP852 : return "cp852";
1665 case S_ENC_CP1250 : return "windows-1250";
1666 case S_ENC_KOI8_R : return "KOI8-R";
1667 case S_ENC_KOI8_U : return "KOI8-U";
1668 case S_ENC_ISO8859_1 : return "ISO-8859-1";
1669 case S_ENC_DEFAULT :
1670 case S_ENC_INVALID :
1672 g_get_charset(&charset);
1677 /* Symbol font handling.
1678 * To ensure compatibility with other terminals,
1679 * use the map provided by http://www.unicode.org/ to
1680 * translate character codes to their unicode counterparts.
1681 * The returned string has te be freed by the calling function. */
1682 gchar* gp_cairo_convert_symbol_to_unicode(plot_struct *plot, const char* string)
1690 GError *error = NULL;
1692 /* first step, get a valid utf8 string, without taking care of Symbol.
1693 * The input string is likely to be encoded in iso_8859_1, with characters
1694 * going from 1 to 255. Try this first. If it's not the case, fall back to
1695 * routine based on the encoding variable. */
1696 string_utf8 = g_convert(string, -1, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
1697 if (error != NULL) {
1698 fprintf(stderr,"Symbol font : fallback to iso_8859_1 did not work\n");
1699 g_error_free(error);
1700 string_utf8 = gp_cairo_convert(plot, string);
1704 /* Assume that the output string in utf8 won't use more than 8 bytes per character/
1705 * The utf8 specification fixes the limit to 4 bytes per character, but here we can also
1706 * composite two characters */
1707 output = (gchar*) gp_alloc((4*strlen(string)+1)*sizeof(gchar),"Symbol to unicode");
1709 imax = g_utf8_strlen(string_utf8,-1) + 1;
1711 for (i=0; i<imax; ++i) {
1712 switch(g_utf8_get_char(iter)) {
1713 #define SYMB_UNICODE(symbol_char,unicode) case symbol_char : g_unichar_to_utf8(unicode, iter_mod); break;
1714 /* not modifying ASCII characters */
1715 /* SYMB_UNICODE(0x20,0x0020); */ /* SPACE */
1716 /* SYMB_UNICODE(0x21,0x0021); */ /* EXCLAMATION MARK */
1717 SYMB_UNICODE(0x22,0x2200); /* FOR ALL */
1718 /* SYMB_UNICODE(0x23,0x0023); */ /* NUMBER SIGN */
1719 SYMB_UNICODE(0x24,0x2203); /* THERE EXISTS */
1720 /* SYMB_UNICODE(0x25,0x0025); */ /* PERCENT SIGN */
1721 /* SYMB_UNICODE(0x26,0x0026); */ /* AMPERSAND */
1722 SYMB_UNICODE(0x27,0x220D); /* SMALL CONTAINS AS MEMBER */
1723 /* SYMB_UNICODE(0x28,0x0028); */ /* LEFT PARENTHESIS */
1724 /* SYMB_UNICODE(0x29,0x0029); */ /* RIGHT PARENTHESIS */
1725 /* SYMB_UNICODE(0x2A,0x2217); */ /* ASTERISK OPERATOR */
1726 /* SYMB_UNICODE(0x2B,0x002B); */ /* PLUS SIGN */
1727 /* SYMB_UNICODE(0x2C,0x002C); */ /* COMMA */
1728 /* SYMB_UNICODE(0x2D,0x2212); */ /* MINUS SIGN */
1729 /* SYMB_UNICODE(0x2E,0x002E); */ /* FULL STOP */
1730 /* SYMB_UNICODE(0x2F,0x002F); */ /* SOLIDUS */
1731 /* SYMB_UNICODE(0x30,0x0030); */ /* DIGIT ZERO */
1732 /* SYMB_UNICODE(0x31,0x0031); */ /* DIGIT ONE */
1733 /* SYMB_UNICODE(0x32,0x0032); */ /* DIGIT TWO */
1734 /* SYMB_UNICODE(0x33,0x0033); */ /* DIGIT THREE */
1735 /* SYMB_UNICODE(0x34,0x0034); */ /* DIGIT FOUR */
1736 /* SYMB_UNICODE(0x35,0x0035); */ /* DIGIT FIVE */
1737 /* SYMB_UNICODE(0x36,0x0036); */ /* DIGIT SIX */
1738 /* SYMB_UNICODE(0x37,0x0037); */ /* DIGIT SEVEN */
1739 /* SYMB_UNICODE(0x38,0x0038); */ /* DIGIT EIGHT */
1740 /* SYMB_UNICODE(0x39,0x0039); */ /* DIGIT NINE */
1741 /* SYMB_UNICODE(0x3A,0x003A); */ /* COLON */
1742 /* SYMB_UNICODE(0x3B,0x003B); */ /* SEMICOLON */
1743 /* SYMB_UNICODE(0x3C,0x003C); */ /* LESS-THAN SIGN */
1744 /* SYMB_UNICODE(0x3D,0x003D); */ /* EQUALS SIGN */
1745 /* SYMB_UNICODE(0x3E,0x003E); */ /* GREATER-THAN SIGN */
1746 /* SYMB_UNICODE(0x3F,0x003F); */ /* QUESTION MARK */
1747 SYMB_UNICODE(0x40,0x2245); /* APPROXIMATELY EQUAL TO */
1748 SYMB_UNICODE(0x41,0x0391); /* GREEK CAPITAL LETTER ALPHA */
1749 SYMB_UNICODE(0x42,0x0392); /* GREEK CAPITAL LETTER BETA */
1750 SYMB_UNICODE(0x43,0x03A7); /* GREEK CAPITAL LETTER CHI */
1751 SYMB_UNICODE(0x44,0x0394); /* GREEK CAPITAL LETTER DELTA */
1752 SYMB_UNICODE(0x45,0x0395); /* GREEK CAPITAL LETTER EPSILON */
1753 SYMB_UNICODE(0x46,0x03A6); /* GREEK CAPITAL LETTER PHI */
1754 SYMB_UNICODE(0x47,0x0393); /* GREEK CAPITAL LETTER GAMMA */
1755 SYMB_UNICODE(0x48,0x0397); /* GREEK CAPITAL LETTER ETA */
1756 SYMB_UNICODE(0x49,0x0399); /* GREEK CAPITAL LETTER IOTA */
1757 SYMB_UNICODE(0x4A,0x03D1); /* GREEK THETA SYMBOL */
1758 SYMB_UNICODE(0x4B,0x039A); /* GREEK CAPITAL LETTER KAPPA */
1759 SYMB_UNICODE(0x4C,0x039B); /* GREEK CAPITAL LETTER LAMDA */
1760 SYMB_UNICODE(0x4D,0x039C); /* GREEK CAPITAL LETTER MU */
1761 SYMB_UNICODE(0x4E,0x039D); /* GREEK CAPITAL LETTER NU */
1762 SYMB_UNICODE(0x4F,0x039F); /* GREEK CAPITAL LETTER OMICRON */
1763 SYMB_UNICODE(0x50,0x03A0); /* GREEK CAPITAL LETTER PI */
1764 SYMB_UNICODE(0x51,0x0398); /* GREEK CAPITAL LETTER THETA */
1765 SYMB_UNICODE(0x52,0x03A1); /* GREEK CAPITAL LETTER RHO */
1766 SYMB_UNICODE(0x53,0x03A3); /* GREEK CAPITAL LETTER SIGMA */
1767 SYMB_UNICODE(0x54,0x03A4); /* GREEK CAPITAL LETTER TAU */
1768 SYMB_UNICODE(0x55,0x03A5); /* GREEK CAPITAL LETTER UPSILON */
1769 SYMB_UNICODE(0x56,0x03C2); /* GREEK SMALL LETTER FINAL SIGMA */
1770 SYMB_UNICODE(0x57,0x03A9); /* GREEK CAPITAL LETTER OMEGA */
1771 SYMB_UNICODE(0x58,0x039E); /* GREEK CAPITAL LETTER XI */
1772 SYMB_UNICODE(0x59,0x03A8); /* GREEK CAPITAL LETTER PSI */
1773 SYMB_UNICODE(0x5A,0x0396); /* GREEK CAPITAL LETTER ZETA */
1774 SYMB_UNICODE(0x5B,0x005B); /* LEFT SQUARE BRACKET */
1775 SYMB_UNICODE(0x5C,0x2234); /* THEREFORE */
1776 SYMB_UNICODE(0x5D,0x005D); /* RIGHT SQUARE BRACKET */
1777 SYMB_UNICODE(0x5E,0x22A5); /* UP TACK */
1778 SYMB_UNICODE(0x5F,0x005F); /* LOW LINE */
1779 SYMB_UNICODE(0x60,0xF8E5); /* radical extender corporate char */
1780 SYMB_UNICODE(0x61,0x03B1); /* GREEK SMALL LETTER ALPHA */
1781 SYMB_UNICODE(0x62,0x03B2); /* GREEK SMALL LETTER BETA */
1782 SYMB_UNICODE(0x63,0x03C7); /* GREEK SMALL LETTER CHI */
1783 SYMB_UNICODE(0x64,0x03B4); /* GREEK SMALL LETTER DELTA */
1784 SYMB_UNICODE(0x65,0x03B5); /* GREEK SMALL LETTER EPSILON */
1785 SYMB_UNICODE(0x66,0x03C6); /* GREEK SMALL LETTER PHI */
1786 SYMB_UNICODE(0x67,0x03B3); /* GREEK SMALL LETTER GAMMA */
1787 SYMB_UNICODE(0x68,0x03B7); /* GREEK SMALL LETTER ETA */
1788 SYMB_UNICODE(0x69,0x03B9); /* GREEK SMALL LETTER IOTA */
1789 SYMB_UNICODE(0x6A,0x03D5); /* GREEK PHI SYMBOL */
1790 SYMB_UNICODE(0x6B,0x03BA); /* GREEK SMALL LETTER KAPPA */
1791 SYMB_UNICODE(0x6C,0x03BB); /* GREEK SMALL LETTER LAMDA */
1792 /* SYMB_UNICODE(0x6D,0x03BC); */ /* GREEK SMALL LETTER MU */
1793 SYMB_UNICODE(0x6D,0x00B5); /* GREEK SMALL LETTER MU */
1794 SYMB_UNICODE(0x6E,0x03BD); /* GREEK SMALL LETTER NU */
1795 SYMB_UNICODE(0x6F,0x03BF); /* GREEK SMALL LETTER OMICRON */
1796 SYMB_UNICODE(0x70,0x03C0); /* GREEK SMALL LETTER PI */
1797 SYMB_UNICODE(0x71,0x03B8); /* GREEK SMALL LETTER THETA */
1798 SYMB_UNICODE(0x72,0x03C1); /* GREEK SMALL LETTER RHO */
1799 SYMB_UNICODE(0x73,0x03C3); /* GREEK SMALL LETTER SIGMA */
1800 SYMB_UNICODE(0x74,0x03C4); /* GREEK SMALL LETTER TAU */
1801 SYMB_UNICODE(0x75,0x03C5); /* GREEK SMALL LETTER UPSILON */
1802 SYMB_UNICODE(0x76,0x03D6); /* GREEK PI SYMBOL */
1803 SYMB_UNICODE(0x77,0x03C9); /* GREEK SMALL LETTER OMEGA */
1804 SYMB_UNICODE(0x78,0x03BE); /* GREEK SMALL LETTER XI */
1805 SYMB_UNICODE(0x79,0x03C8); /* GREEK SMALL LETTER PSI */
1806 SYMB_UNICODE(0x7A,0x03B6); /* GREEK SMALL LETTER ZETA */
1807 SYMB_UNICODE(0x7B,0x007B); /* LEFT CURLY BRACKET */
1808 SYMB_UNICODE(0x7C,0x007C); /* VERTICAL LINE */
1809 SYMB_UNICODE(0x7D,0x007D); /* RIGHT CURLY BRACKET */
1810 SYMB_UNICODE(0x7E,0x223C); /* TILDE OPERATOR */
1812 SYMB_UNICODE(0xA0,0x20AC); /* EURO SIGN */
1813 SYMB_UNICODE(0xA1,0x03D2); /* GREEK UPSILON WITH HOOK SYMBOL */
1814 SYMB_UNICODE(0xA2,0x2032); /* PRIME minute */
1815 SYMB_UNICODE(0xA3,0x2264); /* LESS-THAN OR EQUAL TO */
1816 SYMB_UNICODE(0xA4,0x2044); /* FRACTION SLASH */
1817 SYMB_UNICODE(0xA5,0x221E); /* INFINITY */
1818 SYMB_UNICODE(0xA6,0x0192); /* LATIN SMALL LETTER F WITH HOOK */
1819 SYMB_UNICODE(0xA7,0x2663); /* BLACK CLUB SUIT */
1820 SYMB_UNICODE(0xA8,0x2666); /* BLACK DIAMOND SUIT */
1821 SYMB_UNICODE(0xA9,0x2665); /* BLACK HEART SUIT */
1822 SYMB_UNICODE(0xAA,0x2660); /* BLACK SPADE SUIT */
1823 SYMB_UNICODE(0xAB,0x2194); /* LEFT RIGHT ARROW */
1824 SYMB_UNICODE(0xAC,0x2190); /* LEFTWARDS ARROW */
1825 SYMB_UNICODE(0xAD,0x2191); /* UPWARDS ARROW */
1826 SYMB_UNICODE(0xAE,0x2192); /* RIGHTWARDS ARROW */
1827 SYMB_UNICODE(0xAF,0x2193); /* DOWNWARDS ARROW */
1828 SYMB_UNICODE(0xB0,0x00B0); /* DEGREE SIGN */
1829 SYMB_UNICODE(0xB1,0x00B1); /* PLUS-MINUS SIGN */
1830 SYMB_UNICODE(0xB2,0x2033); /* DOUBLE PRIME second */
1831 SYMB_UNICODE(0xB3,0x2265); /* GREATER-THAN OR EQUAL TO */
1832 SYMB_UNICODE(0xB4,0x00D7); /* MULTIPLICATION SIGN */
1833 SYMB_UNICODE(0xB5,0x221D); /* PROPORTIONAL TO */
1834 SYMB_UNICODE(0xB6,0x2202); /* PARTIAL DIFFERENTIAL */
1835 SYMB_UNICODE(0xB7,0x2022); /* BULLET */
1836 SYMB_UNICODE(0xB8,0x00F7); /* DIVISION SIGN */
1837 SYMB_UNICODE(0xB9,0x2260); /* NOT EQUAL TO */
1838 SYMB_UNICODE(0xBA,0x2261); /* IDENTICAL TO */
1839 SYMB_UNICODE(0xBB,0x2248); /* ALMOST EQUAL TO */
1840 SYMB_UNICODE(0xBC,0x2026); /* HORIZONTAL ELLIPSIS */
1841 SYMB_UNICODE(0xBD,0x23D0); /* VERTICAL LINE EXTENSION (for arrows) */
1842 SYMB_UNICODE(0xBE,0x23AF); /* HORIZONTAL LINE EXTENSION (for arrows) */
1843 SYMB_UNICODE(0xBF,0x21B5); /* DOWNWARDS ARROW WITH CORNER LEFTWARDS */
1844 SYMB_UNICODE(0xC0,0x2135); /* ALEF SYMBOL */
1845 SYMB_UNICODE(0xC1,0x2111); /* BLACK-LETTER CAPITAL I */
1846 SYMB_UNICODE(0xC2,0x211C); /* BLACK-LETTER CAPITAL R */
1847 SYMB_UNICODE(0xC3,0x2118); /* SCRIPT CAPITAL P */
1848 SYMB_UNICODE(0xC4,0x2297); /* CIRCLED TIMES */
1849 SYMB_UNICODE(0xC5,0x2295); /* CIRCLED PLUS */
1850 SYMB_UNICODE(0xC6,0x2205); /* EMPTY SET */
1851 SYMB_UNICODE(0xC7,0x2229); /* INTERSECTION */
1852 SYMB_UNICODE(0xC8,0x222A); /* UNION */
1853 SYMB_UNICODE(0xC9,0x2283); /* SUPERSET OF */
1854 SYMB_UNICODE(0xCA,0x2287); /* SUPERSET OF OR EQUAL TO */
1855 SYMB_UNICODE(0xCB,0x2284); /* NOT A SUBSET OF */
1856 SYMB_UNICODE(0xCC,0x2282); /* SUBSET OF */
1857 SYMB_UNICODE(0xCD,0x2286); /* SUBSET OF OR EQUAL TO */
1858 SYMB_UNICODE(0xCE,0x2208); /* ELEMENT OF */
1859 SYMB_UNICODE(0xCF,0x2209); /* NOT AN ELEMENT OF */
1860 SYMB_UNICODE(0xD0,0x2220); /* ANGLE */
1861 SYMB_UNICODE(0xD1,0x2207); /* NABLA */
1862 SYMB_UNICODE(0xD2,0x00AE); /* REGISTERED SIGN serif */
1863 SYMB_UNICODE(0xD3,0x00A9); /* COPYRIGHT SIGN serif */
1864 SYMB_UNICODE(0xD4,0x2122); /* TRADE MARK SIGN serif */
1865 SYMB_UNICODE(0xD5,0x220F); /* N-ARY PRODUCT */
1866 SYMB_UNICODE(0xD6,0x221A); /* SQUARE ROOT */
1867 SYMB_UNICODE(0xD7,0x22C5); /* DOT OPERATOR */
1868 SYMB_UNICODE(0xD8,0x00AC); /* NOT SIGN */
1869 SYMB_UNICODE(0xD9,0x2227); /* LOGICAL AND */
1870 SYMB_UNICODE(0xDA,0x2228); /* LOGICAL OR */
1871 SYMB_UNICODE(0xDB,0x21D4); /* LEFT RIGHT DOUBLE ARROW */
1872 SYMB_UNICODE(0xDC,0x21D0); /* LEFTWARDS DOUBLE ARROW */
1873 SYMB_UNICODE(0xDD,0x21D1); /* UPWARDS DOUBLE ARROW */
1874 SYMB_UNICODE(0xDE,0x21D2); /* RIGHTWARDS DOUBLE ARROW */
1875 SYMB_UNICODE(0xDF,0x21D3); /* DOWNWARDS DOUBLE ARROW */
1876 SYMB_UNICODE(0xE0,0x25CA); /* LOZENGE previously mapped to 0x22C4 DIAMOND OPERATOR */
1877 SYMB_UNICODE(0xE1,0x3008); /* LEFT ANGLE BRACKET */
1878 SYMB_UNICODE(0xE5,0x2211); /* N-ARY SUMMATION */
1879 SYMB_UNICODE(0xE6,0x239B); /* LEFT PARENTHESIS UPPER HOOK */
1880 SYMB_UNICODE(0xE7,0x239C); /* LEFT PARENTHESIS EXTENSION */
1881 SYMB_UNICODE(0xE8,0x239D); /* LEFT PARENTHESIS LOWER HOOK */
1882 SYMB_UNICODE(0xE9,0x23A1); /* LEFT SQUARE BRACKET UPPER CORNER */
1883 SYMB_UNICODE(0xEA,0x23A2); /* LEFT SQUARE BRACKET EXTENSION */
1884 SYMB_UNICODE(0xEB,0x23A3); /* LEFT SQUARE BRACKET LOWER CORNER */
1885 SYMB_UNICODE(0xEC,0x23A7); /* LEFT CURLY BRACKET UPPER HOOK */
1886 SYMB_UNICODE(0xED,0x23A8); /* LEFT CURLY BRACKET MIDDLE PIECE */
1887 SYMB_UNICODE(0xEE,0x23A9); /* LEFT CURLY BRACKET LOWER HOOK */
1888 SYMB_UNICODE(0xEF,0x23AA); /* CURLY BRACKET EXTENSION */
1889 SYMB_UNICODE(0xF0,0xF8FF); /* Apple logo */
1890 SYMB_UNICODE(0xF1,0x3009); /* RIGHT ANGLE BRACKET */
1891 SYMB_UNICODE(0xF2,0x222B); /* INTEGRAL */
1892 SYMB_UNICODE(0xF3,0x2320); /* TOP HALF INTEGRAL */
1893 SYMB_UNICODE(0xF4,0x23AE); /* INTEGRAL EXTENSION */
1894 SYMB_UNICODE(0xF5,0x2321); /* BOTTOM HALF INTEGRAL */
1895 SYMB_UNICODE(0xF6,0x239E); /* RIGHT PARENTHESIS UPPER HOOK */
1896 SYMB_UNICODE(0xF7,0x239F); /* RIGHT PARENTHESIS EXTENSION */
1897 SYMB_UNICODE(0xF8,0x23A0); /* RIGHT PARENTHESIS LOWER HOOK */
1898 SYMB_UNICODE(0xF9,0x23A4); /* RIGHT SQUARE BRACKET UPPER CORNER */
1899 SYMB_UNICODE(0xFA,0x23A5); /* RIGHT SQUARE BRACKET EXTENSION */
1900 SYMB_UNICODE(0xFB,0x23A6); /* RIGHT SQUARE BRACKET LOWER CORNER */
1901 SYMB_UNICODE(0xFC,0x23AB); /* RIGHT CURLY BRACKET UPPER HOOK */
1902 SYMB_UNICODE(0xFD,0x23AC); /* RIGHT CURLY BRACKET MIDDLE PIECE */
1903 SYMB_UNICODE(0xFE,0x23AD); /* RIGHT CURLY BRACKET LOWER HOOK */
1905 /* to be treated specifically : composed characters */
1906 case 0xE2 : /* REGISTERED SIGN, alternate: sans serif */
1907 g_unichar_to_utf8(0x00AE,iter_mod);
1908 iter_mod = g_utf8_next_char(iter_mod);
1909 g_unichar_to_utf8(0xF87F,iter_mod);
1911 case 0xE3 : /* COPYRIGHT SIGN, alternate: sans serif */
1912 g_unichar_to_utf8(0x00A9,iter_mod);
1913 iter_mod = g_utf8_next_char(iter_mod);
1914 g_unichar_to_utf8(0xF87F,iter_mod);
1916 case 0xE4 : /* TRADE MARK SIGN, alternate: sans serif */
1917 g_unichar_to_utf8(0x2122,iter_mod);
1918 iter_mod = g_utf8_next_char(iter_mod);
1919 g_unichar_to_utf8(0xF87F,iter_mod);
1921 default : g_unichar_to_utf8( g_utf8_get_char(iter), iter_mod); break;
1923 iter = g_utf8_next_char(iter);
1924 iter_mod = g_utf8_next_char(iter_mod);
1927 g_free(string_utf8);