GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
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"), 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
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
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
181static void fc_init(void)
182{
183 static int initialized;
184
185 if (!initialized) {
186 FcInit();
187 initialized = 1;
188 }
189}
190
191static 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
212static 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
256static 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
262static const int num_toy_fonts = 12;
263
264static 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 */
280void 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
292static 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 */
321void 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 */
335void 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 G_free(void *buf)
Free allocated memory.
Definition alloc.c:150
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:159
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition gis/error.c:203
int count
const char * name
Definition named_colr.c:6
#define strcpy
Definition parson.c:62
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