18937
|
1 #include "config.h"
|
|
2
|
|
3 #include <stdlib.h>
|
|
4 #include <stdio.h>
|
|
5 #include <assert.h>
|
|
6 #include <string.h>
|
|
7 #include <sys/types.h>
|
|
8 #include <sys/stat.h>
|
|
9
|
|
10 #include "mp_msg.h"
|
|
11 #include "ass_fontconfig.h"
|
|
12
|
|
13 #ifdef HAVE_FONTCONFIG
|
|
14 #include <fontconfig/fontconfig.h>
|
|
15 #endif
|
|
16
|
|
17 struct fc_instance_s {
|
|
18 #ifdef HAVE_FONTCONFIG
|
|
19 FcConfig* config;
|
|
20 #endif
|
|
21 char* family_default;
|
|
22 char* path_default;
|
|
23 int index_default;
|
|
24 };
|
|
25
|
|
26 extern int no_more_font_messages;
|
|
27
|
|
28 #ifdef HAVE_FONTCONFIG
|
|
29 /**
|
|
30 * \brief Low-level font selection.
|
|
31 * \param priv private data
|
|
32 * \param family font family
|
|
33 * \param bold font weight value
|
|
34 * \param italic font slant value
|
|
35 * \param index out: font index inside a file
|
|
36 * \return font file path
|
|
37 */
|
|
38 static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index)
|
|
39 {
|
|
40 FcBool rc;
|
|
41 FcResult result;
|
|
42 FcPattern *pat, *rpat;
|
|
43 int val_i;
|
|
44 FcChar8* val_s;
|
19001
|
45 FcBool val_b;
|
18937
|
46 char buf[2000];
|
|
47
|
|
48 *index = 0;
|
|
49
|
|
50 snprintf(buf, 2000, "%s:outline=True:slant=%u:weight=%u", family, italic, bold);
|
|
51
|
|
52 pat = FcNameParse((const FcChar8*)buf);
|
|
53 if (!pat)
|
|
54 return 0;
|
|
55
|
|
56 FcDefaultSubstitute(pat);
|
|
57
|
|
58 rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
|
|
59 if (!rc)
|
|
60 return 0;
|
|
61
|
|
62 rpat = FcFontMatch(priv->config, pat, &result);
|
|
63 if (!rpat)
|
|
64 return 0;
|
|
65
|
19001
|
66 result = FcPatternGetBool(rpat, FC_OUTLINE, 0, &val_b);
|
|
67 if (result != FcResultMatch)
|
|
68 return 0;
|
|
69 if (val_b != 1)
|
|
70 return 0;
|
|
71
|
18937
|
72 result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i);
|
|
73 if (result != FcResultMatch)
|
|
74 return 0;
|
|
75 *index = val_i;
|
|
76
|
|
77 result = FcPatternGetString(rpat, FC_FAMILY, 0, &val_s);
|
|
78 if (result != FcResultMatch)
|
|
79 return 0;
|
|
80
|
|
81 if (strcasecmp((const char*)val_s, family) != 0)
|
|
82 mp_msg(MSGT_GLOBAL, MSGL_WARN, "fontconfig: selected font family is not the requested one: '%s' != '%s'\n",
|
|
83 (const char*)val_s, family);
|
|
84
|
|
85 result = FcPatternGetString(rpat, FC_FILE, 0, &val_s);
|
|
86 if (result != FcResultMatch)
|
|
87 return 0;
|
|
88
|
|
89 return strdup((const char*)val_s);
|
|
90 }
|
|
91
|
|
92 /**
|
|
93 * \brief Find a font. Use default family or path if necessary.
|
|
94 * \param priv_ private data
|
|
95 * \param family font family
|
|
96 * \param bold font weight value
|
|
97 * \param italic font slant value
|
|
98 * \param index out: font index inside a file
|
|
99 * \return font file path
|
|
100 */
|
|
101 char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index)
|
|
102 {
|
|
103 char* res = 0;
|
|
104 if (family && *family)
|
|
105 res = _select_font(priv, family, bold, italic, index);
|
|
106 if (!res && priv->family_default) {
|
|
107 res = _select_font(priv, priv->family_default, bold, italic, index);
|
|
108 if (res && !no_more_font_messages)
|
|
109 mp_msg(MSGT_GLOBAL, MSGL_WARN, "fontconfig_select: using default font family: (%s, %d, %d) -> %s, %d\n",
|
|
110 family, bold, italic, res, *index);
|
|
111 }
|
|
112 if (!res && priv->path_default) {
|
|
113 res = priv->path_default;
|
|
114 *index = priv->index_default;
|
|
115 if (!no_more_font_messages)
|
|
116 mp_msg(MSGT_GLOBAL, MSGL_WARN, "fontconfig_select: using default font: (%s, %d, %d) -> %s, %d\n",
|
|
117 family, bold, italic, res, *index);
|
|
118 }
|
|
119 if (!res) {
|
|
120 res = _select_font(priv, "Arial", bold, italic, index);
|
|
121 if (res && !no_more_font_messages)
|
|
122 mp_msg(MSGT_GLOBAL, MSGL_WARN, "fontconfig_select: using 'Arial' font family: (%s, %d, %d) -> %s, %d\n",
|
|
123 family, bold, italic, res, *index);
|
|
124 }
|
|
125 if (res)
|
|
126 mp_msg(MSGT_GLOBAL, MSGL_V, "fontconfig_select: (%s, %d, %d) -> %s, %d\n",
|
|
127 family, bold, italic, res, *index);
|
|
128 return res;
|
|
129 }
|
|
130
|
|
131 /**
|
|
132 * \brief Init fontconfig.
|
|
133 * \param dir additional directoryu for fonts
|
|
134 * \param family default font family
|
|
135 * \param path default font path
|
|
136 * \return pointer to fontconfig private data
|
|
137 */
|
|
138 fc_instance_t* fontconfig_init(const char* dir, const char* family, const char* path)
|
|
139 {
|
|
140 int rc;
|
|
141 struct stat st;
|
|
142 fc_instance_t* priv = calloc(1, sizeof(fc_instance_t));
|
|
143
|
|
144 rc = FcInit();
|
|
145 assert(rc);
|
|
146
|
|
147 priv->config = FcConfigGetCurrent();
|
|
148 if (!priv->config) {
|
|
149 mp_msg(MSGT_GLOBAL, MSGL_FATAL, "FcInitLoadConfigAndFonts failed\n");
|
|
150 return 0;
|
|
151 }
|
|
152
|
|
153 rc = FcConfigAppFontAddDir(priv->config, (const FcChar8*)dir);
|
|
154 if (!rc) {
|
|
155 mp_msg(MSGT_GLOBAL, MSGL_WARN, "FcConfigAppFontAddDir failed\n");
|
|
156 }
|
|
157
|
|
158 priv->family_default = family ? strdup(family) : 0;
|
|
159 priv->index_default = 0;
|
|
160
|
|
161 rc = stat(path, &st);
|
|
162 if (!rc && S_ISREG(st.st_mode))
|
|
163 priv->path_default = path ? strdup(path) : 0;
|
|
164 else
|
|
165 priv->path_default = 0;
|
|
166
|
|
167 return priv;
|
|
168 }
|
|
169
|
|
170 #else
|
|
171
|
|
172 char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index)
|
|
173 {
|
|
174 *index = priv->index_default;
|
|
175 return priv->path_default;
|
|
176 }
|
|
177
|
|
178 fc_instance_t* fontconfig_init(const char* dir, const char* family, const char* path)
|
|
179 {
|
|
180 mp_msg(MSGT_GLOBAL, MSGL_WARN, "Fontconfig disabled, only default font will be used\n");
|
|
181
|
|
182 fc_instance_t* priv = calloc(1, sizeof(fc_instance_t));
|
|
183
|
|
184 priv->path_default = strdup(path);
|
|
185 priv->index_default = 0;
|
|
186 return priv;
|
|
187 }
|
|
188
|
|
189 #endif
|
|
190
|
|
191 void fontconfig_done(fc_instance_t* priv)
|
|
192 {
|
|
193 // don't call FcFini() here, library can still be used by some code
|
|
194 if (priv && priv->path_default) free(priv->path_default);
|
|
195 if (priv && priv->family_default) free(priv->family_default);
|
|
196 if (priv) free(priv);
|
|
197 }
|
|
198
|
|
199
|