1 /* GNUPLOT - gp_cairo.c */
2
3 /*[
4 * Copyright 2005,2006 Timothee Lecomte
5 *
6 * Permission to use, copy, and distribute this software and its
7 * documentation for any purpose with or without fee is hereby granted,
8 * provided that the above copyright notice appear in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation.
11 *
12 * Permission to modify the software is granted, but not the right to
13 * distribute the complete modified source code. Modifications are to
14 * be distributed as patches to the released version. Permission to
15 * distribute binaries produced by compiling modified sources is granted,
16 * provided you
17 * 1. distribute the corresponding source modifications from the
18 * released version in the form of a patch file along with the binaries,
19 * 2. add special version identification to distinguish your version
20 * in addition to the base release version number,
21 * 3. provide your name and address as the primary contact for the
22 * support of your modified version, and
23 * 4. retain our contact information in regard to use of the base
24 * software.
25 * Permission to distribute the released version of the source code along
26 * with corresponding source modifications in the form of a patch file is
27 * granted with same provisions 2 through 4 for binary distributions.
28 *
29 * This software is provided "as is" without express or implied warranty
30 * to the extent permitted by applicable law.
31 *
32 *
33 * Alternatively, the contents of this file may be used under the terms of the
34 * GNU General Public License Version 2 or later (the "GPL"), in which case the
35 * provisions of GPL are applicable instead of those above. If you wish to allow
36 * use of your version of this file only under the terms of the GPL and not
37 * to allow others to use your version of this file under the above gnuplot
38 * license, indicate your decision by deleting the provisions above and replace
39 * them with the notice and other provisions required by the GPL. If you do not
40 * delete the provisions above, a recipient may use your version of this file
41 * under either the GPL or the gnuplot license.
42 ]*/
43
44 /* -----------------------------------------------------
45 * This code uses the cairo library, a 2D graphics library with
46 * support for multiple output devices.
47 * Cairo is distributed under the LGPL licence.
48 *
49 * See http://www.cairographics.org for details.
50
51 * It also uses the pango library, a text-layout rendering library.
52 * Pango is distributed under the LGPL licence.
53 *
54 * See http://www.pango.org for details.
55 * -----------------------------------------------------*/
56
57 /* ------------------------------------------------------
58 * This file implements all cairo related functions,
59 * which provide drawing facilities.
60 *
61 * In particular, we have here :
62 * - all the basic calls (lines, polygons for pm3d, custom patterns),
63 * - image support,
64 * - enhanced text mode
65 *
66 * The text rendering is done via pango.
67 * ------------------------------------------------------*/
68
69 #include "gp_cairo.h"
70
71 #include "alloc.h"
72
73 #include <pango/pangocairo.h>
74 #include <glib.h>
75
76 #ifdef _MSC_VER
77 #define rint(x) floor((x)+0.5L)
78 #endif
79
80 /* undef this to see what happens without the Symbol-to-unicode processing */
81 #define MAP_SYMBOL
82
83 /* ======== enhanced text mode ======== */
84 /* copies of internal variables */
85 static char gp_cairo_enhanced_font[100] = "";
86 static const char* gp_cairo_enhanced_get_fontname(plot_struct *plot);
87 static double gp_cairo_enhanced_fontsize = 0;
88 static double gp_cairo_enhanced_base = 0;
89 static TBOOLEAN gp_cairo_enhanced_widthflag = TRUE;
90 static TBOOLEAN gp_cairo_enhanced_showflag = TRUE;
91 static int gp_cairo_enhanced_overprint = FALSE;
92 static TBOOLEAN gp_cairo_enhanced_opened_string = FALSE; /* try to cut out empty ()'s */
93 static char *gp_cairo_enhanced_string;
94 static char *gp_cairo_enhanced_char;
95 /* utf8 text to draw and its attributes */
96 static gchar gp_cairo_utf8[2048] = "";
97 static PangoAttrList *gp_cairo_enhanced_AttrList = NULL;
98 /* save/restore facilitiy */
99 static TBOOLEAN gp_cairo_enhanced_restore_now = FALSE;
100 static TBOOLEAN gp_cairo_enhanced_save = FALSE;
101 static gchar gp_cairo_save_utf8[2048] = "";
102 static PangoAttrList *gp_cairo_enhanced_save_AttrList = NULL;
103 /* underprint/overprint facility */
104 static gchar gp_cairo_underprinted_utf8[2048] = "";
105 static PangoAttrList *gp_cairo_enhanced_underprinted_AttrList = NULL;
106 /* converts text from symbol encoding to utf8 encoding */
107 static gchar* gp_cairo_convert_symbol_to_unicode(plot_struct *plot, const char* string);
108 /* add standard attributes (fontsize,fontfamily, rise) to
109 * the specified characters in a PangoAttrList */
110 static void gp_cairo_add_attr(plot_struct *plot, PangoAttrList * AttrList, int start, int end );
111 /* add a blank character to the text string and an associated custom shape to the attribute list */
112 static void gp_cairo_add_shape( PangoRectangle rect,int position);
113
114 /* Average character height as reported back through term->v_char */
115 static int avg_vchar = 150;
116
117 /* set a cairo pattern or solid fill depending on parameters */
118 static void gp_cairo_fill(plot_struct *plot, int fillstyle, int fillpar);
119 static void gp_cairo_fill_pattern(plot_struct *plot, int fillstyle, int fillpar);
120
121 #ifdef EAM_BOXED_TEXT
122 /* Boxed text support */
123 static int bounding_box[4];
124 static double bounding_xmargin = 1.0;
125 static double bounding_ymargin = 1.0;
126 static double box_rotation = 0.0;
127 static double box_origin_x;
128 static double box_origin_y;
129 static TBOOLEAN in_textbox = FALSE;
130 #endif
131
132 /* array of colors
133 * FIXME could be shared with all gnuplot terminals */
134 static rgb_color gp_cairo_colorlist[12] = {
135 {1,1,1}, /* white */
136 {0,0,0}, /* black */
137 {0,0,0}, /* black */
138 {1,0,0}, /* red */
139 {0,1,0}, /* green */
140 {0,0,1}, /* blue */
141 {1,0,1}, /* magenta */
142 {0,1,1}, /* cyan */
143 {1,1,0}, /* yellow */
144 {0,0,0}, /* black */
145 {1,0.3,0}, /* orange */
146 {0.5,0.5,0.5} /* grey */
147 };
148
149 /* correspondance between gnuplot linetypes and terminal colors */
gp_cairo_set_background(rgb_color background)150 void gp_cairo_set_background( rgb_color background )
151 {
152 gp_cairo_colorlist[0] = background;
153 }
154
gp_cairo_linetype2color(int linetype)155 rgb_color gp_cairo_linetype2color( int linetype )
156 {
157 if (linetype<=LT_NODRAW)
158 return gp_cairo_colorlist[ 0 ];
159 else
160 return gp_cairo_colorlist[ linetype%9 +3 ];
161 }
162
163 /* initialize all fields of the plot structure */
gp_cairo_initialize_plot(plot_struct * plot)164 void gp_cairo_initialize_plot(plot_struct *plot)
165 {
166 plot->xscale = 1.0; plot->yscale = 1.0;
167 plot->device_xmax = 1; plot->device_ymax = 1;
168 plot->xmax = 1; plot->ymax = 1;
169
170 plot->justify_mode = LEFT;
171 plot->linetype = 1;
172 plot->linewidth = 1.0;
173 plot->linestyle = GP_CAIRO_SOLID;
174 plot->pointsize = 1.0;
175 plot->dashlength = 1.0;
176 plot->text_angle = 0.0;
177 plot->color.r = 0.0; plot->color.g = 0.0; plot->color.b = 0.0;
178 plot->background.r = 1.0; plot->background.g = 1.0; plot->background.b = 1.0;
179
180 plot->opened_path = FALSE;
181
182 plot->current_x = -1; plot->current_y = -1;
183
184 strncpy(plot->fontname, "", sizeof(plot->fontname));
185 plot->fontsize = 1.0;
186 plot->encoding = S_ENC_DEFAULT;
187
188 plot->success = FALSE;
189
190 plot->antialiasing = TRUE;
191
192 plot->oversampling = TRUE;
193 plot->oversampling_scale = GP_CAIRO_SCALE;
194
195 plot->linecap = BUTT;
196
197 plot->hinting = 100;
198
199 plot->polygons_saturate = TRUE;
200
201 plot->cr = NULL;
202
203 plot->polygon_path_last = NULL;
204
205 plot->interrupt = FALSE;
206
207 #ifdef EAM_BOXED_TEXT
208 in_textbox = FALSE;
209 #endif
210 }
211
212 /* set the transformation matrix of the context, and other details */
213 /* NOTE : depends on the setting of xscale and yscale */
gp_cairo_initialize_context(plot_struct * plot)214 void gp_cairo_initialize_context(plot_struct *plot)
215 {
216 cairo_matrix_t matrix;
217
218 if (plot->oversampling)
219 plot->oversampling_scale = GP_CAIRO_SCALE;
220 else
221 plot->oversampling_scale = 1;
222
223 if (plot->antialiasing)
224 cairo_set_antialias(plot->cr,CAIRO_ANTIALIAS_DEFAULT);
225 else
226 cairo_set_antialias(plot->cr,CAIRO_ANTIALIAS_NONE);
227
228 cairo_matrix_init(&matrix,
229 plot->xscale/plot->oversampling_scale,
230 0, 0,
231 plot->yscale/plot->oversampling_scale,
232 0.5, 0.5);
233 cairo_set_matrix(plot->cr, &matrix);
234
235 /* Default is square caps, mitered joins */
236 if (plot->linecap == ROUNDED) {
237 cairo_set_line_cap (plot->cr, CAIRO_LINE_CAP_ROUND);
238 cairo_set_line_join (plot->cr, CAIRO_LINE_JOIN_ROUND);
239 } else if (plot->linecap == SQUARE) {
240 cairo_set_line_cap (plot->cr, CAIRO_LINE_CAP_SQUARE);
241 cairo_set_line_join (plot->cr, CAIRO_LINE_JOIN_MITER);
242 cairo_set_miter_limit(plot->cr, 3.8);
243 } else {
244 cairo_set_line_cap (plot->cr, CAIRO_LINE_CAP_BUTT);
245 cairo_set_line_join (plot->cr, CAIRO_LINE_JOIN_MITER);
246 cairo_set_miter_limit(plot->cr, 3.8);
247 }
248
249 }
250
251
gp_cairo_set_color(plot_struct * plot,rgb_color color,double alpha)252 void gp_cairo_set_color(plot_struct *plot, rgb_color color, double alpha)
253 {
254 /*stroke any open path */
255 gp_cairo_stroke(plot);
256
257 FPRINTF((stderr,"set_color %lf %lf %lf\n",color.r, color.g, color.b));
258
259 plot->color.r = color.r;
260 plot->color.g = color.g;
261 plot->color.b = color.b;
262 plot->color.alpha = alpha;
263 }
264
265
gp_cairo_set_linestyle(plot_struct * plot,int linestyle)266 void gp_cairo_set_linestyle(plot_struct *plot, int linestyle)
267 {
268 /*stroke any open path */
269 gp_cairo_stroke(plot);
270 /* draw any open polygon set */
271 gp_cairo_end_polygon(plot);
272
273 FPRINTF((stderr,"set_linestyle %d\n",linestyle));
274
275 plot->linestyle = linestyle;
276 }
277
278
gp_cairo_set_linetype(plot_struct * plot,int linetype)279 void gp_cairo_set_linetype(plot_struct *plot, int linetype)
280 {
281 /*stroke any open path */
282 gp_cairo_stroke(plot);
283 /* draw any open polygon set */
284 gp_cairo_end_polygon(plot);
285
286 FPRINTF((stderr,"set_linetype %d\n",linetype));
287
288 plot->linetype = linetype;
289 }
290
291
gp_cairo_set_pointsize(plot_struct * plot,double pointsize)292 void gp_cairo_set_pointsize(plot_struct *plot, double pointsize)
293 {
294 FPRINTF((stderr,"set_pointsize %lf\n",pointsize));
295
296 plot->pointsize = pointsize;
297 }
298
299
gp_cairo_set_justify(plot_struct * plot,JUSTIFY mode)300 void gp_cairo_set_justify(plot_struct *plot, JUSTIFY mode)
301 {
302 FPRINTF((stderr,"set_justify\n"));
303
304 plot->justify_mode = mode;
305 }
306
307
gp_cairo_set_font(plot_struct * plot,const char * name,float fontsize)308 void gp_cairo_set_font(plot_struct *plot, const char *name, float fontsize)
309 {
310 char *c;
311 char *fname;
312
313 FPRINTF((stderr,"set_font \"%s\" %f\n", name,fontsize));
314
315 /* Split out Bold and Italic attributes from font name */
316 fname = strdup(name);
317 for (c=fname; *c; c++) {
318 if (*c == '\\') {
319 char *d = c;
320 do { *d = *(d+1); } while (*d++);
321 } else {
322 if (*c == '-') *c = ' ';
323 if (*c == ':') *c = ' ';
324 }
325 }
326 if ((c = strstr(fname, " Bold"))) {
327 do { *c = *(c+5); } while (*c++);
328 plot->fontweight = PANGO_WEIGHT_BOLD;
329 } else
330 plot->fontweight = PANGO_WEIGHT_NORMAL;
331 if ((c = strstr(fname, " Italic"))) {
332 do { *c = *(c+7); } while (*c++);
333 plot->fontstyle = PANGO_STYLE_ITALIC;
334 } else
335 plot->fontstyle = PANGO_STYLE_NORMAL;
336
337 strncpy( plot->fontname, fname, sizeof(plot->fontname) );
338 plot->fontsize = fontsize;
339 free(fname);
340 }
341
342
gp_cairo_set_linewidth(plot_struct * plot,double linewidth)343 void gp_cairo_set_linewidth(plot_struct *plot, double linewidth)
344 {
345 FPRINTF((stderr,"set_linewidth %lf\n",linewidth));
346
347 /*stroke any open path */
348 gp_cairo_stroke(plot);
349 /* draw any open polygon set */
350 gp_cairo_end_polygon(plot);
351
352 if (!strcmp(term->name,"pdfcairo"))
353 linewidth *= 2;
354
355 if (linewidth < 0.20) /* Admittedly arbitrary */
356 linewidth = 0.20;
357 plot->linewidth = linewidth;
358
359 }
360
361
gp_cairo_set_textangle(plot_struct * plot,double angle)362 void gp_cairo_set_textangle(plot_struct *plot, double angle)
363 {
364 FPRINTF((stderr,"set_textangle %lf\n",angle));
365
366 plot->text_angle =angle;
367 }
368
369 /* By default, Cairo uses an antialiasing algorithm which may
370 * leave a seam between polygons which share a common edge.
371 * Several solutions allow to workaround this behaviour :
372 * - don't antialias the polygons
373 * Problem : aliased lines are ugly
374 * - stroke on each edge
375 * Problem : stroking is a very time-consuming operation
376 * - draw without antialiasing to a separate context of a bigger size
377 * Problem : not really in the spirit of the rest of the drawing.
378 * - enlarge the polygons so that they overlap slightly
379 * Problem : It is really more time-consuming that it may seem.
380 * It implies inspecting each corner to find which direction to move it
381 * (making the difference between the inside and the outside of the polygon).
382 * - using CAIRO_OPERATOR_SATURATE
383 * Problem : for each set of polygons, we have to draw front-to-back
384 * on a separate context and then copy back to this one.
385 * Time-consuming but probably less than stroking all the edges.
386 *
387 * The last solution is implemented if plot->polygons_saturate is set to TRUE
388 * Otherwise the default (antialiasing but may have seams) is used.
389 */
390
gp_cairo_draw_polygon(plot_struct * plot,int n,gpiPoint * corners)391 void gp_cairo_draw_polygon(plot_struct *plot, int n, gpiPoint *corners)
392 {
393 /* begin by stroking any open path */
394 gp_cairo_stroke(plot);
395
396 if (plot->polygons_saturate) {
397 int i;
398 path_item *path;
399
400 path = (path_item*) gp_alloc(sizeof(path_item), "gp_cairo : polygon path");
401
402 path->n = n;
403 path->corners = (gpiPoint*) gp_alloc(n*sizeof(gpiPoint), "gp_cairo : polygon corners");
404 for(i=0;i<n;i++)
405 *(path->corners + i) = *corners++;
406
407 path->color = plot->color;
408
409 if (plot->polygon_path_last == NULL) {
410 FPRINTF((stderr,"creating a polygon path\n"));
411 path->previous = NULL;
412 plot->polygon_path_last = path;
413 } else {
414 FPRINTF((stderr,"adding a polygon to the polygon path\n"));
415 path->previous = plot->polygon_path_last;
416 plot->polygon_path_last = path;
417 }
418 } else {
419 int i;
420 /* draw the polygon directly */
421 FPRINTF((stderr,"processing one polygon\n"));
422 cairo_move_to(plot->cr, corners[0].x, corners[0].y);
423 for (i=1;i<n;++i)
424 cairo_line_to(plot->cr, corners[i].x, corners[i].y);
425 cairo_close_path(plot->cr);
426 gp_cairo_fill( plot, corners->style & 0xf, corners->style >> 4 );
427 cairo_fill(plot->cr);
428 }
429 }
430
431
gp_cairo_end_polygon(plot_struct * plot)432 void gp_cairo_end_polygon(plot_struct *plot)
433 {
434 int i;
435 path_item *path;
436 path_item *path2;
437 rgba_color color_sav;
438 cairo_t *context;
439 cairo_t *context_sav;
440 cairo_surface_t *surface;
441 cairo_matrix_t matrix;
442 cairo_matrix_t matrix2;
443 cairo_pattern_t *pattern;
444
445 /* when we are not using OPERATOR_SATURATE, the polygons are drawn
446 * directly in gp_cairo_draw_polygon */
447 if (!plot->polygons_saturate)
448 return;
449
450 if (plot->polygon_path_last == NULL)
451 return;
452
453 path = plot->polygon_path_last;
454 color_sav = plot->color;
455
456 /* if there's only one polygon, draw it directly */
457 if (path->previous == NULL) {
458 FPRINTF((stderr,"processing one polygon\n"));
459 cairo_move_to(plot->cr, path->corners[0].x, path->corners[0].y);
460 for (i=1;i<path->n;++i)
461 cairo_line_to(plot->cr, path->corners[i].x, path->corners[i].y);
462 cairo_close_path(plot->cr);
463 plot->color = path->color;
464 gp_cairo_fill( plot, path->corners->style & 0xf, path->corners->style >> 4 );
465 cairo_fill(plot->cr);
466 free(path->corners);
467 free(path);
468 plot->polygon_path_last = NULL;
469 plot->color = color_sav;
470 return;
471 }
472
473 FPRINTF((stderr,"processing several polygons\n"));
474
475 /* this is meant to test Full-Scene-Anti-Aliasing by supersampling,
476 * in association with CAIRO_ANTIALIAS_NONE a few lines below */
477 #define SCALE 1
478
479 /* otherwise, draw front-to-back to a separate context,
480 * using CAIRO_OPERATOR_SATURATE */
481 context_sav = plot->cr;
482 surface = cairo_surface_create_similar(cairo_get_target(plot->cr),
483 CAIRO_CONTENT_COLOR_ALPHA,
484 plot->device_xmax*SCALE,
485 plot->device_ymax*SCALE);
486 context = cairo_create(surface);
487 cairo_set_operator(context,CAIRO_OPERATOR_SATURATE);
488 if (plot->antialiasing)
489 cairo_set_antialias(context,CAIRO_ANTIALIAS_DEFAULT);
490 else
491 cairo_set_antialias(context,CAIRO_ANTIALIAS_NONE);
492
493 /* transformation matrix between gnuplot and cairo coordinates */
494 cairo_matrix_init(&matrix,
495 plot->xscale/SCALE/plot->oversampling_scale,
496 0,0,
497 plot->yscale/SCALE/plot->oversampling_scale,
498 0.5,0.5);
499 cairo_set_matrix(context, &matrix);
500
501 plot->cr = context;
502 path = plot->polygon_path_last;
503
504 while (path != NULL) {
505 /* check for interrupt */
506 if (plot->interrupt)
507 break;
508 /* build the path */
509 cairo_move_to(plot->cr, path->corners[0].x, path->corners[0].y);
510 for (i=1;i<(path->n);++i)
511 cairo_line_to(plot->cr, path->corners[i].x, path->corners[i].y);
512 cairo_close_path(plot->cr);
513 /* set the fill pattern */
514 plot->color = path->color;
515 gp_cairo_fill( plot, path->corners->style & 0xf, path->corners->style >> 4 );
516 cairo_fill(plot->cr);
517 /* free the ressources, and go to the next point */
518 free(path->corners);
519 path2 = path->previous;
520 free(path);
521 path = path2;
522 }
523
524 plot->polygon_path_last = NULL;
525
526 pattern = cairo_pattern_create_for_surface( surface );
527 cairo_destroy( context );
528
529 /* compensate the transformation matrix of the main context */
530 cairo_matrix_init(&matrix2,
531 plot->xscale*SCALE/plot->oversampling_scale,
532 0,0,
533 plot->yscale*SCALE/plot->oversampling_scale,
534 0.5,0.5);
535 cairo_pattern_set_matrix( pattern, &matrix2 );
536
537 plot->cr = context_sav;
538 plot->color = color_sav;
539 cairo_surface_destroy( surface );
540 cairo_set_source( plot->cr, pattern );
541 cairo_pattern_destroy( pattern );
542 cairo_paint( plot->cr );
543 }
544
gp_cairo_set_dashtype(plot_struct * plot,int type,t_dashtype * custom_dash_type)545 void gp_cairo_set_dashtype(plot_struct *plot, int type, t_dashtype *custom_dash_type)
546 {
547 static double dashpattern[4][8] =
548 {
549 {5, 8, 5, 8, 5, 8, 5, 8}, /* Medium dash */
550 {1, 4, 1, 4, 1, 4, 1, 4}, /* dots */
551 {8, 4, 2, 4, 8, 4, 2, 4}, /* dash dot */
552 {9, 4, 1, 4, 1, 4, 0, 0} /* dash dot dot */
553 };
554 int lt = (type) % 5;
555
556 if (type == DASHTYPE_CUSTOM && custom_dash_type) {
557 /* Convert to internal representation */
558 int i;
559 double empirical_scale;
560
561 if (!strcmp(term->name,"pngcairo"))
562 empirical_scale = 0.25;
563 else
564 empirical_scale = 0.55;
565
566 if (plot->linewidth > 1)
567 empirical_scale *= plot->linewidth;
568
569 for (i=0; i<8; i++)
570 plot->current_dashpattern[i] = custom_dash_type->pattern[i]
571 * plot->dashlength
572 * plot->oversampling_scale * empirical_scale;
573 gp_cairo_set_linestyle(plot, GP_CAIRO_DASH);
574
575 } else if (type > 0 && lt != 0) {
576 /* Use old (version 4) set of linetype patterns */
577 int i;
578 double empirical_scale = 1.;
579 if (plot->linewidth > 1)
580 empirical_scale *= plot->linewidth;
581
582 for (i=0; i<8; i++)
583 plot->current_dashpattern[i] = dashpattern[lt-1][i]
584 * plot->dashlength
585 * plot->oversampling_scale
586 * empirical_scale;
587 gp_cairo_set_linestyle(plot, GP_CAIRO_DASH);
588
589 } else {
590 /* Every 5th pattern in the old set is solid */
591 gp_cairo_set_linestyle(plot, GP_CAIRO_SOLID);
592 }
593 }
594
gp_cairo_stroke(plot_struct * plot)595 void gp_cairo_stroke(plot_struct *plot)
596 {
597 int lt = plot->linetype;
598 double lw = plot->linewidth * plot->oversampling_scale;
599
600 if (!plot->opened_path) {
601 FPRINTF((stderr,"stroke with non-opened path !\n"));
602 return;
603 }
604
605 /* add last point */
606 cairo_line_to (plot->cr, plot->current_x, plot->current_y);
607
608
609 cairo_save(plot->cr);
610
611 if (plot->linetype == LT_NODRAW) {
612 cairo_set_operator(plot->cr, CAIRO_OPERATOR_DEST);
613 lw = 0.0;
614
615 } else if (lt == LT_AXIS || plot->linestyle == GP_CAIRO_DOTS) {
616 /* Grid lines (lt 0) */
617 double dashes[2];
618 double empirical_scale = 1.0;
619 if (plot->linewidth > 1)
620 empirical_scale *= plot->linewidth;
621 dashes[0] = 0.4 * plot->oversampling_scale * plot->dashlength * empirical_scale;
622 dashes[1] = 4.0 * plot->oversampling_scale * plot->dashlength * empirical_scale;
623 cairo_set_dash(plot->cr, dashes, 2 /*num_dashes*/, 0 /*offset*/);
624 }
625
626 else if (plot->linestyle == GP_CAIRO_DASH) {
627 cairo_set_dash(plot->cr, &(plot->current_dashpattern[0]), 8 /*num_dashes*/, 0 /*offset*/);
628 }
629
630 cairo_set_source_rgba(plot->cr, plot->color.r, plot->color.g, plot->color.b,
631 1. - plot->color.alpha);
632 cairo_set_line_width(plot->cr, lw);
633
634 cairo_stroke(plot->cr);
635
636 cairo_restore(plot->cr);
637
638 plot->opened_path = FALSE;
639 }
640
641
gp_cairo_move(plot_struct * plot,int x,int y)642 void gp_cairo_move(plot_struct *plot, int x, int y)
643 {
644 /* Dec 2014 - Do not let zero-length moves interrupt */
645 /* the current line/polyline context, e.g. dash pattern. */
646 if (x == plot->current_x && y == plot->current_y)
647 return;
648
649 /* begin by stroking any open path */
650 gp_cairo_stroke(plot);
651 /* also draw any open polygon set */
652 gp_cairo_end_polygon(plot);
653
654 plot->current_x = x;
655 plot->current_y = y;
656 plot->orig_current_x = x;
657 plot->orig_current_y = y;
658 }
659
660
gp_cairo_vector(plot_struct * plot,int x,int y)661 void gp_cairo_vector(plot_struct *plot, int x, int y)
662 {
663 double x1 = x, y1 = y;
664 double new_pos;
665 double weight1 = (double) plot->hinting/100;
666 double weight2 = 1.0 - weight1;
667
668 /* begin by drawing any open polygon set */
669 gp_cairo_end_polygon(plot);
670
671 FPRINTF((stderr,"vector\n"));
672
673 /* hinting magic when we are using antialiasing+oversampling */
674 if (plot->antialiasing && plot->oversampling) {
675 if (plot->hinting < 0 || plot->hinting > 100) {
676 fprintf(stderr,"wxt terminal : hinting error, setting to default\n");
677 plot->hinting = 100;
678 }
679
680 /* detect and handle vertical lines */
681 /* the second test is there to avoid artefacts when you choose
682 * a high sampling ('set samples 10000'), so that a smooth function
683 * may be drawn as lines between very close points */
684 if (plot->orig_current_x == x1 && fabs(plot->orig_current_y - y1)>plot->oversampling_scale) {
685 new_pos = rint(plot->current_x*plot->xscale/plot->oversampling_scale);
686 new_pos *= plot->oversampling_scale/plot->xscale;
687 plot->current_x = weight1*new_pos + weight2*plot->current_x;
688 x1 = plot->current_x;
689 new_pos = rint(plot->current_y*plot->yscale/plot->oversampling_scale);
690 new_pos *= plot->oversampling_scale/plot->yscale;
691 plot->current_y = weight1*new_pos + weight2*plot->current_y;
692 new_pos = rint(y1*plot->yscale/plot->oversampling_scale);
693 new_pos *= plot->oversampling_scale/plot->yscale;
694 y1 = weight1*new_pos + weight2*y1;
695 }
696 /* do the same for horizontal lines */
697 if (plot->orig_current_y == y1 && fabs(plot->orig_current_x - x1)>plot->oversampling_scale) {
698 new_pos = rint(plot->current_y*plot->yscale/plot->oversampling_scale);
699 new_pos *= plot->oversampling_scale/plot->yscale;
700 plot->current_y = weight1*new_pos + weight2*plot->current_y;
701 y1 = plot->current_y;
702 new_pos = rint(plot->current_x*plot->xscale/plot->oversampling_scale);
703 new_pos *= plot->oversampling_scale/plot->xscale;
704 plot->current_x = weight1*new_pos + weight2*plot->current_x;
705 new_pos = rint(x1*plot->xscale/plot->oversampling_scale);
706 new_pos *= plot->oversampling_scale/plot->xscale;
707 x1 = weight1*new_pos + weight2*x1;
708 }
709 }
710
711 if (!plot->opened_path) {
712 plot->opened_path = TRUE;
713 cairo_move_to (plot->cr, plot->current_x, plot->current_y);
714 } else
715 cairo_line_to (plot->cr, plot->current_x, plot->current_y);
716
717 plot->current_x = x1;
718 plot->current_y = y1;
719 plot->orig_current_x = x;
720 plot->orig_current_y = y;
721 }
722
723 /* pango needs a string encoded in utf-8. We use g_convert from glib.
724 * gp_cairo_get_encoding() gives the encoding set via 'set enconding'
725 * memory allocated for the string has to be freed */
gp_cairo_convert(plot_struct * plot,const char * string)726 static gchar * gp_cairo_convert(plot_struct *plot, const char* string)
727 {
728 gsize bytes_read;
729 GError *error = NULL;
730 const char *charset = NULL;
731 gchar * string_utf8;
732
733 if (g_utf8_validate(string, -1, NULL)) {
734 string_utf8 = g_strdup(string);
735 } else {
736 charset = gp_cairo_get_encoding(plot);
737 string_utf8 = g_convert(string, -1, "UTF-8", charset, &bytes_read, NULL, &error);
738 }
739
740 /* handle error case */
741 if (error != NULL) {
742 /* fatal error in conversion */
743 if (error->code != G_CONVERT_ERROR_ILLEGAL_SEQUENCE) {
744 fprintf(stderr, "Unable to convert \"%s\": %s\n", string, error->message);
745 g_error_free (error);
746 return strdup("");
747 }
748 /* The sequence is invalid in the chosen charset.
749 * we will try to fall back to iso_8859_1, and if it doesn't work,
750 * we'll use bytes_read to convert up to the faulty character,
751 * and throw the rest. */
752 g_error_free (error);
753 error = NULL;
754 string_utf8 = g_convert(string, -1, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
755 if (error != NULL) {
756 fprintf(stderr, "Unable to convert \"%s\": the sequence is invalid "\
757 "in the current charset (%s), %d bytes read out of %d\n",
758 string, charset, (int)bytes_read, (int)strlen(string));
759 string_utf8 = g_convert(string, bytes_read, "UTF-8", charset, NULL, NULL, NULL);
760 g_error_free (error);
761 } else
762 fprintf(stderr, "Unable to convert \"%s\": the sequence is invalid "\
763 "in the current charset (%s), falling back to iso_8859_1\n",
764 string, charset);
765 }
766
767 return string_utf8;
768 }
769
770 /*
771 * The following #ifdef WIN32 section is all to work around a bug in
772 * the cairo/win32 backend for font rendering. It has the effect of
773 * testing for libfreetype support, and using that instead if possible.
774 * Suggested by cairo developer Behdad Esfahbod.
775 * Allin Cottrell suggests that this not necessary anymore for newer
776 * versions of cairo.
777 */
778 #if defined(WIN32) && (CAIRO_VERSION_MAJOR < 2) && (CAIRO_VERSION_MINOR < 10)
779 static PangoLayout *
gp_cairo_create_layout(cairo_t * cr)780 gp_cairo_create_layout(cairo_t *cr)
781 {
782 static PangoFontMap *fontmap;
783 PangoContext *context;
784 PangoLayout *layout;
785
786 if (fontmap == NULL) {
787 fontmap = pango_cairo_font_map_new_for_font_type(CAIRO_FONT_TYPE_FT);
788 if (fontmap == NULL) {
789 fontmap = pango_cairo_font_map_get_default();
790 }
791 }
792
793 #if PANGO_VERSION_MAJOR > 1 || PANGO_VERSION_MINOR >= 22
794 context = pango_font_map_create_context(fontmap);
795 #else
796 context = pango_cairo_font_map_create_context((PangoCairoFontMap *) fontmap);
797 #endif
798
799 layout = pango_layout_new(context);
800 g_clear_object (&context);
801
802 return layout;
803 }
804 #else
805 static PangoLayout *
gp_cairo_create_layout(cairo_t * cr)806 gp_cairo_create_layout(cairo_t *cr)
807 {
808 return pango_cairo_create_layout(cr);
809 }
810 #endif
811
gp_cairo_draw_text(plot_struct * plot,int x1,int y1,const char * string,int * width,int * height)812 void gp_cairo_draw_text(plot_struct *plot, int x1, int y1, const char* string,
813 int *width, int *height)
814 {
815 double x,y;
816 double arg;
817 double vert_just, delta, deltax, deltay;
818 double box_x, box_y;
819 PangoRectangle ink_rect;
820 PangoRectangle logical_rect;
821 PangoLayout *layout;
822 PangoFontDescription *desc;
823 gchar* string_utf8;
824 #ifdef MAP_SYMBOL
825 TBOOLEAN symbol_font_parsed = FALSE;
826 #endif /*MAP_SYMBOL*/
827 int baseline_offset;
828
829
830 /* begin by stroking any open path */
831 gp_cairo_stroke(plot);
832 /* also draw any open polygon set */
833 gp_cairo_end_polygon(plot);
834
835 FPRINTF((stderr,"draw_text\n"));
836
837 #ifdef MAP_SYMBOL
838 /* we have to treat Symbol font as a special case */
839 if (!strcmp(plot->fontname,"Symbol")) {
840 FPRINTF((stderr,"Parsing a Symbol string\n"));
841 string_utf8 = gp_cairo_convert_symbol_to_unicode(plot, string);
842 strncpy(plot->fontname, gp_cairo_default_font(), sizeof(plot->fontname));
843 symbol_font_parsed = TRUE;
844 } else
845 #endif /*MAP_SYMBOL*/
846 {
847 /* convert the input string to utf8 */
848 string_utf8 = gp_cairo_convert(plot, string);
849 }
850
851 /* Create a PangoLayout, set the font and text */
852 layout = gp_cairo_create_layout (plot->cr);
853
854 pango_layout_set_text (layout, string_utf8, -1);
855 g_free(string_utf8);
856 desc = pango_font_description_new ();
857 pango_font_description_set_family (desc, (const char*) plot->fontname);
858 #ifdef MAP_SYMBOL
859 /* restore the Symbol font setting */
860 if (symbol_font_parsed)
861 strncpy(plot->fontname, "Symbol", sizeof(plot->fontname));
862 #endif /*MAP_SYMBOL*/
863 pango_font_description_set_size (desc, (int) (plot->fontsize*PANGO_SCALE*plot->oversampling_scale) );
864
865 pango_font_description_set_weight (desc, plot->fontweight);
866 pango_font_description_set_style (desc,
867 plot->fontstyle ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
868 pango_layout_set_font_description (layout, desc);
869 FPRINTF((stderr, "pango font description: %s\n", pango_font_description_to_string(desc)));
870 pango_font_description_free (desc);
871
872 pango_layout_get_extents(layout, &ink_rect, &logical_rect);
873 if (width)
874 *width = logical_rect.width / PANGO_SCALE;
875 if (height)
876 *height = logical_rect.height / PANGO_SCALE;
877
878 /* EAM Mar 2009 - Adjusting the vertical position for every character fragment */
879 /* leads to uneven baselines. Better to adjust to the "average" character height */
880 /* EAM Dec 2012 - The problem is that avg_vchar is not kept in sync with the */
881 /* font size. It is changed when the set_font command is received, not when */
882 /* it is executed in the display list. Try basing off plot->fontsize instead. */
883
884 baseline_offset = pango_layout_get_baseline(layout) / PANGO_SCALE;
885 vert_just = 0.5 * (float)(plot->fontsize * plot->oversampling_scale);
886 vert_just = baseline_offset - vert_just;
887
888 arg = plot->text_angle * M_PI/180;
889 x = (double)x1 - vert_just * sin(arg);
890 y = (double)y1 - vert_just * cos(arg);
891
892 delta = ((double)logical_rect.width/2) / PANGO_SCALE;
893
894 deltax = delta * cos(arg);
895 deltay = delta * sin(arg);
896
897 switch (plot->justify_mode) {
898 case LEFT :
899 break;
900 case CENTRE :
901 x -= deltax;
902 y += deltay;
903 break;
904 case RIGHT :
905 x -= 2*deltax;
906 y += 2*deltay;
907 break;
908 }
909
910 #if 0 /* helper point */
911 gp_cairo_draw_point(plot, x1, y1, 0);
912 #endif /* helper point */
913
914 cairo_save (plot->cr);
915 cairo_translate(plot->cr, x, y);
916 cairo_rotate(plot->cr, -arg);
917
918 cairo_set_source_rgba(plot->cr, plot->color.r, plot->color.g, plot->color.b,
919 1. - plot->color.alpha);
920
921 /* Inform Pango to re-layout the text with the new transformation */
922 pango_cairo_update_layout (plot->cr, layout);
923 pango_cairo_show_layout (plot->cr, layout);
924 /* pango_cairo_show_layout does not clear the path (here a starting point)
925 * Do it by ourselves, or we can get spurious lines on future calls. */
926 cairo_new_path(plot->cr);
927
928 #ifdef EAM_BOXED_TEXT
929 if (in_textbox) {
930 box_rotation = -arg;
931 box_origin_x = x1;
932 box_origin_y = y1;
933 box_y = box_origin_y - vert_just;
934 switch (plot->justify_mode) {
935 case LEFT:
936 box_x = box_origin_x;
937 break;
938 default:
939 case CENTRE:
940 box_x = box_origin_x - delta;
941 break;
942 case RIGHT:
943 box_x = box_origin_x - 2*delta;
944 break;
945 }
946
947 /* Update bounding box for boxed label text */
948 pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
949
950 /* Auto-initialization */
951 if (bounding_box[0] < 0 && bounding_box[1] < 0) {
952 bounding_box[0] = bounding_box[2] = box_x;
953 bounding_box[1] = bounding_box[3] = box_y;
954 }
955 if (bounding_box[0] > box_x + ink_rect.x)
956 bounding_box[0] = box_x + ink_rect.x;
957 if (bounding_box[2] < box_x + ink_rect.x + ink_rect.width)
958 bounding_box[2] = box_x + ink_rect.x + ink_rect.width;
959 if (bounding_box[1] > box_y + ink_rect.y)
960 bounding_box[1] = box_y + ink_rect.y;
961 if (bounding_box[3] < box_y + ink_rect.y + ink_rect.height)
962 bounding_box[3] = box_y + ink_rect.y + ink_rect.height;
963 }
964 #endif
965
966 /* free the layout object */
967 g_clear_object (&layout);
968 cairo_restore (plot->cr);
969 }
970
971
gp_cairo_draw_point(plot_struct * plot,int x1,int y1,int style)972 void gp_cairo_draw_point(plot_struct *plot, int x1, int y1, int style)
973 {
974 double x = x1;
975 double y = y1;
976 double new_pos;
977 double weight1 = (double) plot->hinting/100;
978 double weight2 = 1.0 - weight1;
979 double size = plot->pointsize*3*plot->oversampling_scale;
980
981 /* begin by stroking any open path */
982 gp_cairo_stroke(plot);
983 /* also draw any open polygon set */
984 gp_cairo_end_polygon(plot);
985
986 FPRINTF((stderr,"drawpoint\n"));
987
988 /* hinting magic when we are using antialiasing+oversampling */
989 if (plot->antialiasing && plot->oversampling) {
990 if (plot->hinting < 0 || plot->hinting > 100) {
991 fprintf(stderr,"wxt terminal : hinting error, setting to default\n");
992 plot->hinting = 100;
993 }
994
995 new_pos = rint(x*plot->xscale/plot->oversampling_scale);
996 new_pos *= plot->oversampling_scale/plot->xscale;
997 x = weight1*new_pos + weight2*x;
998
999 new_pos = rint(y*plot->yscale/plot->oversampling_scale);
1000 new_pos *= plot->oversampling_scale/plot->yscale;
1001 y = weight1*new_pos + weight2*y;
1002 }
1003
1004 cairo_save(plot->cr);
1005 cairo_set_line_width(plot->cr, plot->linewidth*plot->oversampling_scale);
1006 cairo_set_source_rgba(plot->cr, plot->color.r, plot->color.g, plot->color.b,
1007 1. - plot->color.alpha);
1008
1009 /* Dot FIXME: because this is drawn as a filled circle, it's quite slow */
1010 if (style < 0) {
1011 cairo_arc (plot->cr, x, y, 0.5*plot->oversampling_scale, 0, 2*M_PI);
1012 cairo_fill (plot->cr);
1013 }
1014
1015
1016 style = style % 15;
1017 switch (style) {
1018 case 0: /* plus */
1019 cairo_move_to(plot->cr, x-size, y);
1020 cairo_line_to(plot->cr, x+size,y);
1021 cairo_stroke(plot->cr);
1022 cairo_move_to(plot->cr, x, y-size);
1023 cairo_line_to(plot->cr, x,y+size);
1024 cairo_stroke(plot->cr);
1025 break;
1026 case 1: /* plot->cross */
1027 cairo_move_to(plot->cr, x-size, y-size);
1028 cairo_line_to(plot->cr, x+size,y+size);
1029 cairo_stroke(plot->cr);
1030 cairo_move_to(plot->cr, x-size, y+size);
1031 cairo_line_to(plot->cr, x+size,y-size);
1032 cairo_stroke(plot->cr);
1033 break;
1034 case 2: /* star */
1035 cairo_move_to(plot->cr, x-size, y);
1036 cairo_line_to(plot->cr, x+size,y);
1037 cairo_stroke(plot->cr);
1038 cairo_move_to(plot->cr, x, y-size);
1039 cairo_line_to(plot->cr, x,y+size);
1040 cairo_stroke(plot->cr);
1041 cairo_move_to(plot->cr, x-size, y-size);
1042 cairo_line_to(plot->cr, x+size,y+size);
1043 cairo_stroke(plot->cr);
1044 cairo_move_to(plot->cr, x-size, y+size);
1045 cairo_line_to(plot->cr, x+size,y-size);
1046 cairo_stroke(plot->cr);
1047 break;
1048 case 3: /* box */
1049 case 4: /* filled box */
1050 cairo_move_to(plot->cr, x-size, y-size);
1051 cairo_line_to(plot->cr, x-size,y+size);
1052 cairo_line_to(plot->cr, x+size,y+size);
1053 cairo_line_to(plot->cr, x+size,y-size);
1054 cairo_close_path(plot->cr);
1055 if (style == 4)
1056 cairo_fill_preserve(plot->cr);
1057 cairo_stroke(plot->cr);
1058 break;
1059 case 5: /* circle */
1060 cairo_arc (plot->cr, x, y, size, 0, 2*M_PI);
1061 cairo_stroke (plot->cr);
1062 break;
1063 case 6: /* filled circle */
1064 cairo_arc (plot->cr, x, y, size, 0, 2*M_PI);
1065 cairo_fill_preserve(plot->cr);
1066 cairo_stroke(plot->cr);
1067 break;
1068 case 7: /* triangle */
1069 case 8: /* filled triangle */
1070 cairo_move_to(plot->cr, x-size, y+size-plot->oversampling_scale);
1071 cairo_line_to(plot->cr, x,y-size);
1072 cairo_line_to(plot->cr, x+size,y+size-plot->oversampling_scale);
1073 cairo_close_path(plot->cr);
1074 if (style == 8)
1075 cairo_fill_preserve(plot->cr);
1076 cairo_stroke(plot->cr);
1077 break;
1078 case 9: /* upside down triangle */
1079 case 10: /* filled upside down triangle */
1080 cairo_move_to(plot->cr, x-size, y-size+plot->oversampling_scale);
1081 cairo_line_to(plot->cr, x,y+size);
1082 cairo_line_to(plot->cr, x+size,y-size+plot->oversampling_scale);
1083 cairo_close_path(plot->cr);
1084 if (style == 10)
1085 cairo_fill_preserve(plot->cr);
1086 cairo_stroke(plot->cr);
1087 break;
1088 case 11: /* diamond */
1089 case 12: /* filled diamond */
1090 cairo_move_to(plot->cr, x-size, y);
1091 cairo_line_to(plot->cr, x,y+size);
1092 cairo_line_to(plot->cr, x+size,y);
1093 cairo_line_to(plot->cr, x,y-size);
1094 cairo_close_path(plot->cr);
1095 if (style == 12)
1096 cairo_fill_preserve(plot->cr);
1097 cairo_stroke(plot->cr);
1098 break;
1099 case 13: /* pentagon */
1100 case 14: /* filled pentagon */
1101 cairo_move_to(plot->cr, x+size*0.5878, y-size*0.8090);
1102 cairo_line_to(plot->cr, x-size*0.5878, y-size*0.8090);
1103 cairo_line_to(plot->cr, x-size*0.9511, y+size*0.3090);
1104 cairo_line_to(plot->cr, x, y+size);
1105 cairo_line_to(plot->cr, x+size*0.9511, y+size*0.3090);
1106 cairo_close_path(plot->cr);
1107 if (style == 14)
1108 cairo_fill_preserve(plot->cr);
1109 cairo_stroke(plot->cr);
1110 break;
1111 default :
1112 break;
1113 }
1114 cairo_restore(plot->cr);
1115 }
1116
1117
1118
gp_cairo_draw_fillbox(plot_struct * plot,int x,int y,int width,int height,int style)1119 void gp_cairo_draw_fillbox(plot_struct *plot, int x, int y, int width, int height, int style)
1120 {
1121 int fillpar = style >> 4;
1122 int fillstyle = style & 0xf;
1123
1124 /* begin by stroking any open path */
1125 gp_cairo_stroke(plot);
1126 /* also draw any open polygon set */
1127 gp_cairo_end_polygon(plot);
1128
1129 FPRINTF((stderr,"fillbox fillpar = %d, fillstyle = %d\n",fillpar, fillstyle));
1130 gp_cairo_fill( plot, fillstyle, fillpar);
1131
1132 cairo_move_to(plot->cr, x, y);
1133 cairo_rel_line_to(plot->cr, 0, -height);
1134 cairo_rel_line_to(plot->cr, width, 0);
1135 cairo_rel_line_to(plot->cr, 0, height);
1136 cairo_rel_line_to(plot->cr, -width, 0);
1137 cairo_close_path(plot->cr);
1138 cairo_fill(plot->cr);
1139 }
1140
1141
1142 /* corner[0] = (x1,y1) is the upper left corner (in terms of plot location) of
1143 * the outer edge of the image. Similarly, corner[1] = (x2,y2) is the lower
1144 * right corner of the outer edge of the image. (Outer edge means the
1145 * outer extent of the corner pixels, not the middle of the corner pixels).
1146 * corner[2] and corner[3] = (x3,y3) and (x4,y4) define a clipping box in
1147 * the primary plot into which all or part of the image will be rendered.
1148 */
gp_cairo_draw_image(plot_struct * plot,unsigned int * image,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int M,int N)1149 void gp_cairo_draw_image(plot_struct *plot, unsigned int * image, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int M, int N)
1150 {
1151 double scale_x, scale_y;
1152 cairo_surface_t *image_surface;
1153 cairo_pattern_t *pattern;
1154 cairo_matrix_t matrix;
1155
1156 /* begin by stroking any open path */
1157 gp_cairo_stroke(plot);
1158 /* also draw any open polygon set */
1159 gp_cairo_end_polygon(plot);
1160
1161 image_surface = cairo_image_surface_create_for_data((unsigned char*) image,
1162 CAIRO_FORMAT_ARGB32, M, N, 4*M);
1163
1164 scale_x = (double)M/(double)abs( x2 - x1 );
1165 scale_y = (double)N/(double)abs( y2 - y1 );
1166
1167 FPRINTF((stderr,"M %d N %d x1 %d y1 %d\n", M, N, x1, y1));
1168 cairo_save( plot->cr );
1169
1170 /* Set clipping boundaries for image copy.
1171 * The bounds were originally possed in corners[2] and corners[3]
1172 */
1173 cairo_move_to(plot->cr, x3, y3);
1174 cairo_line_to(plot->cr, x3, y4);
1175 cairo_line_to(plot->cr, x4, y4);
1176 cairo_line_to(plot->cr, x4, y3);
1177 cairo_close_path(plot->cr);
1178 cairo_clip(plot->cr);
1179
1180 pattern = cairo_pattern_create_for_surface( image_surface );
1181 /* scale and keep sharp edges */
1182 cairo_pattern_set_filter( pattern, CAIRO_FILTER_FAST );
1183 cairo_matrix_init_scale( &matrix, scale_x, scale_y );
1184 /* x1 and y1 give the user-space coordinate
1185 * at which the surface origin should appear.
1186 * (The surface origin is its upper-left corner
1187 * before any transformation has been applied.) */
1188 cairo_matrix_translate( &matrix, -x1, -y1 );
1189 cairo_pattern_set_matrix( pattern, &matrix );
1190 cairo_set_source( plot->cr, pattern );
1191
1192 cairo_paint( plot->cr );
1193
1194 cairo_restore( plot->cr );
1195
1196 cairo_pattern_destroy( pattern );
1197 cairo_surface_destroy( image_surface );
1198 }
1199
1200 /* =======================================================================
1201 * Enhanced text mode support
1202 * =====================================================================*/
1203
gp_cairo_add_attr(plot_struct * plot,PangoAttrList * AttrList,int start,int end)1204 void gp_cairo_add_attr(plot_struct *plot, PangoAttrList * AttrList, int start, int end )
1205 {
1206 PangoAttribute *p_attr_rise, *p_attr_size, *p_attr_family;
1207 PangoAttribute *p_attr_weight, *p_attr_style;
1208
1209 p_attr_size = pango_attr_size_new ((int) (gp_cairo_enhanced_fontsize*PANGO_SCALE));
1210 p_attr_size->start_index = start;
1211 p_attr_size->end_index = end;
1212 pango_attr_list_insert (AttrList, p_attr_size);
1213
1214 p_attr_rise = pango_attr_rise_new ((int) (gp_cairo_enhanced_base*PANGO_SCALE));
1215 p_attr_rise->start_index = start;
1216 p_attr_rise->end_index = end;
1217 pango_attr_list_insert (AttrList, p_attr_rise);
1218
1219 p_attr_family = pango_attr_family_new (gp_cairo_enhanced_get_fontname(plot));
1220 p_attr_family->start_index = start;
1221 p_attr_family->end_index = end;
1222 pango_attr_list_insert (AttrList, p_attr_family);
1223
1224 p_attr_weight = pango_attr_weight_new (plot->fontweight);
1225 p_attr_weight->start_index = start;
1226 p_attr_weight->end_index = end;
1227 pango_attr_list_insert (AttrList, p_attr_weight);
1228
1229 p_attr_style = pango_attr_style_new (plot->fontstyle);
1230 p_attr_style->start_index = start;
1231 p_attr_style->end_index = end;
1232 pango_attr_list_insert (AttrList, p_attr_style);
1233 }
1234
1235 /* add a blank character to the text string with a custom shape */
gp_cairo_add_shape(PangoRectangle rect,int position)1236 void gp_cairo_add_shape( PangoRectangle rect,int position)
1237 {
1238 PangoAttribute *p_attr_shape;
1239
1240 FPRINTF((stderr, "adding blank custom shape\n"));
1241
1242 strncat(gp_cairo_utf8, " ", sizeof(gp_cairo_utf8)-strlen(gp_cairo_utf8)-1);
1243 p_attr_shape = pango_attr_shape_new (&rect,&rect);
1244 p_attr_shape->start_index = position;
1245 p_attr_shape->end_index = position+1;
1246 pango_attr_list_insert (gp_cairo_enhanced_AttrList, p_attr_shape);
1247 }
1248
1249 /* gp_cairo_enhanced_flush() draws enhanced_text, which has been filled by _writec()*/
gp_cairo_enhanced_flush(plot_struct * plot)1250 void gp_cairo_enhanced_flush(plot_struct *plot)
1251 {
1252 PangoRectangle save_logical_rect;
1253 PangoLayout *save_layout;
1254
1255 PangoLayout *current_layout;
1256 PangoRectangle current_ink_rect;
1257 PangoRectangle current_logical_rect;
1258 PangoFontDescription *current_desc;
1259
1260 PangoRectangle underprinted_logical_rect;
1261 int overprinted_width = 0;
1262 PangoLayout *underprinted_layout;
1263 int start, end;
1264 PangoLayout *hide_layout;
1265
1266 PangoRectangle hide_ink_rect;
1267 PangoRectangle hide_logical_rect;
1268 PangoFontDescription *hide_desc;
1269 PangoLayout *zerowidth_layout;
1270 PangoFontDescription *zerowidth_desc;
1271 PangoRectangle zerowidth_logical_rect;
1272 /* PangoRectangle zerowidth_ink_rect; */
1273
1274 int save_start, save_end;
1275 int underprinted_start, underprinted_end;
1276
1277 gchar* enhanced_text_utf8;
1278
1279 #ifdef MAP_SYMBOL
1280 TBOOLEAN symbol_font_parsed = FALSE;
1281 #endif /*MAP_SYMBOL*/
1282
1283 if (!gp_cairo_enhanced_opened_string)
1284 return;
1285
1286 FPRINTF((stderr, "enhanced flush str=\"%s\" font=%s op=%d sf=%d wf=%d base=%f os=%d wt=%d sl=%d\n",
1287 gp_cairo_enhanced_string,
1288 gp_cairo_enhanced_font,
1289 gp_cairo_enhanced_overprint,
1290 gp_cairo_enhanced_showflag,
1291 gp_cairo_enhanced_widthflag,
1292 gp_cairo_enhanced_base,
1293 gp_cairo_enhanced_opened_string,
1294 plot->fontweight,
1295 plot->fontstyle ));
1296
1297 gp_cairo_enhanced_opened_string = FALSE;
1298
1299 #ifdef MAP_SYMBOL
1300 /* we have to treat Symbol font as a special case */
1301 if (!strcmp(gp_cairo_enhanced_font,"Symbol")) {
1302 FPRINTF((stderr,"Parsing a Symbol string\n"));
1303
1304 enhanced_text_utf8 = gp_cairo_convert_symbol_to_unicode(plot, gp_cairo_enhanced_string);
1305
1306 if (!strcmp(plot->fontname,"Symbol")) {
1307 strncpy(gp_cairo_enhanced_font,
1308 plot->fontname,
1309 sizeof(gp_cairo_enhanced_font));
1310 } else {
1311 strncpy(gp_cairo_enhanced_font,
1312 gp_cairo_default_font(), sizeof(gp_cairo_enhanced_font));
1313 }
1314 symbol_font_parsed = TRUE;
1315 } else
1316 #endif /*MAP_SYMBOL*/
1317 {
1318 /* convert the input string to utf8 */
1319 enhanced_text_utf8 = gp_cairo_convert(plot, gp_cairo_enhanced_string);
1320 }
1321
1322 start = strlen(gp_cairo_utf8);
1323
1324 if (gp_cairo_enhanced_restore_now) {
1325 /* restore saved position */
1326 /* the idea is to use a space character, drawn with a negative width */
1327
1328 /* we first compute the size of the text drawn since the 'save' command */
1329
1330 /* Create a PangoLayout, set the font and text
1331 * with the saved attributes list, get extents */
1332 save_layout = gp_cairo_create_layout (plot->cr);
1333 pango_layout_set_text (save_layout, gp_cairo_save_utf8, -1);
1334 pango_layout_set_attributes (save_layout, gp_cairo_enhanced_save_AttrList);
1335 pango_layout_get_extents(save_layout, NULL, &save_logical_rect);
1336 g_clear_object (&save_layout);
1337
1338 pango_attr_list_unref( gp_cairo_enhanced_save_AttrList );
1339 gp_cairo_enhanced_save_AttrList = NULL;
1340
1341 /* invert the size, so we will go back to the saved state */
1342 save_logical_rect.width = -save_logical_rect.width;
1343 /* EAM FIXME: Zero height necessary but I don't understand why */
1344 save_logical_rect.height = 0;
1345 /* adding a blank character with the corresponding shape */
1346 gp_cairo_add_shape(save_logical_rect,start);
1347
1348 strncpy(gp_cairo_save_utf8, "", sizeof(gp_cairo_save_utf8));
1349 gp_cairo_enhanced_restore_now = FALSE;
1350 start++;
1351 }
1352
1353 if (gp_cairo_enhanced_overprint==2) {
1354 /* the idea is first to use a space character, drawn with an appropriate negative width */
1355
1356 /* we first compute the size of the text drawn since overprint==1 was used */
1357
1358 /* Create a PangoLayout, set the font and text with
1359 * the saved attributes list, get extents */
1360 underprinted_layout = gp_cairo_create_layout (plot->cr);
1361 pango_layout_set_text (underprinted_layout, gp_cairo_underprinted_utf8, -1);
1362 if (!gp_cairo_enhanced_underprinted_AttrList)
1363 fprintf(stderr,"uninitialized gp_cairo_enhanced_underprinted_AttrList!\n");
1364 else
1365 pango_layout_set_attributes (underprinted_layout, gp_cairo_enhanced_underprinted_AttrList);
1366 pango_layout_get_extents(underprinted_layout, NULL, &underprinted_logical_rect);
1367 g_clear_object (&underprinted_layout);
1368
1369 /* compute the size of the text to overprint*/
1370
1371 /* Create a PangoLayout, set the font and text */
1372 current_layout = gp_cairo_create_layout (plot->cr);
1373 pango_layout_set_text (current_layout, enhanced_text_utf8, -1);
1374 current_desc = pango_font_description_new ();
1375 pango_font_description_set_family (current_desc, gp_cairo_enhanced_get_fontname(plot));
1376 pango_font_description_set_size(current_desc,(int) gp_cairo_enhanced_fontsize*PANGO_SCALE);
1377 pango_font_description_set_weight (current_desc, plot->fontweight);
1378 pango_font_description_set_style (current_desc,
1379 plot->fontstyle ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
1380
1381 pango_layout_set_font_description (current_layout, current_desc);
1382 pango_font_description_free (current_desc);
1383 pango_layout_get_extents(current_layout, ¤t_ink_rect, ¤t_logical_rect);
1384 g_clear_object (¤t_layout);
1385
1386 /* calculate the distance to remove to center the overprinted text */
1387 underprinted_logical_rect.width = -(underprinted_logical_rect.width + current_logical_rect.width)/2;
1388 overprinted_width = current_logical_rect.width;
1389
1390 /* adding a blank character with the corresponding shape */
1391 gp_cairo_add_shape(underprinted_logical_rect, start);
1392
1393 strncpy(gp_cairo_underprinted_utf8, "", sizeof(gp_cairo_underprinted_utf8));
1394 /* increment the position as we added a character */
1395 start++;
1396 }
1397
1398 if (gp_cairo_enhanced_showflag) {
1399 strncat(gp_cairo_utf8, enhanced_text_utf8, sizeof(gp_cairo_utf8)-strlen(gp_cairo_utf8)-1);
1400 end = strlen(gp_cairo_utf8);
1401
1402 /* add text attributes to the main list */
1403 gp_cairo_add_attr(plot, gp_cairo_enhanced_AttrList, start, end);
1404
1405 } else {
1406 /* position must be modified, but text not actually drawn */
1407 /* the idea is to use a blank character, drawn with the width of the text*/
1408
1409 current_layout = gp_cairo_create_layout (plot->cr);
1410 pango_layout_set_text (current_layout, gp_cairo_utf8, -1);
1411 pango_layout_set_attributes (current_layout, gp_cairo_enhanced_AttrList);
1412 pango_layout_get_extents(current_layout, ¤t_ink_rect, ¤t_logical_rect);
1413 g_clear_object (¤t_layout);
1414
1415 /* we first compute the size of the text */
1416 /* Create a PangoLayout, set the font and text */
1417 hide_layout = gp_cairo_create_layout (plot->cr);
1418 pango_layout_set_text (hide_layout, enhanced_text_utf8, -1);
1419 hide_desc = pango_font_description_new ();
1420 pango_font_description_set_family (hide_desc, gp_cairo_enhanced_get_fontname(plot));
1421 pango_font_description_set_size(hide_desc,(int) gp_cairo_enhanced_fontsize*PANGO_SCALE);
1422 pango_font_description_set_weight (hide_desc, plot->fontweight);
1423 pango_font_description_set_style (hide_desc,
1424 plot->fontstyle ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
1425 pango_layout_set_font_description (hide_layout, hide_desc);
1426 pango_font_description_free (hide_desc);
1427
1428 pango_layout_get_extents(hide_layout, &hide_ink_rect, &hide_logical_rect);
1429 g_clear_object (&hide_layout);
1430
1431 /* rect.y must be reworked to take previous text into account, which may be smaller */
1432 /* hide_logical_rect.y is always initialized at zero, but should be : */
1433 if (current_logical_rect.height<hide_logical_rect.height)
1434 hide_logical_rect.y = current_logical_rect.height - hide_logical_rect.height;
1435
1436 /* adding a blank character with the corresponding shape */
1437 gp_cairo_add_shape(hide_logical_rect, start);
1438
1439 end = start+1; /* end *must* be defined, as it is used if widthflag is false */
1440 }
1441
1442 if (!gp_cairo_enhanced_widthflag) {
1443 /* the idea is to use a blank character, drawn with the inverted width of the text*/
1444 /* we first compute the size of the text */
1445
1446 /* Create a PangoLayout, set the font and text */
1447 zerowidth_layout = gp_cairo_create_layout (plot->cr);
1448 pango_layout_set_text (zerowidth_layout, enhanced_text_utf8, -1);
1449 zerowidth_desc = pango_font_description_new ();
1450 pango_font_description_set_family (zerowidth_desc, gp_cairo_enhanced_get_fontname(plot));
1451 pango_font_description_set_size(zerowidth_desc,(int) gp_cairo_enhanced_fontsize*PANGO_SCALE);
1452 pango_font_description_set_weight (zerowidth_desc, plot->fontweight);
1453 pango_font_description_set_style (zerowidth_desc,
1454 plot->fontstyle ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
1455 pango_layout_set_font_description (zerowidth_layout, zerowidth_desc);
1456 pango_font_description_free (zerowidth_desc);
1457 pango_layout_get_extents(zerowidth_layout, NULL, &zerowidth_logical_rect);
1458 g_clear_object (&zerowidth_layout);
1459
1460 /* invert the size, so we will go back to the start of the string */
1461 zerowidth_logical_rect.width = -zerowidth_logical_rect.width;
1462
1463 /* adding a blank character with the corresponding shape */
1464 gp_cairo_add_shape(zerowidth_logical_rect,end);
1465 end++;
1466 }
1467
1468 if (gp_cairo_enhanced_overprint==2) {
1469 /* revert the previous negative space to go back to starting point.
1470 * Take centered overprinted text width into account */
1471 underprinted_logical_rect.width = -underprinted_logical_rect.width - overprinted_width/2;
1472 /* adding a blank character with the corresponding shape */
1473 gp_cairo_add_shape(underprinted_logical_rect,end);
1474 }
1475
1476 if (gp_cairo_enhanced_save) /* we aim at restoring position later */ {
1477 save_start = strlen( gp_cairo_save_utf8);
1478 strncat(gp_cairo_save_utf8, enhanced_text_utf8, sizeof(gp_cairo_utf8)-strlen(gp_cairo_utf8)-1);
1479 save_end = strlen( gp_cairo_save_utf8);
1480
1481 /* add text attributes to the save list */
1482 gp_cairo_add_attr(plot, gp_cairo_enhanced_save_AttrList, save_start, save_end);
1483 }
1484
1485 if (gp_cairo_enhanced_overprint==1) /* save underprinted text with its attributes */{
1486 underprinted_start = strlen(gp_cairo_underprinted_utf8);
1487 strncat(gp_cairo_underprinted_utf8,
1488 enhanced_text_utf8,
1489 sizeof(gp_cairo_underprinted_utf8)-strlen(gp_cairo_underprinted_utf8)-1);
1490 underprinted_end = strlen(gp_cairo_underprinted_utf8);
1491
1492 if (gp_cairo_enhanced_underprinted_AttrList)
1493 pango_attr_list_unref( gp_cairo_enhanced_underprinted_AttrList );
1494 gp_cairo_enhanced_underprinted_AttrList = pango_attr_list_new();
1495
1496 /* add text attributes to the underprinted list */
1497 gp_cairo_add_attr(plot, gp_cairo_enhanced_underprinted_AttrList,
1498 underprinted_start, underprinted_end);
1499 }
1500
1501 #ifdef MAP_SYMBOL
1502 if (symbol_font_parsed)
1503 strncpy(gp_cairo_enhanced_font, "Symbol", sizeof(gp_cairo_enhanced_font));
1504 #endif /* MAP_SYMBOL */
1505
1506 g_free(enhanced_text_utf8);
1507 }
1508
1509 /* brace is TRUE to keep processing to },
1510 * FALSE to do one character only
1511 * fontname & fontsize are obvious
1512 * base is the current baseline
1513 * widthflag is TRUE if the width of this should count,
1514 * FALSE for zero width boxes
1515 * showflag is TRUE if this should be shown,
1516 * FALSE if it should not be shown (like TeX \phantom)
1517 * overprint is 0 for normal operation,
1518 * 1 for the underprinted text (included in width calculation),
1519 * 2 for the overprinted text (not included in width calc, through widhtflag=false),
1520 * (overprinted text is centered horizontally on underprinted text)
1521 * 3 means "save current position",
1522 * 4 means "restore saved position" */
gp_cairo_enhanced_open(plot_struct * plot,char * fontname,double fontsize,double base,TBOOLEAN widthflag,TBOOLEAN showflag,int overprint)1523 void gp_cairo_enhanced_open(plot_struct *plot, char* fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint)
1524 {
1525 if (overprint == 3) {
1526 gp_cairo_enhanced_save = TRUE;
1527 gp_cairo_enhanced_restore_now = FALSE;
1528 gp_cairo_enhanced_save_AttrList = pango_attr_list_new();
1529 return;
1530 }
1531
1532 if (overprint == 4) {
1533 gp_cairo_enhanced_save = FALSE;
1534 gp_cairo_enhanced_restore_now = TRUE;
1535 return;
1536 }
1537
1538 if (!gp_cairo_enhanced_opened_string) {
1539 // Strip off Bold or Italic and apply immediately
1540 // Is it really necessary to preserve plot->fontname?
1541 char *save_plot_font = strdup(plot->fontname);
1542 gp_cairo_set_font(plot, fontname, plot->fontsize);
1543 strncpy(gp_cairo_enhanced_font, plot->fontname, sizeof(gp_cairo_enhanced_font));
1544 strcpy(plot->fontname, save_plot_font);
1545 free(save_plot_font);
1546
1547 gp_cairo_enhanced_opened_string = TRUE;
1548 gp_cairo_enhanced_char = gp_cairo_enhanced_string;
1549 gp_cairo_enhanced_fontsize = fontsize*plot->oversampling_scale;
1550 gp_cairo_enhanced_base = base*plot->oversampling_scale;
1551 gp_cairo_enhanced_showflag = showflag;
1552 gp_cairo_enhanced_overprint = overprint;
1553 gp_cairo_enhanced_widthflag = widthflag;
1554 }
1555 }
1556
gp_cairo_enhanced_writec(plot_struct * plot,int character)1557 void gp_cairo_enhanced_writec(plot_struct *plot, int character)
1558 {
1559 *gp_cairo_enhanced_char++ = character;
1560 *gp_cairo_enhanced_char = '\0';
1561 }
1562
gp_cairo_enhanced_init(plot_struct * plot,int len)1563 void gp_cairo_enhanced_init(plot_struct *plot, int len)
1564 {
1565 /* begin by stroking any open path */
1566 gp_cairo_stroke(plot);
1567 /* also draw any open polygon set */
1568 gp_cairo_end_polygon(plot);
1569
1570
1571 gp_cairo_enhanced_string = (char*) malloc(len+1);
1572 gp_cairo_enhanced_opened_string = FALSE;
1573 gp_cairo_enhanced_overprint = FALSE;
1574 gp_cairo_enhanced_showflag = TRUE;
1575 gp_cairo_enhanced_fontsize = plot->fontsize*plot->oversampling_scale;
1576 strncpy(gp_cairo_enhanced_font, plot->fontname, sizeof(gp_cairo_enhanced_font));
1577 gp_cairo_enhanced_AttrList = pango_attr_list_new();
1578 }
1579
gp_cairo_enhanced_finish(plot_struct * plot,int x,int y)1580 void gp_cairo_enhanced_finish(plot_struct *plot, int x, int y)
1581 {
1582 PangoRectangle ink_rect, logical_rect;
1583 PangoLayout *layout;
1584 double vert_just, arg, enh_x, enh_y, delta, deltax, deltay;
1585 double box_x, box_y;
1586 int baseline_offset;
1587
1588 /* Create a PangoLayout, set the font and text */
1589 layout = gp_cairo_create_layout (plot->cr);
1590
1591 pango_layout_set_text (layout, gp_cairo_utf8, -1);
1592
1593 pango_layout_set_attributes (layout, gp_cairo_enhanced_AttrList);
1594
1595 pango_layout_get_extents(layout, &ink_rect, &logical_rect);
1596
1597 /* NB: See explanatory comments in gp_cairo_draw_text() */
1598 baseline_offset = pango_layout_get_baseline(layout) / PANGO_SCALE;
1599 vert_just = 0.5 * (float)(plot->fontsize * plot->oversampling_scale);
1600 vert_just = baseline_offset - vert_just;
1601
1602 arg = plot->text_angle * M_PI/180;
1603 enh_x = x - vert_just * sin(arg);
1604 enh_y = y - vert_just * cos(arg);
1605
1606 delta = ((double)logical_rect.width/2) / PANGO_SCALE;
1607
1608 deltax = delta * cos(arg);
1609 deltay = delta * sin(arg);
1610
1611 switch (plot->justify_mode) {
1612 case LEFT :
1613 break;
1614 case CENTRE :
1615 enh_x -= deltax;
1616 enh_y += deltay;
1617 break;
1618 case RIGHT :
1619 enh_x -= 2*deltax;
1620 enh_y += 2*deltay;
1621 break;
1622 }
1623
1624 cairo_save(plot->cr);
1625 cairo_translate(plot->cr, enh_x, enh_y);
1626 cairo_rotate(plot->cr, -arg);
1627
1628 cairo_set_source_rgba(plot->cr, plot->color.r, plot->color.g, plot->color.b,
1629 1. - plot->color.alpha);
1630 /* Inform Pango to re-layout the text with the new transformation */
1631 pango_cairo_update_layout (plot->cr, layout);
1632 pango_cairo_show_layout (plot->cr, layout);
1633 /* pango_cairo_show_layout does not clear the path (here a starting point)
1634 * Do it by ourselves, or we can get spurious lines on future calls. */
1635 cairo_new_path(plot->cr);
1636
1637 #ifdef EAM_BOXED_TEXT
1638 if (in_textbox) {
1639 box_rotation = -arg;
1640 box_origin_x = x;
1641 box_origin_y = y;
1642 box_y = box_origin_y - vert_just;
1643 switch (plot->justify_mode) {
1644 case LEFT:
1645 box_x = box_origin_x;
1646 break;
1647 default:
1648 case CENTRE:
1649 box_x = box_origin_x - delta;
1650 break;
1651 case RIGHT:
1652 box_x = box_origin_x - 2*delta;
1653 break;
1654 }
1655
1656 /* Update bounding box for boxed label text */
1657 pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
1658
1659 /* Auto-initialization */
1660 if (bounding_box[0] < 0 && bounding_box[1] < 0) {
1661 bounding_box[0] = bounding_box[2] = box_x;
1662 bounding_box[1] = bounding_box[3] = box_y;
1663 }
1664 if (bounding_box[0] > box_x + ink_rect.x)
1665 bounding_box[0] = box_x + ink_rect.x;
1666 if (bounding_box[2] < box_x + ink_rect.x + ink_rect.width)
1667 bounding_box[2] = box_x + ink_rect.x + ink_rect.width;
1668 if (bounding_box[1] > box_y + ink_rect.y)
1669 bounding_box[1] = box_y + ink_rect.y;
1670 if (bounding_box[3] < box_y + ink_rect.y + ink_rect.height)
1671 bounding_box[3] = box_y + ink_rect.y + ink_rect.height;
1672 }
1673 #endif
1674
1675 /* free the layout object */
1676 pango_attr_list_unref( gp_cairo_enhanced_AttrList );
1677 gp_cairo_enhanced_AttrList = NULL;
1678 g_clear_object (&layout);
1679 cairo_restore(plot->cr);
1680 strncpy(gp_cairo_utf8, "", sizeof(gp_cairo_utf8));
1681 free(gp_cairo_enhanced_string);
1682 }
1683
1684 /* obtain the right pattern or solid fill from fillstyle and fillpar.
1685 * Used to draw fillboxes and polygons */
gp_cairo_fill(plot_struct * plot,int fillstyle,int fillpar)1686 void gp_cairo_fill(plot_struct *plot, int fillstyle, int fillpar)
1687 {
1688 double red = 0, green = 0, blue = 0, fact = 0;
1689
1690 switch (fillstyle) {
1691 case FS_SOLID: /* solid fill */
1692 if (plot->color.alpha > 0) {
1693 fillpar = 100. * (1. - plot->color.alpha);
1694 /* Fall through to FS_TRANSPARENT_SOLID */
1695 } else if (fillpar==100)
1696 /* treated as a special case to accelerate common situation */ {
1697 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
1698 FPRINTF((stderr,"solid %lf %lf %lf\n",plot->color.r, plot->color.g, plot->color.b));
1699 return;
1700 } else {
1701 red = plot->color.r;
1702 green = plot->color.g;
1703 blue = plot->color.b;
1704
1705 fact = (double)(100 - fillpar) /100;
1706
1707 if (fact >= 0 && fact <= 1) {
1708 red += (1 - red) * fact;
1709 green += (1 - green) * fact;
1710 blue += (1 - blue) * fact;
1711 }
1712 cairo_set_source_rgb(plot->cr, red, green, blue);
1713 FPRINTF((stderr,"transparent solid %lf %lf %lf\n",red, green, blue));
1714 return;
1715 }
1716 case FS_TRANSPARENT_SOLID:
1717 red = plot->color.r;
1718 green = plot->color.g;
1719 blue = plot->color.b;
1720 cairo_set_source_rgba(plot->cr, red, green, blue, (double)fillpar/100.);
1721 return;
1722 case FS_PATTERN: /* pattern fill */
1723 case FS_TRANSPARENT_PATTERN:
1724 gp_cairo_fill_pattern(plot, fillstyle, fillpar);
1725 FPRINTF((stderr,"pattern fillpar = %d %lf %lf %lf\n",fillpar, plot->color.r, plot->color.g, plot->color.b));
1726 return;
1727 case FS_EMPTY: /* fill with background plot->color */
1728 cairo_set_source_rgb(plot->cr, plot->background.r, plot->background.g, plot->background.b);
1729 FPRINTF((stderr,"empty\n"));
1730 return;
1731 default:
1732 cairo_set_source_rgb(plot->cr, plot->color.r, plot->color.g, plot->color.b);
1733 FPRINTF((stderr,"default %lf %lf %lf\n",plot->color.r, plot->color.g, plot->color.b));
1734 return;
1735 }
1736 }
1737
1738 #ifdef EAM_BOXED_TEXT
gp_cairo_boxed_text(plot_struct * plot,int x,int y,int option)1739 void gp_cairo_boxed_text(plot_struct *plot, int x, int y, int option)
1740 {
1741 int dx, dy;
1742
1743 switch (option) {
1744 case TEXTBOX_INIT:
1745 /* Initialize bounding box for this text string */
1746 bounding_box[0] = bounding_box[2] = x;
1747 bounding_box[1] = bounding_box[3] = y;
1748 in_textbox = TRUE;
1749 break;
1750
1751 case TEXTBOX_OUTLINE:
1752 /* Stroke the outline of the bounding box for previous text */
1753 case TEXTBOX_BACKGROUNDFILL:
1754 case TEXTBOX_GREY:
1755 /* Fill the bounding box with background color */
1756 /* begin by stroking any open path */
1757 gp_cairo_stroke(plot);
1758 gp_cairo_end_polygon(plot);
1759
1760 cairo_save(plot->cr);
1761
1762 /* In progress: textbox rotation
1763 * 1) translate to text origin
1764 * 2) substract translation from bounding box
1765 * 3) rotate about new origin
1766 * 4) stroke/fill
1767 */
1768 cairo_translate(plot->cr, box_origin_x, box_origin_y);
1769 cairo_rotate(plot->cr, box_rotation);
1770 cairo_translate(plot->cr, -box_origin_x, -box_origin_y);
1771
1772 dx = 0.25 * bounding_xmargin * (float)(plot->fontsize * plot->oversampling_scale);
1773 dy = 0.25 * bounding_ymargin * (float)(plot->fontsize * plot->oversampling_scale);
1774 if (option == TEXTBOX_GREY)
1775 dy = 0;
1776 gp_cairo_move(plot, bounding_box[0]-dx, bounding_box[1]-dy);
1777 gp_cairo_vector(plot, bounding_box[0]-dx, bounding_box[3]+dy);
1778 gp_cairo_vector(plot, bounding_box[2]+dx, bounding_box[3]+dy);
1779 gp_cairo_vector(plot, bounding_box[2]+dx, bounding_box[1]-dy);
1780 gp_cairo_vector(plot, bounding_box[0]+dx, bounding_box[1]-dy);
1781 cairo_close_path(plot->cr);
1782 if (option == TEXTBOX_BACKGROUNDFILL) {
1783 cairo_set_source_rgba(plot->cr, plot->color.r, plot->color.g,
1784 plot->color.b, 1. - plot->color.alpha);
1785 cairo_fill(plot->cr);
1786 } else if (option == TEXTBOX_GREY) {
1787 cairo_set_source_rgba(plot->cr, 0.75, 0.75, 0.75, 0.50);
1788 cairo_fill(plot->cr);
1789 } else { /* option == TEXTBOX_OUTLINE */
1790 cairo_set_line_width(plot->cr,
1791 0.5*plot->linewidth*plot->oversampling_scale);
1792 cairo_set_source_rgba(plot->cr, plot->color.r, plot->color.g,
1793 plot->color.b, 1. - plot->color.alpha);
1794 cairo_stroke(plot->cr);
1795 }
1796
1797 cairo_restore(plot->cr);
1798 in_textbox = FALSE;
1799 break;
1800
1801 case TEXTBOX_MARGINS: /* Change the margin between text and box */
1802 bounding_xmargin = (double)x/100.;
1803 bounding_ymargin = (double)y/100.;
1804 break;
1805
1806 default:
1807 break;
1808 }
1809 }
1810 #endif
1811
1812 #define PATTERN_SIZE 8
1813
1814 /* return a pattern used for fillboxes and polygons */
gp_cairo_fill_pattern(plot_struct * plot,int fillstyle,int fillpar)1815 void gp_cairo_fill_pattern(plot_struct *plot, int fillstyle, int fillpar)
1816 {
1817 cairo_surface_t *pattern_surface;
1818 cairo_t *pattern_cr;
1819 cairo_pattern_t *pattern;
1820 cairo_matrix_t context_matrix;
1821 cairo_matrix_t matrix;
1822
1823 pattern_surface = cairo_surface_create_similar(cairo_get_target(plot->cr),
1824 CAIRO_CONTENT_COLOR_ALPHA,
1825 PATTERN_SIZE,
1826 PATTERN_SIZE);
1827 pattern_cr = cairo_create(pattern_surface);
1828
1829 cairo_matrix_init_scale(&context_matrix,
1830 PATTERN_SIZE,
1831 PATTERN_SIZE);
1832 cairo_set_matrix(pattern_cr,&context_matrix);
1833
1834 if (fillstyle == FS_TRANSPARENT_PATTERN)
1835 cairo_set_source_rgba( pattern_cr, 1.0, 1.0, 1.0, 0.0);
1836 else
1837 cairo_set_source_rgb( pattern_cr, 1.0, 1.0, 1.0);
1838
1839 cairo_paint(pattern_cr);
1840
1841 if (!strcmp(term->name,"pdfcairo")) /* Work-around for poor scaling in cairo */
1842 cairo_set_line_width(pattern_cr, PATTERN_SIZE/150.);
1843 else
1844 cairo_set_line_width(pattern_cr, PATTERN_SIZE/50.);
1845 cairo_set_line_cap (pattern_cr, CAIRO_LINE_CAP_BUTT);
1846 cairo_set_source_rgb(pattern_cr, plot->color.r, plot->color.g, plot->color.b);
1847
1848 switch (fillpar%8) {
1849 case 0: /* no fill */
1850 default:
1851 break;
1852 case 1: /* cross-hatch */
1853 case 2: /* double cross-hatch */
1854 cairo_move_to(pattern_cr, 0,0);
1855 cairo_line_to(pattern_cr, 1.0,1.0);
1856 cairo_stroke(pattern_cr);
1857 cairo_move_to(pattern_cr, 0,1.0);
1858 cairo_line_to(pattern_cr, 1.0,0);
1859 cairo_stroke(pattern_cr);
1860 break;
1861 case 3: /* solid */
1862 cairo_paint(pattern_cr);
1863 break;
1864 case 4: /* diagonal hatch */
1865 case 5:
1866 case 6:
1867 case 7:
1868 cairo_move_to(pattern_cr, 0.5,0.);
1869 cairo_line_to(pattern_cr, 0.5,1.);
1870 cairo_stroke(pattern_cr);
1871 break;
1872 }
1873
1874 pattern = cairo_pattern_create_for_surface( pattern_surface );
1875 cairo_pattern_set_extend( pattern, CAIRO_EXTEND_REPEAT );
1876
1877 /* compensate the transformation matrix of the main context */
1878 cairo_matrix_init_scale(&matrix,
1879 1.0/plot->oversampling_scale,
1880 1.0/plot->oversampling_scale);
1881
1882 switch (fillpar%8) {
1883 case 0: /* no fill */
1884 case 1: /* cross-hatch */
1885 case 3: /* solid */
1886 default:
1887 break;
1888 case 2: /* double cross-hatch */
1889 cairo_matrix_scale( &matrix, 2.,2.);
1890 break;
1891 case 4: /* diagonal hatch */
1892 cairo_matrix_rotate( &matrix, M_PI/4);
1893 break;
1894 case 5:
1895 cairo_matrix_rotate( &matrix, -M_PI/4);
1896 break;
1897 case 6:
1898 cairo_matrix_rotate( &matrix, M_PI/4);
1899 cairo_matrix_scale( &matrix, 2.,2.);
1900 break;
1901 case 7:
1902 cairo_matrix_rotate( &matrix, -M_PI/4);
1903 cairo_matrix_scale( &matrix, 2.,2.);
1904 break;
1905 }
1906
1907 cairo_pattern_set_matrix(pattern,&matrix);
1908
1909 cairo_destroy( pattern_cr );
1910 cairo_set_source( plot->cr, pattern );
1911 cairo_pattern_destroy( pattern );
1912 cairo_surface_destroy( pattern_surface );
1913 }
1914
1915
1916 /* Sets term vars v_char, h_char, v_tic, h_tic
1917 * Depends on plot->fontsize and fontname */
gp_cairo_set_termvar(plot_struct * plot,unsigned int * v_char,unsigned int * h_char)1918 void gp_cairo_set_termvar(plot_struct *plot, unsigned int *v_char,
1919 unsigned int *h_char)
1920 {
1921 PangoLayout *layout;
1922 PangoFontDescription *desc;
1923 PangoRectangle ink_rect;
1924 PangoRectangle logical_rect;
1925 unsigned int tmp_v_char, tmp_h_char;
1926
1927 /* Create a PangoLayout, set the font and text */
1928 layout = gp_cairo_create_layout (plot->cr);
1929 pango_layout_set_text (layout, "0123456789", -1);
1930 desc = pango_font_description_new ();
1931 pango_font_description_set_family (desc, plot->fontname);
1932 pango_font_description_set_size(desc,(int) (plot->fontsize*PANGO_SCALE*plot->oversampling_scale));
1933 pango_font_description_set_weight (desc, plot->fontweight);
1934 pango_font_description_set_style (desc,
1935 plot->fontstyle ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
1936 pango_layout_set_font_description (layout, desc);
1937 pango_font_description_free (desc);
1938 pango_layout_get_extents(layout, &ink_rect, &logical_rect);
1939 g_clear_object (&layout);
1940
1941 /* we don't use gnuplot_x() and gnuplot_y() in the following
1942 * as the scale should have just been updated to 1.
1943 * Although PANGO works with integer, it scales them via a huge number (usually ~1000).
1944 * That's why I use ceil() instead of direct division result */
1945 tmp_v_char = (int) ceil( (double) logical_rect.height/PANGO_SCALE) - 1;
1946 tmp_h_char = (int) ceil( (double) logical_rect.width/(10*PANGO_SCALE));
1947
1948 if (v_char)
1949 *v_char = tmp_v_char;
1950 if (h_char)
1951 *h_char = tmp_h_char;
1952
1953 /* FIXME!!! So far, so good. But now we have a problem. This routine */
1954 /* is called synchronously with the set_font command, but avg_vchar is */
1955 /* needed asynchronously during execution of the display list. */
1956 avg_vchar = tmp_v_char;
1957 }
1958
gp_cairo_solid_background(plot_struct * plot)1959 void gp_cairo_solid_background(plot_struct *plot)
1960 {
1961 if (cairo_status (plot->cr)) {
1962 fprintf(stderr, "Cairo is unhappy: %s\n",
1963 cairo_status_to_string (cairo_status (plot->cr)));
1964 gp_exit(EXIT_FAILURE);
1965 }
1966 cairo_set_source_rgb(plot->cr, plot->background.r, plot->background.g, plot->background.b);
1967 cairo_paint(plot->cr);
1968 }
1969
gp_cairo_clear_background(plot_struct * plot)1970 void gp_cairo_clear_background(plot_struct *plot)
1971 {
1972 if (cairo_status (plot->cr)) {
1973 fprintf(stderr, "Cairo is unhappy: %s\n",
1974 cairo_status_to_string (cairo_status (plot->cr)));
1975 gp_exit(EXIT_FAILURE);
1976 }
1977 cairo_set_source_rgba(plot->cr, 0.0, 0.0, 0.0, 0.0);
1978 cairo_paint(plot->cr);
1979 }
1980
1981 /*----------------------------------------------------------------------------
1982 font functions
1983 ----------------------------------------------------------------------------*/
1984
1985
1986 /* in enhanced text mode, look if enhanced mode has set the font,
1987 * otherwise return the default */
gp_cairo_enhanced_get_fontname(plot_struct * plot)1988 const char* gp_cairo_enhanced_get_fontname(plot_struct *plot)
1989 {
1990 if ( strlen(gp_cairo_enhanced_font)==0 )
1991 return plot->fontname;
1992 else
1993 return gp_cairo_enhanced_font;
1994 }
1995
1996 /* BM: New function to determine the default font.
1997 * On Windows, the "Sans" alias normally is equivalent to
1998 * "Tahoma" but the resolution fails on some systems. */
1999 const char *
gp_cairo_default_font(void)2000 gp_cairo_default_font(void)
2001 {
2002 #ifdef WIN32
2003 return "Tahoma";
2004 #else
2005 return "Sans";
2006 #endif
2007 }
2008
2009 /*----------------------------------------------------------------------------
2010 coordinates functions
2011 ----------------------------------------------------------------------------*/
2012
2013 #define OFFSET 0
2014
device_x(plot_struct * plot,double x)2015 double device_x(plot_struct *plot, double x)
2016 {
2017 double scaled_x;
2018 scaled_x = plot->xscale*x/plot->oversampling_scale ;
2019 return scaled_x + OFFSET;
2020 }
2021
device_y(plot_struct * plot,double y)2022 double device_y(plot_struct *plot, double y)
2023 {
2024 double scaled_and_mirrored_y;
2025 scaled_and_mirrored_y = (plot->ymax - y)*plot->yscale/plot->oversampling_scale;
2026 return scaled_and_mirrored_y + OFFSET;
2027 }
2028
gnuplot_x(plot_struct * plot,double x)2029 double gnuplot_x(plot_struct *plot, double x)
2030 {
2031 double scaled_x;
2032 scaled_x = (x + OFFSET)/plot->xscale*plot->oversampling_scale ;
2033 return scaled_x;
2034 }
2035
gnuplot_y(plot_struct * plot,double y)2036 double gnuplot_y(plot_struct *plot, double y)
2037 {
2038 double scaled_and_mirrored_y;
2039 scaled_and_mirrored_y = plot->ymax +(-y + OFFSET)/plot->yscale*plot->oversampling_scale;
2040 return scaled_and_mirrored_y;
2041 }
2042
2043
2044 /* return the charset as a string accepted by glib routines,
2045 * default to the locale charset,
2046 * the returned char* doesn't have to be freed. */
gp_cairo_get_encoding(plot_struct * plot)2047 const char* gp_cairo_get_encoding(plot_struct *plot)
2048 {
2049 const char * charset;
2050
2051 switch (plot->encoding) {
2052 case S_ENC_ISO8859_2 : return "ISO-8859-2";
2053 case S_ENC_ISO8859_15 : return "ISO-8859-15";
2054 case S_ENC_CP437 : return "cp437";
2055 case S_ENC_CP850 : return "cp850";
2056 case S_ENC_CP852 : return "cp852";
2057 case S_ENC_CP1250 : return "windows-1250";
2058 case S_ENC_CP1252 : return "windows-1252";
2059 case S_ENC_KOI8_R : return "KOI8-R";
2060 case S_ENC_KOI8_U : return "KOI8-U";
2061 case S_ENC_ISO8859_1 : return "ISO-8859-1";
2062 case S_ENC_UTF8 : return "UTF-8";
2063 case S_ENC_DEFAULT :
2064 case S_ENC_INVALID :
2065 default :
2066 g_get_charset(&charset);
2067 return charset;
2068 }
2069 }
2070
2071 /* Symbol font handling.
2072 * To ensure compatibility with other terminals,
2073 * use the map provided by http://www.unicode.org/ to
2074 * translate character codes to their unicode counterparts.
2075 * The returned string has te be freed by the calling function. */
gp_cairo_convert_symbol_to_unicode(plot_struct * plot,const char * string)2076 gchar* gp_cairo_convert_symbol_to_unicode(plot_struct *plot, const char* string)
2077 {
2078 gchar *string_utf8;
2079 gchar *output;
2080 gchar *iter;
2081 gchar *iter_mod;
2082 int i;
2083 int imax;
2084 GError *error = NULL;
2085
2086 /* first step, get a valid utf8 string, without taking care of Symbol.
2087 * The input string is likely to be encoded in iso_8859_1, with characters
2088 * going from 1 to 255. Try this first. If it's not the case, fall back to
2089 * routine based on the encoding variable. */
2090 string_utf8 = g_convert(string, -1, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
2091 if (error != NULL) {
2092 fprintf(stderr,"Symbol font : fallback to iso_8859_1 did not work\n");
2093 g_error_free(error);
2094 string_utf8 = gp_cairo_convert(plot, string);
2095 }
2096
2097 iter = string_utf8;
2098 /* Assume that the output string in utf8 won't use more than 8 bytes per character/
2099 * The utf8 specification fixes the limit to 4 bytes per character, but here we can also
2100 * composite two characters */
2101 output = (gchar*) gp_alloc((4*strlen(string)+1)*sizeof(gchar),"Symbol to unicode");
2102 iter_mod = output;
2103 imax = g_utf8_strlen(string_utf8,-1) + 1;
2104
2105 for (i=0; i<imax; ++i) {
2106 switch(g_utf8_get_char(iter)) {
2107 #define SYMB_UNICODE(symbol_char,unicode) case symbol_char : g_unichar_to_utf8(unicode, iter_mod); break;
2108 /* not modifying ASCII characters */
2109 /* SYMB_UNICODE(0x20,0x0020); */ /* SPACE */
2110 /* SYMB_UNICODE(0x21,0x0021); */ /* EXCLAMATION MARK */
2111 SYMB_UNICODE(0x22,0x2200); /* FOR ALL */
2112 /* SYMB_UNICODE(0x23,0x0023); */ /* NUMBER SIGN */
2113 SYMB_UNICODE(0x24,0x2203); /* THERE EXISTS */
2114 /* SYMB_UNICODE(0x25,0x0025); */ /* PERCENT SIGN */
2115 /* SYMB_UNICODE(0x26,0x0026); */ /* AMPERSAND */
2116 SYMB_UNICODE(0x27,0x220D); /* SMALL CONTAINS AS MEMBER */
2117 /* SYMB_UNICODE(0x28,0x0028); */ /* LEFT PARENTHESIS */
2118 /* SYMB_UNICODE(0x29,0x0029); */ /* RIGHT PARENTHESIS */
2119 /* SYMB_UNICODE(0x2A,0x2217); */ /* ASTERISK OPERATOR */
2120 /* SYMB_UNICODE(0x2B,0x002B); */ /* PLUS SIGN */
2121 /* SYMB_UNICODE(0x2C,0x002C); */ /* COMMA */
2122 /* SYMB_UNICODE(0x2D,0x2212); */ /* MINUS SIGN */
2123 /* SYMB_UNICODE(0x2E,0x002E); */ /* FULL STOP */
2124 /* SYMB_UNICODE(0x2F,0x002F); */ /* SOLIDUS */
2125 /* SYMB_UNICODE(0x30,0x0030); */ /* DIGIT ZERO */
2126 /* SYMB_UNICODE(0x31,0x0031); */ /* DIGIT ONE */
2127 /* SYMB_UNICODE(0x32,0x0032); */ /* DIGIT TWO */
2128 /* SYMB_UNICODE(0x33,0x0033); */ /* DIGIT THREE */
2129 /* SYMB_UNICODE(0x34,0x0034); */ /* DIGIT FOUR */
2130 /* SYMB_UNICODE(0x35,0x0035); */ /* DIGIT FIVE */
2131 /* SYMB_UNICODE(0x36,0x0036); */ /* DIGIT SIX */
2132 /* SYMB_UNICODE(0x37,0x0037); */ /* DIGIT SEVEN */
2133 /* SYMB_UNICODE(0x38,0x0038); */ /* DIGIT EIGHT */
2134 /* SYMB_UNICODE(0x39,0x0039); */ /* DIGIT NINE */
2135 /* SYMB_UNICODE(0x3A,0x003A); */ /* COLON */
2136 /* SYMB_UNICODE(0x3B,0x003B); */ /* SEMICOLON */
2137 /* SYMB_UNICODE(0x3C,0x003C); */ /* LESS-THAN SIGN */
2138 /* SYMB_UNICODE(0x3D,0x003D); */ /* EQUALS SIGN */
2139 /* SYMB_UNICODE(0x3E,0x003E); */ /* GREATER-THAN SIGN */
2140 /* SYMB_UNICODE(0x3F,0x003F); */ /* QUESTION MARK */
2141 SYMB_UNICODE(0x40,0x2245); /* APPROXIMATELY EQUAL TO */
2142 SYMB_UNICODE(0x41,0x0391); /* GREEK CAPITAL LETTER ALPHA */
2143 SYMB_UNICODE(0x42,0x0392); /* GREEK CAPITAL LETTER BETA */
2144 SYMB_UNICODE(0x43,0x03A7); /* GREEK CAPITAL LETTER CHI */
2145 SYMB_UNICODE(0x44,0x0394); /* GREEK CAPITAL LETTER DELTA */
2146 SYMB_UNICODE(0x45,0x0395); /* GREEK CAPITAL LETTER EPSILON */
2147 SYMB_UNICODE(0x46,0x03A6); /* GREEK CAPITAL LETTER PHI */
2148 SYMB_UNICODE(0x47,0x0393); /* GREEK CAPITAL LETTER GAMMA */
2149 SYMB_UNICODE(0x48,0x0397); /* GREEK CAPITAL LETTER ETA */
2150 SYMB_UNICODE(0x49,0x0399); /* GREEK CAPITAL LETTER IOTA */
2151 SYMB_UNICODE(0x4A,0x03D1); /* GREEK THETA SYMBOL */
2152 SYMB_UNICODE(0x4B,0x039A); /* GREEK CAPITAL LETTER KAPPA */
2153 SYMB_UNICODE(0x4C,0x039B); /* GREEK CAPITAL LETTER LAMDA */
2154 SYMB_UNICODE(0x4D,0x039C); /* GREEK CAPITAL LETTER MU */
2155 SYMB_UNICODE(0x4E,0x039D); /* GREEK CAPITAL LETTER NU */
2156 SYMB_UNICODE(0x4F,0x039F); /* GREEK CAPITAL LETTER OMICRON */
2157 SYMB_UNICODE(0x50,0x03A0); /* GREEK CAPITAL LETTER PI */
2158 SYMB_UNICODE(0x51,0x0398); /* GREEK CAPITAL LETTER THETA */
2159 SYMB_UNICODE(0x52,0x03A1); /* GREEK CAPITAL LETTER RHO */
2160 SYMB_UNICODE(0x53,0x03A3); /* GREEK CAPITAL LETTER SIGMA */
2161 SYMB_UNICODE(0x54,0x03A4); /* GREEK CAPITAL LETTER TAU */
2162 SYMB_UNICODE(0x55,0x03A5); /* GREEK CAPITAL LETTER UPSILON */
2163 SYMB_UNICODE(0x56,0x03C2); /* GREEK SMALL LETTER FINAL SIGMA */
2164 SYMB_UNICODE(0x57,0x03A9); /* GREEK CAPITAL LETTER OMEGA */
2165 SYMB_UNICODE(0x58,0x039E); /* GREEK CAPITAL LETTER XI */
2166 SYMB_UNICODE(0x59,0x03A8); /* GREEK CAPITAL LETTER PSI */
2167 SYMB_UNICODE(0x5A,0x0396); /* GREEK CAPITAL LETTER ZETA */
2168 SYMB_UNICODE(0x5B,0x005B); /* LEFT SQUARE BRACKET */
2169 SYMB_UNICODE(0x5C,0x2234); /* THEREFORE */
2170 SYMB_UNICODE(0x5D,0x005D); /* RIGHT SQUARE BRACKET */
2171 SYMB_UNICODE(0x5E,0x22A5); /* UP TACK */
2172 SYMB_UNICODE(0x5F,0x005F); /* LOW LINE */
2173 SYMB_UNICODE(0x60,0xF8E5); /* radical extender corporate char */
2174 SYMB_UNICODE(0x61,0x03B1); /* GREEK SMALL LETTER ALPHA */
2175 SYMB_UNICODE(0x62,0x03B2); /* GREEK SMALL LETTER BETA */
2176 SYMB_UNICODE(0x63,0x03C7); /* GREEK SMALL LETTER CHI */
2177 SYMB_UNICODE(0x64,0x03B4); /* GREEK SMALL LETTER DELTA */
2178 SYMB_UNICODE(0x65,0x03B5); /* GREEK SMALL LETTER EPSILON */
2179 SYMB_UNICODE(0x66,0x03C6); /* GREEK SMALL LETTER PHI */
2180 SYMB_UNICODE(0x67,0x03B3); /* GREEK SMALL LETTER GAMMA */
2181 SYMB_UNICODE(0x68,0x03B7); /* GREEK SMALL LETTER ETA */
2182 SYMB_UNICODE(0x69,0x03B9); /* GREEK SMALL LETTER IOTA */
2183 SYMB_UNICODE(0x6A,0x03D5); /* GREEK PHI SYMBOL */
2184 SYMB_UNICODE(0x6B,0x03BA); /* GREEK SMALL LETTER KAPPA */
2185 SYMB_UNICODE(0x6C,0x03BB); /* GREEK SMALL LETTER LAMDA */
2186 /* SYMB_UNICODE(0x6D,0x03BC); */ /* GREEK SMALL LETTER MU */
2187 SYMB_UNICODE(0x6D,0x00B5); /* GREEK SMALL LETTER MU */
2188 SYMB_UNICODE(0x6E,0x03BD); /* GREEK SMALL LETTER NU */
2189 SYMB_UNICODE(0x6F,0x03BF); /* GREEK SMALL LETTER OMICRON */
2190 SYMB_UNICODE(0x70,0x03C0); /* GREEK SMALL LETTER PI */
2191 SYMB_UNICODE(0x71,0x03B8); /* GREEK SMALL LETTER THETA */
2192 SYMB_UNICODE(0x72,0x03C1); /* GREEK SMALL LETTER RHO */
2193 SYMB_UNICODE(0x73,0x03C3); /* GREEK SMALL LETTER SIGMA */
2194 SYMB_UNICODE(0x74,0x03C4); /* GREEK SMALL LETTER TAU */
2195 SYMB_UNICODE(0x75,0x03C5); /* GREEK SMALL LETTER UPSILON */
2196 SYMB_UNICODE(0x76,0x03D6); /* GREEK PI SYMBOL */
2197 SYMB_UNICODE(0x77,0x03C9); /* GREEK SMALL LETTER OMEGA */
2198 SYMB_UNICODE(0x78,0x03BE); /* GREEK SMALL LETTER XI */
2199 SYMB_UNICODE(0x79,0x03C8); /* GREEK SMALL LETTER PSI */
2200 SYMB_UNICODE(0x7A,0x03B6); /* GREEK SMALL LETTER ZETA */
2201 SYMB_UNICODE(0x7B,0x007B); /* LEFT CURLY BRACKET */
2202 SYMB_UNICODE(0x7C,0x007C); /* VERTICAL LINE */
2203 SYMB_UNICODE(0x7D,0x007D); /* RIGHT CURLY BRACKET */
2204 SYMB_UNICODE(0x7E,0x223C); /* TILDE OPERATOR */
2205
2206 SYMB_UNICODE(0xA0,0x20AC); /* EURO SIGN */
2207 SYMB_UNICODE(0xA1,0x03D2); /* GREEK UPSILON WITH HOOK SYMBOL */
2208 SYMB_UNICODE(0xA2,0x2032); /* PRIME minute */
2209 SYMB_UNICODE(0xA3,0x2264); /* LESS-THAN OR EQUAL TO */
2210 SYMB_UNICODE(0xA4,0x2044); /* FRACTION SLASH */
2211 SYMB_UNICODE(0xA5,0x221E); /* INFINITY */
2212 SYMB_UNICODE(0xA6,0x0192); /* LATIN SMALL LETTER F WITH HOOK */
2213 SYMB_UNICODE(0xA7,0x2663); /* BLACK CLUB SUIT */
2214 SYMB_UNICODE(0xA8,0x2666); /* BLACK DIAMOND SUIT */
2215 SYMB_UNICODE(0xA9,0x2665); /* BLACK HEART SUIT */
2216 SYMB_UNICODE(0xAA,0x2660); /* BLACK SPADE SUIT */
2217 SYMB_UNICODE(0xAB,0x2194); /* LEFT RIGHT ARROW */
2218 SYMB_UNICODE(0xAC,0x2190); /* LEFTWARDS ARROW */
2219 SYMB_UNICODE(0xAD,0x2191); /* UPWARDS ARROW */
2220 SYMB_UNICODE(0xAE,0x2192); /* RIGHTWARDS ARROW */
2221 SYMB_UNICODE(0xAF,0x2193); /* DOWNWARDS ARROW */
2222 SYMB_UNICODE(0xB0,0x00B0); /* DEGREE SIGN */
2223 SYMB_UNICODE(0xB1,0x00B1); /* PLUS-MINUS SIGN */
2224 SYMB_UNICODE(0xB2,0x2033); /* DOUBLE PRIME second */
2225 SYMB_UNICODE(0xB3,0x2265); /* GREATER-THAN OR EQUAL TO */
2226 SYMB_UNICODE(0xB4,0x00D7); /* MULTIPLICATION SIGN */
2227 SYMB_UNICODE(0xB5,0x221D); /* PROPORTIONAL TO */
2228 SYMB_UNICODE(0xB6,0x2202); /* PARTIAL DIFFERENTIAL */
2229 SYMB_UNICODE(0xB7,0x2022); /* BULLET */
2230 SYMB_UNICODE(0xB8,0x00F7); /* DIVISION SIGN */
2231 SYMB_UNICODE(0xB9,0x2260); /* NOT EQUAL TO */
2232 SYMB_UNICODE(0xBA,0x2261); /* IDENTICAL TO */
2233 SYMB_UNICODE(0xBB,0x2248); /* ALMOST EQUAL TO */
2234 SYMB_UNICODE(0xBC,0x2026); /* HORIZONTAL ELLIPSIS */
2235 SYMB_UNICODE(0xBD,0x23D0); /* VERTICAL LINE EXTENSION (for arrows) */
2236 SYMB_UNICODE(0xBE,0x23AF); /* HORIZONTAL LINE EXTENSION (for arrows) */
2237 SYMB_UNICODE(0xBF,0x21B5); /* DOWNWARDS ARROW WITH CORNER LEFTWARDS */
2238 SYMB_UNICODE(0xC0,0x2135); /* ALEF SYMBOL */
2239 SYMB_UNICODE(0xC1,0x2111); /* BLACK-LETTER CAPITAL I */
2240 SYMB_UNICODE(0xC2,0x211C); /* BLACK-LETTER CAPITAL R */
2241 SYMB_UNICODE(0xC3,0x2118); /* SCRIPT CAPITAL P */
2242 SYMB_UNICODE(0xC4,0x2297); /* CIRCLED TIMES */
2243 SYMB_UNICODE(0xC5,0x2295); /* CIRCLED PLUS */
2244 SYMB_UNICODE(0xC6,0x2205); /* EMPTY SET */
2245 SYMB_UNICODE(0xC7,0x2229); /* INTERSECTION */
2246 SYMB_UNICODE(0xC8,0x222A); /* UNION */
2247 SYMB_UNICODE(0xC9,0x2283); /* SUPERSET OF */
2248 SYMB_UNICODE(0xCA,0x2287); /* SUPERSET OF OR EQUAL TO */
2249 SYMB_UNICODE(0xCB,0x2284); /* NOT A SUBSET OF */
2250 SYMB_UNICODE(0xCC,0x2282); /* SUBSET OF */
2251 SYMB_UNICODE(0xCD,0x2286); /* SUBSET OF OR EQUAL TO */
2252 SYMB_UNICODE(0xCE,0x2208); /* ELEMENT OF */
2253 SYMB_UNICODE(0xCF,0x2209); /* NOT AN ELEMENT OF */
2254 SYMB_UNICODE(0xD0,0x2220); /* ANGLE */
2255 SYMB_UNICODE(0xD1,0x2207); /* NABLA */
2256 SYMB_UNICODE(0xD2,0x00AE); /* REGISTERED SIGN serif */
2257 SYMB_UNICODE(0xD3,0x00A9); /* COPYRIGHT SIGN serif */
2258 SYMB_UNICODE(0xD4,0x2122); /* TRADE MARK SIGN serif */
2259 SYMB_UNICODE(0xD5,0x220F); /* N-ARY PRODUCT */
2260 SYMB_UNICODE(0xD6,0x221A); /* SQUARE ROOT */
2261 SYMB_UNICODE(0xD7,0x22C5); /* DOT OPERATOR */
2262 SYMB_UNICODE(0xD8,0x00AC); /* NOT SIGN */
2263 SYMB_UNICODE(0xD9,0x2227); /* LOGICAL AND */
2264 SYMB_UNICODE(0xDA,0x2228); /* LOGICAL OR */
2265 SYMB_UNICODE(0xDB,0x21D4); /* LEFT RIGHT DOUBLE ARROW */
2266 SYMB_UNICODE(0xDC,0x21D0); /* LEFTWARDS DOUBLE ARROW */
2267 SYMB_UNICODE(0xDD,0x21D1); /* UPWARDS DOUBLE ARROW */
2268 SYMB_UNICODE(0xDE,0x21D2); /* RIGHTWARDS DOUBLE ARROW */
2269 SYMB_UNICODE(0xDF,0x21D3); /* DOWNWARDS DOUBLE ARROW */
2270 SYMB_UNICODE(0xE0,0x25CA); /* LOZENGE previously mapped to 0x22C4 DIAMOND OPERATOR */
2271 SYMB_UNICODE(0xE1,0x3008); /* LEFT ANGLE BRACKET */
2272 SYMB_UNICODE(0xE5,0x2211); /* N-ARY SUMMATION */
2273 SYMB_UNICODE(0xE6,0x239B); /* LEFT PARENTHESIS UPPER HOOK */
2274 SYMB_UNICODE(0xE7,0x239C); /* LEFT PARENTHESIS EXTENSION */
2275 SYMB_UNICODE(0xE8,0x239D); /* LEFT PARENTHESIS LOWER HOOK */
2276 SYMB_UNICODE(0xE9,0x23A1); /* LEFT SQUARE BRACKET UPPER CORNER */
2277 SYMB_UNICODE(0xEA,0x23A2); /* LEFT SQUARE BRACKET EXTENSION */
2278 SYMB_UNICODE(0xEB,0x23A3); /* LEFT SQUARE BRACKET LOWER CORNER */
2279 SYMB_UNICODE(0xEC,0x23A7); /* LEFT CURLY BRACKET UPPER HOOK */
2280 SYMB_UNICODE(0xED,0x23A8); /* LEFT CURLY BRACKET MIDDLE PIECE */
2281 SYMB_UNICODE(0xEE,0x23A9); /* LEFT CURLY BRACKET LOWER HOOK */
2282 SYMB_UNICODE(0xEF,0x23AA); /* CURLY BRACKET EXTENSION */
2283 SYMB_UNICODE(0xF0,0xF8FF); /* Apple logo */
2284 SYMB_UNICODE(0xF1,0x3009); /* RIGHT ANGLE BRACKET */
2285 SYMB_UNICODE(0xF2,0x222B); /* INTEGRAL */
2286 SYMB_UNICODE(0xF3,0x2320); /* TOP HALF INTEGRAL */
2287 SYMB_UNICODE(0xF4,0x23AE); /* INTEGRAL EXTENSION */
2288 SYMB_UNICODE(0xF5,0x2321); /* BOTTOM HALF INTEGRAL */
2289 SYMB_UNICODE(0xF6,0x239E); /* RIGHT PARENTHESIS UPPER HOOK */
2290 SYMB_UNICODE(0xF7,0x239F); /* RIGHT PARENTHESIS EXTENSION */
2291 SYMB_UNICODE(0xF8,0x23A0); /* RIGHT PARENTHESIS LOWER HOOK */
2292 SYMB_UNICODE(0xF9,0x23A4); /* RIGHT SQUARE BRACKET UPPER CORNER */
2293 SYMB_UNICODE(0xFA,0x23A5); /* RIGHT SQUARE BRACKET EXTENSION */
2294 SYMB_UNICODE(0xFB,0x23A6); /* RIGHT SQUARE BRACKET LOWER CORNER */
2295 SYMB_UNICODE(0xFC,0x23AB); /* RIGHT CURLY BRACKET UPPER HOOK */
2296 SYMB_UNICODE(0xFD,0x23AC); /* RIGHT CURLY BRACKET MIDDLE PIECE */
2297 SYMB_UNICODE(0xFE,0x23AD); /* RIGHT CURLY BRACKET LOWER HOOK */
2298
2299 /* to be treated specifically : composed characters */
2300 case 0xE2 : /* REGISTERED SIGN, alternate: sans serif */
2301 g_unichar_to_utf8(0x00AE,iter_mod);
2302 iter_mod = g_utf8_next_char(iter_mod);
2303 g_unichar_to_utf8(0xF87F,iter_mod);
2304 break;
2305 case 0xE3 : /* COPYRIGHT SIGN, alternate: sans serif */
2306 g_unichar_to_utf8(0x00A9,iter_mod);
2307 iter_mod = g_utf8_next_char(iter_mod);
2308 g_unichar_to_utf8(0xF87F,iter_mod);
2309 break;
2310 case 0xE4 : /* TRADE MARK SIGN, alternate: sans serif */
2311 g_unichar_to_utf8(0x2122,iter_mod);
2312 iter_mod = g_utf8_next_char(iter_mod);
2313 g_unichar_to_utf8(0xF87F,iter_mod);
2314 break;
2315 default : g_unichar_to_utf8( g_utf8_get_char(iter), iter_mod); break;
2316 }
2317 iter = g_utf8_next_char(iter);
2318 iter_mod = g_utf8_next_char(iter_mod);
2319 }
2320
2321 g_free(string_utf8);
2322 return output;
2323 }
2324