GRASS GIS 8 Programmer's Manual 8.2.0(2022)-exported
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
32static 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
86static 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*/
107void 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*/
130void 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
150static 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
180static void fc_init(void)
181{
182 static int initialized;
183
184 if (!initialized) {
185 FcInit();
186 initialized = 1;
187 }
188}
189
190static 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
211static 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
255static 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};
269static const int num_toy_fonts = 12;
270
271static 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*/
287void 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
299static 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*/
327void 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*/
341void 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}
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
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
double b
double l
double t
double r
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
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
int count
const char * name
Definition: named_colr.c:7
struct list * list
Definition: read_list.c:24
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:47
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87