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