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