Mercurial > mplayer.hg
annotate libass/ass_fontconfig.c @ 31790:224ed68c32e2
sync with en/mplayer.1 rev. 31814
author | jrash |
---|---|
date | Fri, 30 Jul 2010 14:11:05 +0000 |
parents | 48d020c5ceca |
children | e64df5862cea |
rev | line source |
---|---|
20008
fa122b7c71c6
Add copyright notice and vim/emacs comments to libass and vf_ass.c.
eugeni
parents:
19902
diff
changeset
|
1 /* |
26723 | 2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> |
3 * | |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
4 * This file is part of libass. |
26723 | 5 * |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
6 * libass is free software; you can redistribute it and/or modify |
26723 | 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. | |
10 * | |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
11 * libass is distributed in the hope that it will be useful, |
26723 | 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. | |
15 * | |
16 * You should have received a copy of the GNU General Public License along | |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
17 * with libass; if not, write to the Free Software Foundation, Inc., |
26723 | 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 */ | |
20008
fa122b7c71c6
Add copyright notice and vim/emacs comments to libass and vf_ass.c.
eugeni
parents:
19902
diff
changeset
|
20 |
18937 | 21 #include "config.h" |
22 | |
23 #include <stdlib.h> | |
24 #include <stdio.h> | |
25 #include <assert.h> | |
26 #include <string.h> | |
27 #include <sys/types.h> | |
28 #include <sys/stat.h> | |
22292 | 29 #include <inttypes.h> |
30 #include <ft2build.h> | |
31 #include FT_FREETYPE_H | |
18937 | 32 |
30200 | 33 #include "ass_utils.h" |
21458
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
34 #include "ass.h" |
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
35 #include "ass_library.h" |
18937 | 36 #include "ass_fontconfig.h" |
37 | |
27393 | 38 #ifdef CONFIG_FONTCONFIG |
18937 | 39 #include <fontconfig/fontconfig.h> |
21460 | 40 #include <fontconfig/fcfreetype.h> |
18937 | 41 #endif |
42 | |
30200 | 43 struct fc_instance { |
27393 | 44 #ifdef CONFIG_FONTCONFIG |
30200 | 45 FcConfig *config; |
18937 | 46 #endif |
30200 | 47 char *family_default; |
48 char *path_default; | |
49 int index_default; | |
18937 | 50 }; |
51 | |
27393 | 52 #ifdef CONFIG_FONTCONFIG |
26660
ab5729095d68
Define FC_FULLNAME and FC_EMBOLDEN to fix compilation with ancient fontconfig.
eugeni
parents:
26659
diff
changeset
|
53 |
18937 | 54 /** |
55 * \brief Low-level font selection. | |
56 * \param priv private data | |
57 * \param family font family | |
28860
7fcc0bf5b27a
Treat -font/-subfont as Fontconfig pattern in libass.
eugeni
parents:
27842
diff
changeset
|
58 * \param treat_family_as_pattern treat family as fontconfig pattern |
18937 | 59 * \param bold font weight value |
60 * \param italic font slant value | |
61 * \param index out: font index inside a file | |
23980 | 62 * \param code: the character that should be present in the font, can be 0 |
18937 | 63 * \return font file path |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
64 */ |
30200 | 65 static char *_select_font(ASS_Library *library, FCInstance *priv, |
66 const char *family, int treat_family_as_pattern, | |
67 unsigned bold, unsigned italic, int *index, | |
68 uint32_t code) | |
18937 | 69 { |
30200 | 70 FcBool rc; |
71 FcResult result; | |
72 FcPattern *pat = NULL, *rpat = NULL; | |
73 int r_index, r_slant, r_weight; | |
74 FcChar8 *r_family, *r_style, *r_file, *r_fullname; | |
75 FcBool r_outline, r_embolden; | |
76 FcCharSet *r_charset; | |
77 FcFontSet *fset = NULL; | |
78 int curf; | |
79 char *retval = NULL; | |
80 int family_cnt = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
81 |
30200 | 82 *index = 0; |
18937 | 83 |
30200 | 84 if (treat_family_as_pattern) |
85 pat = FcNameParse((const FcChar8 *) family); | |
86 else | |
87 pat = FcPatternCreate(); | |
28860
7fcc0bf5b27a
Treat -font/-subfont as Fontconfig pattern in libass.
eugeni
parents:
27842
diff
changeset
|
88 |
30200 | 89 if (!pat) |
90 goto error; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
91 |
30200 | 92 if (!treat_family_as_pattern) { |
93 FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family); | |
26591 | 94 |
30200 | 95 // In SSA/ASS fonts are sometimes referenced by their "full name", |
96 // which is usually a concatenation of family name and font | |
97 // style (ex. Ottawa Bold). Full name is available from | |
98 // FontConfig pattern element FC_FULLNAME, but it is never | |
99 // used for font matching. | |
100 // Therefore, I'm removing words from the end of the name one | |
101 // by one, and adding shortened names to the pattern. It seems | |
102 // that the first value (full name in this case) has | |
103 // precedence in matching. | |
104 // An alternative approach could be to reimplement FcFontSort | |
105 // using FC_FULLNAME instead of FC_FAMILY. | |
106 family_cnt = 1; | |
107 { | |
108 char *s = strdup(family); | |
109 char *p = s + strlen(s); | |
110 while (--p > s) | |
111 if (*p == ' ' || *p == '-') { | |
112 *p = '\0'; | |
113 FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s); | |
114 ++family_cnt; | |
115 } | |
116 free(s); | |
117 } | |
118 } | |
119 FcPatternAddBool(pat, FC_OUTLINE, FcTrue); | |
120 FcPatternAddInteger(pat, FC_SLANT, italic); | |
121 FcPatternAddInteger(pat, FC_WEIGHT, bold); | |
19063
5525af2ee4c7
Use FcPatternAdd-Type instead of FcNameParse. The latter, as it turns out, requires escaping of some characters ('-', maybe more).
eugeni
parents:
19001
diff
changeset
|
122 |
30200 | 123 FcDefaultSubstitute(pat); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
124 |
30200 | 125 rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); |
126 if (!rc) | |
127 goto error; | |
21351
c611dfc4cb85
If a glyph is not found in the current font, switch to another one.
eugeni
parents:
21279
diff
changeset
|
128 |
30200 | 129 fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result); |
130 if (!fset) | |
131 goto error; | |
21351
c611dfc4cb85
If a glyph is not found in the current font, switch to another one.
eugeni
parents:
21279
diff
changeset
|
132 |
30200 | 133 for (curf = 0; curf < fset->nfont; ++curf) { |
134 FcPattern *curp = fset->fonts[curf]; | |
26658
1e1ebebc8f5b
Remove extra family names from the search pattern after FcFontSort and
eugeni
parents:
26620
diff
changeset
|
135 |
30200 | 136 result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline); |
137 if (result != FcResultMatch) | |
138 continue; | |
139 if (r_outline != FcTrue) | |
140 continue; | |
141 if (!code) | |
142 break; | |
143 result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset); | |
144 if (result != FcResultMatch) | |
145 continue; | |
146 if (FcCharSetHasChar(r_charset, code)) | |
147 break; | |
148 } | |
21351
c611dfc4cb85
If a glyph is not found in the current font, switch to another one.
eugeni
parents:
21279
diff
changeset
|
149 |
30200 | 150 if (curf >= fset->nfont) |
151 goto error; | |
21351
c611dfc4cb85
If a glyph is not found in the current font, switch to another one.
eugeni
parents:
21279
diff
changeset
|
152 |
30200 | 153 if (!treat_family_as_pattern) { |
154 // Remove all extra family names from original pattern. | |
155 // After this, FcFontRenderPrepare will select the most relevant family | |
156 // name in case there are more than one of them. | |
157 for (; family_cnt > 1; --family_cnt) | |
158 FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); | |
159 } | |
160 | |
161 rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); | |
162 if (!rpat) | |
163 goto error; | |
26658
1e1ebebc8f5b
Remove extra family names from the search pattern after FcFontSort and
eugeni
parents:
26620
diff
changeset
|
164 |
30200 | 165 result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index); |
166 if (result != FcResultMatch) | |
167 goto error; | |
168 *index = r_index; | |
26658
1e1ebebc8f5b
Remove extra family names from the search pattern after FcFontSort and
eugeni
parents:
26620
diff
changeset
|
169 |
30200 | 170 result = FcPatternGetString(rpat, FC_FILE, 0, &r_file); |
171 if (result != FcResultMatch) | |
172 goto error; | |
173 retval = strdup((const char *) r_file); | |
18937 | 174 |
30200 | 175 result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family); |
176 if (result != FcResultMatch) | |
177 r_family = NULL; | |
26614 | 178 |
30200 | 179 result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname); |
180 if (result != FcResultMatch) | |
181 r_fullname = NULL; | |
18937 | 182 |
30200 | 183 if (!treat_family_as_pattern && |
184 !(r_family && strcasecmp((const char *) r_family, family) == 0) && | |
185 !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) | |
186 ass_msg(library, MSGL_WARN, | |
187 "fontconfig: Selected font is not the requested one: " | |
188 "'%s' != '%s'", | |
189 (const char *) (r_fullname ? r_fullname : r_family), family); | |
26616 | 190 |
30200 | 191 result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style); |
192 if (result != FcResultMatch) | |
193 r_style = NULL; | |
194 | |
195 result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant); | |
196 if (result != FcResultMatch) | |
197 r_slant = 0; | |
26616 | 198 |
30200 | 199 result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight); |
200 if (result != FcResultMatch) | |
201 r_weight = 0; | |
26616 | 202 |
30200 | 203 result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden); |
204 if (result != FcResultMatch) | |
205 r_embolden = 0; | |
26616 | 206 |
30200 | 207 ass_msg(library, MSGL_V, |
208 "Font info: family '%s', style '%s', fullname '%s'," | |
209 " slant %d, weight %d%s", (const char *) r_family, | |
210 (const char *) r_style, (const char *) r_fullname, r_slant, | |
211 r_weight, r_embolden ? ", embolden" : ""); | |
26616 | 212 |
30200 | 213 error: |
214 if (pat) | |
215 FcPatternDestroy(pat); | |
216 if (rpat) | |
217 FcPatternDestroy(rpat); | |
218 if (fset) | |
219 FcFontSetDestroy(fset); | |
220 return retval; | |
18937 | 221 } |
222 | |
223 /** | |
224 * \brief Find a font. Use default family or path if necessary. | |
225 * \param priv_ private data | |
226 * \param family font family | |
28860
7fcc0bf5b27a
Treat -font/-subfont as Fontconfig pattern in libass.
eugeni
parents:
27842
diff
changeset
|
227 * \param treat_family_as_pattern treat family as fontconfig pattern |
18937 | 228 * \param bold font weight value |
229 * \param italic font slant value | |
230 * \param index out: font index inside a file | |
23980 | 231 * \param code: the character that should be present in the font, can be 0 |
18937 | 232 * \return font file path |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
233 */ |
30200 | 234 char *fontconfig_select(ASS_Library *library, FCInstance *priv, |
235 const char *family, int treat_family_as_pattern, | |
236 unsigned bold, unsigned italic, int *index, | |
237 uint32_t code) | |
18937 | 238 { |
30200 | 239 char *res = 0; |
240 if (!priv->config) { | |
241 *index = priv->index_default; | |
242 res = priv->path_default ? strdup(priv->path_default) : 0; | |
243 return res; | |
244 } | |
245 if (family && *family) | |
246 res = | |
247 _select_font(library, priv, family, treat_family_as_pattern, | |
248 bold, italic, index, code); | |
249 if (!res && priv->family_default) { | |
250 res = | |
251 _select_font(library, priv, priv->family_default, 0, bold, | |
252 italic, index, code); | |
253 if (res) | |
254 ass_msg(library, MSGL_WARN, "fontconfig_select: Using default " | |
255 "font family: (%s, %d, %d) -> %s, %d", | |
256 family, bold, italic, res, *index); | |
257 } | |
258 if (!res && priv->path_default) { | |
259 res = strdup(priv->path_default); | |
260 *index = priv->index_default; | |
261 ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: " | |
262 "(%s, %d, %d) -> %s, %d", family, bold, italic, | |
263 res, *index); | |
264 } | |
265 if (!res) { | |
266 res = _select_font(library, priv, "Arial", 0, bold, italic, | |
267 index, code); | |
268 if (res) | |
269 ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' " | |
270 "font family: (%s, %d, %d) -> %s, %d", family, bold, | |
271 italic, res, *index); | |
272 } | |
273 if (res) | |
274 ass_msg(library, MSGL_V, | |
275 "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold, | |
276 italic, res, *index); | |
277 return res; | |
18937 | 278 } |
279 | |
21458
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
280 /** |
21630 | 281 * \brief Process memory font. |
282 * \param priv private data | |
283 * \param library library object | |
284 * \param ftlibrary freetype library object | |
285 * \param idx index of the processed font in library->fontdata | |
286 * With FontConfig >= 2.4.2, builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace. | |
287 * With older FontConfig versions, save the font to ~/.mplayer/fonts. | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
288 */ |
30200 | 289 static void process_fontdata(FCInstance *priv, ASS_Library *library, |
290 FT_Library ftlibrary, int idx) | |
21458
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
291 { |
30200 | 292 int rc; |
293 const char *name = library->fontdata[idx].name; | |
294 const char *data = library->fontdata[idx].data; | |
295 int data_size = library->fontdata[idx].size; | |
23216
b863ed752149
Move variables and a function under #ifdef FC_VERSION to avoid warnings.
eugeni
parents:
23215
diff
changeset
|
296 |
30200 | 297 FT_Face face; |
298 FcPattern *pattern; | |
299 FcFontSet *fset; | |
300 FcBool res; | |
301 int face_index, num_faces = 1; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
302 |
30200 | 303 for (face_index = 0; face_index < num_faces; ++face_index) { |
304 rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data, | |
305 data_size, face_index, &face); | |
306 if (rc) { | |
307 ass_msg(library, MSGL_WARN, "Error opening memory font: %s", | |
308 name); | |
309 return; | |
310 } | |
311 num_faces = face->num_faces; | |
21458
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
312 |
30200 | 313 pattern = |
314 FcFreeTypeQueryFace(face, (unsigned char *) name, 0, | |
315 FcConfigGetBlanks(priv->config)); | |
316 if (!pattern) { | |
317 ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace"); | |
318 FT_Done_Face(face); | |
319 return; | |
320 } | |
21460 | 321 |
30200 | 322 fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication |
323 if (!fset) { | |
324 ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts"); | |
325 FT_Done_Face(face); | |
326 return; | |
327 } | |
21460 | 328 |
30200 | 329 res = FcFontSetAdd(fset, pattern); |
330 if (!res) { | |
331 ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd"); | |
332 FT_Done_Face(face); | |
333 return; | |
334 } | |
21460 | 335 |
30200 | 336 FT_Done_Face(face); |
337 } | |
21458
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
338 } |
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
339 |
18937 | 340 /** |
341 * \brief Init fontconfig. | |
21630 | 342 * \param library libass library object |
343 * \param ftlibrary freetype library object | |
18937 | 344 * \param family default font family |
345 * \param path default font path | |
30200 | 346 * \param fc whether fontconfig should be used |
347 * \param config path to a fontconfig configuration file, or NULL | |
348 * \param update whether the fontconfig cache should be built/updated | |
18937 | 349 * \return pointer to fontconfig private data |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
350 */ |
30200 | 351 FCInstance *fontconfig_init(ASS_Library *library, |
352 FT_Library ftlibrary, const char *family, | |
353 const char *path, int fc, const char *config, | |
354 int update) | |
18937 | 355 { |
30200 | 356 int rc; |
357 FCInstance *priv = calloc(1, sizeof(FCInstance)); | |
358 const char *dir = library->fonts_dir; | |
359 int i; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
360 |
30200 | 361 if (!fc) { |
362 ass_msg(library, MSGL_WARN, | |
363 "Fontconfig disabled, only default font will be used."); | |
364 goto exit; | |
365 } | |
21458
7af6c25a0cfc
Keep embedded fonts in ass_library_t and perform actual disk write
eugeni
parents:
21351
diff
changeset
|
366 |
30200 | 367 priv->config = FcConfigCreate(); |
368 rc = FcConfigParseAndLoad(priv->config, (unsigned char *) config, FcTrue); | |
369 if (!rc) { | |
370 ass_msg(library, MSGL_WARN, "No usable fontconfig configuration " | |
371 "file found, using fallback."); | |
372 FcConfigDestroy(priv->config); | |
373 priv->config = FcInitLoadConfig(); | |
374 rc++; | |
375 } | |
376 if (rc && update) { | |
377 FcConfigBuildFonts(priv->config); | |
378 } | |
27095 | 379 |
30200 | 380 if (!rc || !priv->config) { |
381 ass_msg(library, MSGL_FATAL, | |
382 "No valid fontconfig configuration found!"); | |
383 FcConfigDestroy(priv->config); | |
384 goto exit; | |
385 } | |
386 | |
387 for (i = 0; i < library->num_fontdata; ++i) | |
388 process_fontdata(priv, library, ftlibrary, i); | |
389 | |
390 if (dir) { | |
391 ass_msg(library, MSGL_INFO, "Updating font cache"); | |
27095 | 392 |
30200 | 393 rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); |
394 if (!rc) { | |
395 ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir"); | |
396 } | |
397 } | |
19340 | 398 |
30200 | 399 priv->family_default = family ? strdup(family) : NULL; |
400 exit: | |
401 priv->path_default = path ? strdup(path) : NULL; | |
402 priv->index_default = 0; | |
19340 | 403 |
30200 | 404 return priv; |
18937 | 405 } |
406 | |
30200 | 407 int fontconfig_update(FCInstance *priv) |
408 { | |
409 return FcConfigBuildFonts(priv->config); | |
410 } | |
411 | |
412 #else /* CONFIG_FONTCONFIG */ | |
18937 | 413 |
30200 | 414 char *fontconfig_select(ASS_Library *library, FCInstance *priv, |
415 const char *family, int treat_family_as_pattern, | |
416 unsigned bold, unsigned italic, int *index, | |
417 uint32_t code) | |
18937 | 418 { |
30200 | 419 *index = priv->index_default; |
420 char* res = priv->path_default ? strdup(priv->path_default) : 0; | |
421 return res; | |
18937 | 422 } |
423 | |
30200 | 424 FCInstance *fontconfig_init(ASS_Library *library, |
425 FT_Library ftlibrary, const char *family, | |
426 const char *path, int fc, const char *config, | |
427 int update) | |
18937 | 428 { |
30200 | 429 FCInstance *priv; |
19481 | 430 |
30200 | 431 ass_msg(library, MSGL_WARN, |
432 "Fontconfig disabled, only default font will be used."); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
433 |
30200 | 434 priv = calloc(1, sizeof(FCInstance)); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28942
diff
changeset
|
435 |
30200 | 436 priv->path_default = path ? strdup(path) : 0; |
437 priv->index_default = 0; | |
438 return priv; | |
439 } | |
440 | |
441 int fontconfig_update(FCInstance *priv) | |
442 { | |
443 // Do nothing | |
444 return 1; | |
18937 | 445 } |
446 | |
447 #endif | |
448 | |
30200 | 449 void fontconfig_done(FCInstance *priv) |
18937 | 450 { |
30200 | 451 #ifdef CONFIG_FONTCONFIG |
452 if (priv && priv->config) | |
453 FcConfigDestroy(priv->config); | |
454 #endif | |
455 if (priv && priv->path_default) | |
456 free(priv->path_default); | |
457 if (priv && priv->family_default) | |
458 free(priv->family_default); | |
459 if (priv) | |
460 free(priv); | |
18937 | 461 } |