GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d37ee165c
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"),
52  encoding);
53 
54  ret = iconv(cd, &p1, &ilen, &p2, &olen);
55 
56  iconv_close(cd);
57 
58  *p2++ = '\0';
59 
60  if (ret > 0)
61  G_warning(_("Some characters could not be converted to UTF-8"));
62  }
63 #else
64  {
65  const unsigned char *p1 = (const unsigned char *) in;
66  unsigned char *p2 = (unsigned char *) out;
67  int i, j;
68 
69  for (i = j = 0; i < ilen; i++) {
70  int c = p1[i];
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  if (!p)
159  break;
160 
161  if (G_strcasecmp(p, "-bold") == 0)
162  weight = CAIRO_FONT_WEIGHT_BOLD;
163  else if (strcasecmp(p, "-italic") == 0)
164  slant = CAIRO_FONT_SLANT_ITALIC;
165  else if (G_strcasecmp(p, "-oblique") == 0)
166  slant = CAIRO_FONT_SLANT_OBLIQUE;
167  else
168  break;
169 
170  *p = '\0';
171  }
172 
173  cairo_select_font_face(cairo, font, slant, weight);
174 
175  G_free(font);
176 }
177 
178 #if USE_FONTCONFIG
179 
180 static void fc_init(void)
181 {
182  static int initialized;
183 
184  if (!initialized) {
185  FcInit();
186  initialized = 1;
187  }
188 }
189 
190 static void set_font_fc(const char *name)
191 {
192  static cairo_font_face_t *face;
193  FcPattern *pattern;
194  FcResult result;
195 
196  fc_init();
197 
198  if (face) {
199  cairo_font_face_destroy(face);
200  face = NULL;
201  }
202 
203  pattern = FcNameParse((FcChar8 *)name);
204  FcDefaultSubstitute(pattern);
205  FcConfigSubstitute(FcConfigGetCurrent(), pattern, FcMatchPattern);
206  pattern = FcFontMatch(FcConfigGetCurrent(), pattern, &result);
207  face = cairo_ft_font_face_create_for_pattern(pattern);
208  cairo_set_font_face(cairo, face);
209 }
210 
211 static void font_list_fc(char ***list, int *count, int verbose)
212 {
213  FcPattern *pattern;
214  FcObjectSet *objset;
215  FcFontSet *fontset;
216  char **fonts = *list;
217  int num_fonts = *count;
218  int i;
219 
220  fc_init();
221 
222  pattern = FcPatternCreate();
223  objset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (char *) NULL);
224  fontset = FcFontList(NULL, pattern, objset);
225 
226  fonts = G_realloc(fonts, (num_fonts + fontset->nfont) * sizeof(char *));
227 
228  for (i = 0; i < fontset->nfont; i++) {
229  char buf[1024];
230  FcPattern *pat = fontset->fonts[i];
231  FcChar8 *family = (FcChar8 *)"", *style = (FcChar8 *)"";
232 
233  FcPatternGetString(pat, FC_FAMILY, 0, &family);
234  FcPatternGetString(pat, FC_STYLE , 0, &style );
235 
236  if (verbose)
237  sprintf(buf, "%s:%s|%s:%s|%d|%s|%d|%s|",
238  family, style, family, style, GFONT_DRIVER, "", 0, "utf-8");
239  else
240  sprintf(buf, "%s:%s", family, style);
241 
242  fonts[num_fonts++] = G_store(buf);
243  }
244 
245  FcObjectSetDestroy(objset);
246  FcPatternDestroy(pattern);
247  FcFontSetDestroy (fontset);
248 
249  *list = fonts;
250  *count = num_fonts;
251 }
252 
253 #endif
254 
255 static const char *toy_fonts[12] = {
256  "sans",
257  "sans-italic",
258  "sans-bold",
259  "sans-bold-italic",
260  "serif",
261  "serif-italic",
262  "serif-bold",
263  "serif-bold-italic",
264  "mono",
265  "mono-italic",
266  "mono-bold",
267  "mono-bold-italic",
268 };
269 static const int num_toy_fonts = 12;
270 
271 static int is_toy_font(const char *name)
272 {
273  int i;
274 
275  for (i = 0; i < num_toy_fonts; i++)
276  if (G_strcasecmp(name, toy_fonts[i]) == 0)
277  return 1;
278 
279  return 0;
280 }
281 
282 /*!
283  \brief Set font
284 
285  \param name font name
286 */
287 void Cairo_set_font(const char *name)
288 {
289 #if USE_FONTCONFIG
290  if (is_toy_font(name))
291  set_font_toy(name);
292  else
293  set_font_fc(name);
294 #else
295  set_font_toy(name);
296 #endif
297 }
298 
299 static void font_list_toy(char ***list, int *count, int verbose)
300 {
301  char **fonts = *list;
302  int num_fonts = *count;
303  int i;
304 
305  fonts = G_realloc(fonts, (num_fonts + num_toy_fonts) * sizeof(char *));
306 
307  for (i = 0; i < num_toy_fonts; i++) {
308  char buf[256];
309  if (verbose)
310  sprintf(buf, "%s|%s|%d|%s|%d|%s|",
311  toy_fonts[i], toy_fonts[i], GFONT_DRIVER, "", 0, "utf-8");
312  else
313  strcpy(buf, toy_fonts[i]);
314  fonts[num_fonts++] = G_store(buf);
315  }
316 
317  *list = fonts;
318  *count = num_fonts;
319 }
320 
321 /*!
322  \brief Get list of fonts
323 
324  \param[out] list font list
325  \param[out] count number of items in the list
326 */
327 void Cairo_font_list(char ***list, int *count)
328 {
329  font_list_toy(list, count, 0);
330 #if USE_FONTCONFIG
331  font_list_fc(list, count, 0);
332 #endif
333 }
334 
335 /*!
336  \brief Get fonts into
337 
338  \param[out] list font list
339  \param[out] count number of items in the list
340 */
341 void Cairo_font_info(char ***list, int *count)
342 {
343  font_list_toy(list, count, 1);
344 #if USE_FONTCONFIG
345  font_list_fc(list, count, 1);
346 #endif
347 }
#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:144
#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