GRASS 8 Programmer's Manual 8.5.0RC1(2026)-3334b87d9c
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#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
35static 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
89static 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 */
110void 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 */
133void 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
153static 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
184static void fc_init(void)
185{
186 static int initialized;
187
188 if (!initialized) {
189 FcInit();
190 initialized = 1;
191 }
192}
193
194static 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
215static 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 snprintf(buf, sizeof(buf), "%s:%s|%s:%s|%d|%s|%d|%s|", family,
242 style, family, style, GFONT_DRIVER, "", 0, "utf-8");
243 else
244 snprintf(buf, sizeof(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
259static 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
265static const int num_toy_fonts = 12;
266
267static 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 */
283void 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
295static 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 snprintf(buf, sizeof(buf), "%s|%s|%d|%s|%d|%s|", toy_fonts[i],
308 toy_fonts[i], 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 */
324void 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 */
338void 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 G_free(void *buf)
Free allocated memory.
Definition alloc.c:147
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:66
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