1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
4 Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include <sys/types.h>
31 #include "ass_fontconfig.h"
33 #ifdef HAVE_FONTCONFIG
34 #include <fontconfig/fontconfig.h>
37 struct fc_instance_s
{
38 #ifdef HAVE_FONTCONFIG
46 extern int no_more_font_messages
;
48 #ifdef HAVE_FONTCONFIG
50 * \brief Low-level font selection.
51 * \param priv private data
52 * \param family font family
53 * \param bold font weight value
54 * \param italic font slant value
55 * \param index out: font index inside a file
56 * \return font file path
58 static char* _select_font(fc_instance_t
* priv
, const char* family
, unsigned bold
, unsigned italic
, int* index
)
62 FcPattern
*pat
, *rpat
;
69 pat
= FcPatternCreate();
73 FcPatternAddString(pat
, FC_FAMILY
, (const FcChar8
*)family
);
74 FcPatternAddBool(pat
, FC_OUTLINE
, FcTrue
);
75 FcPatternAddInteger(pat
, FC_SLANT
, italic
);
76 FcPatternAddInteger(pat
, FC_WEIGHT
, bold
);
78 FcDefaultSubstitute(pat
);
80 rc
= FcConfigSubstitute(priv
->config
, pat
, FcMatchPattern
);
84 rpat
= FcFontMatch(priv
->config
, pat
, &result
);
88 result
= FcPatternGetBool(rpat
, FC_OUTLINE
, 0, &val_b
);
89 if (result
!= FcResultMatch
)
94 result
= FcPatternGetInteger(rpat
, FC_INDEX
, 0, &val_i
);
95 if (result
!= FcResultMatch
)
99 result
= FcPatternGetString(rpat
, FC_FAMILY
, 0, &val_s
);
100 if (result
!= FcResultMatch
)
103 if (strcasecmp((const char*)val_s
, family
) != 0)
104 mp_msg(MSGT_ASS
, MSGL_WARN
, "fontconfig: selected font family is not the requested one: '%s' != '%s'\n",
105 (const char*)val_s
, family
);
107 result
= FcPatternGetString(rpat
, FC_FILE
, 0, &val_s
);
108 if (result
!= FcResultMatch
)
111 return strdup((const char*)val_s
);
115 * \brief Find a font. Use default family or path if necessary.
116 * \param priv_ private data
117 * \param family font family
118 * \param bold font weight value
119 * \param italic font slant value
120 * \param index out: font index inside a file
121 * \return font file path
123 char* fontconfig_select(fc_instance_t
* priv
, const char* family
, unsigned bold
, unsigned italic
, int* index
)
126 if (family
&& *family
)
127 res
= _select_font(priv
, family
, bold
, italic
, index
);
128 if (!res
&& priv
->family_default
) {
129 res
= _select_font(priv
, priv
->family_default
, bold
, italic
, index
);
130 if (res
&& !no_more_font_messages
)
131 mp_msg(MSGT_ASS
, MSGL_WARN
, "fontconfig_select: using default font family: (%s, %d, %d) -> %s, %d\n",
132 family
, bold
, italic
, res
, *index
);
134 if (!res
&& priv
->path_default
) {
135 res
= priv
->path_default
;
136 *index
= priv
->index_default
;
137 if (!no_more_font_messages
)
138 mp_msg(MSGT_ASS
, MSGL_WARN
, "fontconfig_select: using default font: (%s, %d, %d) -> %s, %d\n",
139 family
, bold
, italic
, res
, *index
);
142 res
= _select_font(priv
, "Arial", bold
, italic
, index
);
143 if (res
&& !no_more_font_messages
)
144 mp_msg(MSGT_ASS
, MSGL_WARN
, "fontconfig_select: using 'Arial' font family: (%s, %d, %d) -> %s, %d\n",
145 family
, bold
, italic
, res
, *index
);
148 mp_msg(MSGT_ASS
, MSGL_V
, "fontconfig_select: (%s, %d, %d) -> %s, %d\n",
149 family
, bold
, italic
, res
, *index
);
154 * \brief Init fontconfig.
155 * \param dir additional directoryu for fonts
156 * \param family default font family
157 * \param path default font path
158 * \return pointer to fontconfig private data
160 fc_instance_t
* fontconfig_init(const char* dir
, const char* family
, const char* path
)
164 fc_instance_t
* priv
= calloc(1, sizeof(fc_instance_t
));
169 priv
->config
= FcConfigGetCurrent();
171 mp_msg(MSGT_ASS
, MSGL_FATAL
, "FcInitLoadConfigAndFonts failed\n");
175 if (FcDirCacheValid((const FcChar8
*)dir
) == FcFalse
)
177 mp_msg(MSGT_ASS
, MSGL_INFO
, "[ass] Updating font cache\n");
178 if (FcGetVersion() >= 20390 && FcGetVersion() < 20400)
179 mp_msg(MSGT_ASS
, MSGL_WARN
,
180 "[ass] beta versions of fontconfig are not supported\n"
181 " update before reporting any bugs\n");
182 // FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir()
183 if (FcGetVersion() < 20390) {
186 fcs
= FcFontSetCreate();
187 fss
= FcStrSetCreate();
188 rc
= FcStrSetAdd(fss
, (const FcChar8
*)dir
);
190 mp_msg(MSGT_ASS
, MSGL_WARN
, "FcStrSetAdd failed\n");
194 rc
= FcDirScan(fcs
, fss
, NULL
, FcConfigGetBlanks(priv
->config
), (const FcChar8
*)dir
, FcFalse
);
196 mp_msg(MSGT_ASS
, MSGL_WARN
, "FcDirScan failed\n");
200 rc
= FcDirSave(fcs
, fss
, (const FcChar8
*)dir
);
202 mp_msg(MSGT_ASS
, MSGL_WARN
, "FcDirSave failed\n");
210 rc
= FcConfigAppFontAddDir(priv
->config
, (const FcChar8
*)dir
);
212 mp_msg(MSGT_ASS
, MSGL_WARN
, "FcConfigAppFontAddDir failed\n");
215 priv
->family_default
= family
? strdup(family
) : 0;
216 priv
->index_default
= 0;
218 rc
= stat(path
, &st
);
219 if (!rc
&& S_ISREG(st
.st_mode
))
220 priv
->path_default
= path
? strdup(path
) : 0;
222 priv
->path_default
= 0;
229 char* fontconfig_select(fc_instance_t
* priv
, const char* family
, unsigned bold
, unsigned italic
, int* index
)
231 *index
= priv
->index_default
;
232 return priv
->path_default
;
235 fc_instance_t
* fontconfig_init(const char* dir
, const char* family
, const char* path
)
239 mp_msg(MSGT_ASS
, MSGL_WARN
, "Fontconfig disabled, only default font will be used\n");
241 priv
= calloc(1, sizeof(fc_instance_t
));
243 priv
->path_default
= strdup(path
);
244 priv
->index_default
= 0;
250 void fontconfig_done(fc_instance_t
* priv
)
252 // don't call FcFini() here, library can still be used by some code
253 if (priv
&& priv
->path_default
) free(priv
->path_default
);
254 if (priv
&& priv
->family_default
) free(priv
->family_default
);
255 if (priv
) free(priv
);