GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-dd1a9b617b
cairodriver/text.c
Go to the documentation of this file.
1 /*!
2  \file lib/cairodriver/text.c
3 
4  \brief GRASS cairo display driver - text subroutines
5 
6  (C) 2007-2008 by Lars Ahlzen and the GRASS Development Team
7 
8  This program is free software under the GNU General Public License
9  (>=v2). Read the file COPYING that comes with GRASS for details.
10 
11  \author Lars Ahlzen <lars ahlzen.com> (original contributor)
12  \author Glynn Clements
13  */
14 
15 #include <grass/glocale.h>
16 #include "cairodriver.h"
17 
18 #if CAIRO_HAS_FT_FONT
19 #include <cairo-ft.h>
20 #if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 10, 0) || defined(CAIRO_HAS_FC_FONT)
21 #define USE_FONTCONFIG 1
22 #include <fontconfig/fontconfig.h>
23 #else
24 #define USE_FONTCONFIG 0
25 #endif
26 #endif /* CAIRO_HAS_FT_FONT */
27 
28 #ifdef HAVE_ICONV_H
29 #include <iconv.h>
30 #endif
31 
32 static char *convert(const char *in)
33 {
34  size_t ilen, olen;
35  char *out;
36 
37  ilen = strlen(in);
38  olen = 3 * ilen + 1;
39 
40  out = G_malloc(olen);
41 
42 #ifdef HAVE_ICONV_H
43  {
44  const char *encoding = font_get_encoding();
45  char *p1 = (char *)in;
46  char *p2 = out;
47  size_t ret;
48  iconv_t cd;
49 
50  if ((cd = iconv_open("UTF-8", encoding)) == (iconv_t)-1)
51  G_fatal_error(_("Unable to convert from <%s> to UTF-8"), encoding);
52 
53  ret = iconv(cd, &p1, &ilen, &p2, &olen);
54 
55  iconv_close(cd);
56 
57  *p2++ = '\0';
58 
59  if (ret > 0)
60  G_warning(_("Some characters could not be converted to UTF-8"));
61  }
62 #else
63  {
64  const unsigned char *p1 = (const unsigned char *)in;
65  unsigned char *p2 = (unsigned char *)out;
66  int i, j;
67 
68  for (i = j = 0; i < ilen; i++) {
69  int c = p1[i];
70 
71  if (c < 0x80)
72  p2[j++] = c;
73  else {
74  p2[j++] = 0xC0 + (c >> 6);
75  p2[j++] = 0x80 + (c & 0x3F);
76  }
77  }
78 
79  p2[j++] = '\0';
80  }
81 #endif
82 
83  return out;
84 }
85 
86 static void set_matrix(void)
87 {
88  static cairo_matrix_t mat;
89 
90  if (matrix_valid)
91  return;
92 
93  cairo_matrix_init_identity(&mat);
94  cairo_matrix_scale(&mat, text_size_x, text_size_y);
95  cairo_matrix_rotate(&mat, -text_rotation * M_PI / 180);
96 
97  cairo_set_font_matrix(cairo, &mat);
98 
99  matrix_valid = 1;
100 }
101 
102 /*!
103  \brief Draw text
104 
105  \param str string to be drawn
106  */
107 void Cairo_Text(const char *str)
108 {
109  char *utf8 = convert(str);
110 
111  if (!utf8)
112  return;
113 
114  set_matrix();
115 
116  cairo_move_to(cairo, cur_x, cur_y);
117  cairo_show_text(cairo, utf8);
118 
119  G_free(utf8);
120 
121  ca.modified = 1;
122 }
123 
124 /*
125  \brief Get text bounding box
126 
127  \param str string
128  \param[out] t,b,l,r top, bottom, left, right corner
129  */
130 void Cairo_text_box(const char *str, double *t, double *b, double *l, double *r)
131 {
132  char *utf8 = convert(str);
133  cairo_text_extents_t ext;
134 
135  if (!utf8)
136  return;
137 
138  set_matrix();
139 
140  cairo_text_extents(cairo, utf8, &ext);
141 
142  G_free(utf8);
143 
144  *l = cur_x + ext.x_bearing;
145  *r = cur_x + ext.x_bearing + ext.width;
146  *t = cur_y + ext.y_bearing;
147  *b = cur_y + ext.y_bearing + ext.height;
148 }
149 
150 static void set_font_toy(const char *name)
151 {
152  char *font = G_store(name);
153  cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
154  cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL;
155 
156  for (;;) {
157  char *p = strrchr(font, '-');
158 
159  if (!p)
160  break;
161 
162  if (G_strcasecmp(p, "-bold") == 0)
163  weight = CAIRO_FONT_WEIGHT_BOLD;
164  else if (strcasecmp(p, "-italic") == 0)
165  slant = CAIRO_FONT_SLANT_ITALIC;
166  else if (G_strcasecmp(p, "-oblique") == 0)
167  slant = CAIRO_FONT_SLANT_OBLIQUE;
168  else
169  break;
170 
171  *p = '\0';
172  }
173 
174  cairo_select_font_face(cairo, font, slant, weight);
175 
176  G_free(font);
177 }
178 
179 #if USE_FONTCONFIG
180 
181 static void fc_init(void)
182 {
183  static int initialized;
184 
185  if (!initialized) {
186  FcInit();
187  initialized = 1;
188  }
189 }
190 
191 static void set_font_fc(const char *name)
192 {
193  static cairo_font_face_t *face;
194  FcPattern *pattern;
195  FcResult result;
196 
197  fc_init();
198 
199  if (face) {
200  cairo_font_face_destroy(face);
201  face = NULL;
202  }
203 
204  pattern = FcNameParse((FcChar8 *)name);
205  FcDefaultSubstitute(pattern);
206  FcConfigSubstitute(FcConfigGetCurrent(), pattern, FcMatchPattern);
207  pattern = FcFontMatch(FcConfigGetCurrent(), pattern, &result);
208  face = cairo_ft_font_face_create_for_pattern(pattern);
209  cairo_set_font_face(cairo, face);
210 }
211 
212 static void font_list_fc(char ***list, int *count, int verbose)
213 {
214  FcPattern *pattern;
215  FcObjectSet *objset;
216  FcFontSet *fontset;
217  char **fonts = *list;
218  int num_fonts = *count;
219  int i;
220 
221  fc_init();
222 
223  pattern = FcPatternCreate();
224  objset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (char *)NULL);
225  fontset = FcFontList(NULL, pattern, objset);
226 
227  fonts = G_realloc(fonts, (num_fonts + fontset->nfont) * sizeof(char *));
228 
229  for (i = 0; i < fontset->nfont; i++) {
230  char buf[1024];
231  FcPattern *pat = fontset->fonts[i];
232  FcChar8 *family = (FcChar8 *)"", *style = (FcChar8 *)"";
233 
234  FcPatternGetString(pat, FC_FAMILY, 0, &family);
235  FcPatternGetString(pat, FC_STYLE, 0, &style);
236 
237  if (verbose)
238  sprintf(buf, "%s:%s|%s:%s|%d|%s|%d|%s|", family, style, family,
239  style, GFONT_DRIVER, "", 0, "utf-8");
240  else
241  sprintf(buf, "%s:%s", family, style);
242 
243  fonts[num_fonts++] = G_store(buf);
244  }
245 
246  FcObjectSetDestroy(objset);
247  FcPatternDestroy(pattern);
248  FcFontSetDestroy(fontset);
249 
250  *list = fonts;
251  *count = num_fonts;
252 }
253 
254 #endif
255 
256 static const char *toy_fonts[12] = {
257  "sans", "sans-italic", "sans-bold", "sans-bold-italic",
258  "serif", "serif-italic", "serif-bold", "serif-bold-italic",
259  "mono", "mono-italic", "mono-bold", "mono-bold-italic",
260 };
261 
262 static const int num_toy_fonts = 12;
263 
264 static int is_toy_font(const char *name)
265 {
266  int i;
267 
268  for (i = 0; i < num_toy_fonts; i++)
269  if (G_strcasecmp(name, toy_fonts[i]) == 0)
270  return 1;
271 
272  return 0;
273 }
274 
275 /*!
276  \brief Set font
277 
278  \param name font name
279  */
280 void Cairo_set_font(const char *name)
281 {
282 #if USE_FONTCONFIG
283  if (is_toy_font(name))
284  set_font_toy(name);
285  else
286  set_font_fc(name);
287 #else
288  set_font_toy(name);
289 #endif
290 }
291 
292 static void font_list_toy(char ***list, int *count, int verbose)
293 {
294  char **fonts = *list;
295  int num_fonts = *count;
296  int i;
297 
298  fonts = G_realloc(fonts, (num_fonts + num_toy_fonts) * sizeof(char *));
299 
300  for (i = 0; i < num_toy_fonts; i++) {
301  char buf[256];
302 
303  if (verbose)
304  sprintf(buf, "%s|%s|%d|%s|%d|%s|", toy_fonts[i], toy_fonts[i],
305  GFONT_DRIVER, "", 0, "utf-8");
306  else
307  strcpy(buf, toy_fonts[i]);
308  fonts[num_fonts++] = G_store(buf);
309  }
310 
311  *list = fonts;
312  *count = num_fonts;
313 }
314 
315 /*!
316  \brief Get list of fonts
317 
318  \param[out] list font list
319  \param[out] count number of items in the list
320  */
321 void Cairo_font_list(char ***list, int *count)
322 {
323  font_list_toy(list, count, 0);
324 #if USE_FONTCONFIG
325  font_list_fc(list, count, 0);
326 #endif
327 }
328 
329 /*!
330  \brief Get fonts into
331 
332  \param[out] list font list
333  \param[out] count number of items in the list
334  */
335 void Cairo_font_info(char ***list, int *count)
336 {
337  font_list_toy(list, count, 1);
338 #if USE_FONTCONFIG
339  font_list_fc(list, count, 1);
340 #endif
341 }
void Cairo_text_box(const char *str, double *t, double *b, double *l, double *r)
void Cairo_font_info(char ***list, int *count)
Get fonts into.
void Cairo_font_list(char ***list, int *count)
Get list of fonts.
void Cairo_Text(const char *str)
Draw text.
void Cairo_set_font(const char *name)
Set font.
GRASS cairo display driver - header file.
struct cairo_state ca
cairo_t * cairo
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
double text_size_y
Definition: driver/init.c:36
double text_rotation
Definition: driver/init.c:37
int matrix_valid
Definition: driver/init.c:40
double text_size_x
Definition: driver/init.c:35
double cur_x
Definition: driver/init.c:32
double cur_y
Definition: driver/init.c:33
const char * font_get_encoding(void)
Definition: font.c:34
#define GFONT_DRIVER
Definition: fontcap.h:21
#define M_PI
Definition: gis.h:158
#define _(str)
Definition: glocale.h:10
int count
const char * name
Definition: named_colr.c:6
#define strcpy
Definition: parson.c:62
double b
Definition: r_raster.c:39
double l
Definition: r_raster.c:39
double t
Definition: r_raster.c:39
double r
Definition: r_raster.c:39
struct list * list
Definition: read_list.c:24
Definition: manage.h:4