/src/fontconfig/src/fclist.c
Line | Count | Source |
1 | | /* |
2 | | * fontconfig/src/fclist.c |
3 | | * |
4 | | * Copyright © 2000 Keith Packard |
5 | | * |
6 | | * Permission to use, copy, modify, distribute, and sell this software and its |
7 | | * documentation for any purpose is hereby granted without fee, provided that |
8 | | * the above copyright notice appear in all copies and that both that |
9 | | * copyright notice and this permission notice appear in supporting |
10 | | * documentation, and that the name of the author(s) not be used in |
11 | | * advertising or publicity pertaining to distribution of the software without |
12 | | * specific, written prior permission. The authors make no |
13 | | * representations about the suitability of this software for any purpose. It |
14 | | * is provided "as is" without express or implied warranty. |
15 | | * |
16 | | * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
17 | | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
18 | | * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
19 | | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
20 | | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
21 | | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
22 | | * PERFORMANCE OF THIS SOFTWARE. |
23 | | */ |
24 | | |
25 | | #include "fcint.h" |
26 | | |
27 | | #include <stdlib.h> |
28 | | |
29 | | FcObjectSet * |
30 | | FcObjectSetCreate (void) |
31 | 0 | { |
32 | 0 | FcObjectSet *os; |
33 | |
|
34 | 0 | os = (FcObjectSet *)malloc (sizeof (FcObjectSet)); |
35 | 0 | if (!os) |
36 | 0 | return 0; |
37 | 0 | os->nobject = 0; |
38 | 0 | os->sobject = 0; |
39 | 0 | os->objects = 0; |
40 | 0 | os->nobjIds = 0; |
41 | 0 | os->objIds = 0; |
42 | 0 | return os; |
43 | 0 | } |
44 | | |
45 | | FcBool |
46 | | FcObjectSetAdd (FcObjectSet *os, const char *object) |
47 | 0 | { |
48 | 0 | int s; |
49 | 0 | int high, low, mid, c; |
50 | 0 | FcObject *objects, o = FcObjectFromName (object); |
51 | |
|
52 | 0 | if (os->nobjIds == os->sobject) { |
53 | 0 | s = os->sobject + 4; |
54 | 0 | if (os->objIds) |
55 | 0 | objects = (FcObject *)realloc ((void *)os->objIds, |
56 | 0 | s * sizeof (FcObject)); |
57 | 0 | else |
58 | 0 | objects = (FcObject *)malloc (s * sizeof (FcObject)); |
59 | 0 | if (!objects) |
60 | 0 | return FcFalse; |
61 | 0 | os->objIds = objects; |
62 | 0 | os->sobject = s; |
63 | 0 | } |
64 | 0 | high = os->nobjIds - 1; |
65 | 0 | low = 0; |
66 | 0 | mid = 0; |
67 | 0 | c = 1; |
68 | 0 | while (low <= high) { |
69 | 0 | mid = (low + high) >> 1; |
70 | 0 | c = os->objIds[mid] - o; |
71 | 0 | if (c == 0) { |
72 | 0 | return FcTrue; |
73 | 0 | } |
74 | 0 | if (c < 0) |
75 | 0 | low = mid + 1; |
76 | 0 | else |
77 | 0 | high = mid - 1; |
78 | 0 | } |
79 | 0 | if (c < 0) |
80 | 0 | mid++; |
81 | 0 | memmove (os->objIds + mid + 1, os->objIds + mid, |
82 | 0 | (os->nobjIds - mid) * sizeof (FcObject)); |
83 | 0 | os->objIds[mid] = o; |
84 | 0 | os->nobjIds++; |
85 | 0 | return FcTrue; |
86 | 0 | } |
87 | | |
88 | | void |
89 | | FcObjectSetDestroy (FcObjectSet *os) |
90 | 0 | { |
91 | 0 | if (os) { |
92 | 0 | if (os->objIds) { |
93 | 0 | free ((void *)os->objIds); |
94 | 0 | } |
95 | 0 | free (os); |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | FcObjectSet * |
100 | | FcObjectSetVaBuild (const char *first, va_list va) |
101 | 0 | { |
102 | 0 | FcObjectSet *ret; |
103 | |
|
104 | 0 | FcObjectSetVapBuild (ret, first, va); |
105 | 0 | return ret; |
106 | 0 | } |
107 | | |
108 | | FcObjectSet * |
109 | | FcObjectSetBuild (const char *first, ...) |
110 | 0 | { |
111 | 0 | va_list va; |
112 | 0 | FcObjectSet *os; |
113 | |
|
114 | 0 | va_start (va, first); |
115 | 0 | FcObjectSetVapBuild (os, first, va); |
116 | 0 | va_end (va); |
117 | 0 | return os; |
118 | 0 | } |
119 | | |
120 | | /* |
121 | | * Font must have a containing value for every value in the pattern |
122 | | */ |
123 | | static FcBool |
124 | | FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */ |
125 | | FcValueListPtr fntOrig) /* font */ |
126 | 0 | { |
127 | 0 | FcValueListPtr pat, fnt; |
128 | |
|
129 | 0 | for (pat = patOrig; pat != NULL; pat = FcValueListNext (pat)) { |
130 | 0 | for (fnt = fntOrig; fnt != NULL; fnt = FcValueListNext (fnt)) { |
131 | | /* |
132 | | * make sure the font 'contains' the pattern. |
133 | | * (OpListing is OpContains except for strings |
134 | | * where it requires an exact match) |
135 | | */ |
136 | 0 | if (FcConfigCompareValue (&fnt->value, |
137 | 0 | FC_OP (FcOpListing, FcOpFlagIgnoreBlanks), |
138 | 0 | &pat->value)) |
139 | 0 | break; |
140 | 0 | } |
141 | 0 | if (fnt == NULL) |
142 | 0 | return FcFalse; |
143 | 0 | } |
144 | 0 | return FcTrue; |
145 | 0 | } |
146 | | |
147 | | static FcBool |
148 | | FcListValueListEqual (FcValueListPtr v1orig, |
149 | | FcValueListPtr v2orig) |
150 | 0 | { |
151 | 0 | FcValueListPtr v1, v2; |
152 | |
|
153 | 0 | for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext (v1)) { |
154 | 0 | for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext (v2)) |
155 | 0 | if (FcValueEqual (FcValueCanonicalize (&(v1)->value), |
156 | 0 | FcValueCanonicalize (&(v2)->value))) |
157 | 0 | break; |
158 | 0 | if (v2 == NULL) |
159 | 0 | return FcFalse; |
160 | 0 | } |
161 | 0 | for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext (v2)) { |
162 | 0 | for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext (v1)) |
163 | 0 | if (FcValueEqual (FcValueCanonicalize (&v1->value), |
164 | 0 | FcValueCanonicalize (&v2->value))) |
165 | 0 | break; |
166 | 0 | if (v1 == NULL) |
167 | 0 | return FcFalse; |
168 | 0 | } |
169 | 0 | return FcTrue; |
170 | 0 | } |
171 | | |
172 | | static FcBool |
173 | | FcListPatternEqual (FcPattern *p1, |
174 | | FcPattern *p2, |
175 | | FcObjectSet *os) |
176 | 0 | { |
177 | 0 | int i; |
178 | 0 | FcPatternElt *e1, *e2; |
179 | |
|
180 | 0 | for (i = 0; i < os->nobjIds; i++) { |
181 | 0 | e1 = FcPatternObjectFindElt (p1, os->objIds[i]); |
182 | 0 | e2 = FcPatternObjectFindElt (p2, os->objIds[i]); |
183 | 0 | if (!e1 && !e2) |
184 | 0 | continue; |
185 | 0 | if (!e1 || !e2) |
186 | 0 | return FcFalse; |
187 | 0 | if (!FcListValueListEqual (FcPatternEltValues (e1), |
188 | 0 | FcPatternEltValues (e2))) |
189 | 0 | return FcFalse; |
190 | 0 | } |
191 | 0 | return FcTrue; |
192 | 0 | } |
193 | | |
194 | | /* |
195 | | * FcTrue iff all objects in "p" match "font" |
196 | | */ |
197 | | |
198 | | FcBool |
199 | | FcListPatternMatchAny (const FcPattern *p, |
200 | | const FcPattern *font) |
201 | 0 | { |
202 | 0 | int i; |
203 | |
|
204 | 0 | if (!p) |
205 | 0 | return FcFalse; |
206 | 0 | for (i = 0; i < p->num; i++) { |
207 | 0 | FcPatternElt *pe = &FcPatternElts (p)[i]; |
208 | 0 | FcPatternElt *fe; |
209 | |
|
210 | 0 | if (pe->object == FC_NAMELANG_OBJECT) { |
211 | | /* "namelang" object is the alias object to change "familylang", |
212 | | * "stylelang" and "fullnamelang" object all together. it won't be |
213 | | * available on the font pattern. so checking its availability |
214 | | * causes no results. we should ignore it here. |
215 | | */ |
216 | 0 | continue; |
217 | 0 | } |
218 | 0 | fe = FcPatternObjectFindElt (font, pe->object); |
219 | 0 | if (!fe) |
220 | 0 | return FcFalse; |
221 | 0 | if (!FcListValueListMatchAny (FcPatternEltValues (pe), /* pat elts */ |
222 | 0 | FcPatternEltValues (fe))) /* font elts */ |
223 | 0 | return FcFalse; |
224 | 0 | } |
225 | 0 | return FcTrue; |
226 | 0 | } |
227 | | |
228 | | static FcChar32 |
229 | | FcListMatrixHash (const FcMatrix *m) |
230 | 0 | { |
231 | 0 | int xx = (int)(m->xx * 100), |
232 | 0 | xy = (int)(m->xy * 100), |
233 | 0 | yx = (int)(m->yx * 100), |
234 | 0 | yy = (int)(m->yy * 100); |
235 | |
|
236 | 0 | return ((FcChar32)xx) ^ ((FcChar32)xy) ^ ((FcChar32)yx) ^ ((FcChar32)yy); |
237 | 0 | } |
238 | | |
239 | | static FcChar32 |
240 | | FcListValueHash (FcValue *value) |
241 | 0 | { |
242 | 0 | FcValue v = FcValueCanonicalize (value); |
243 | 0 | switch (v.type) { |
244 | 0 | case FcTypeUnknown: |
245 | 0 | case FcTypeVoid: |
246 | 0 | return 0; |
247 | 0 | case FcTypeInteger: |
248 | 0 | return (FcChar32)v.u.i; |
249 | 0 | case FcTypeDouble: |
250 | 0 | return (FcChar32)(int)v.u.d; |
251 | 0 | case FcTypeString: |
252 | 0 | return FcStrHashIgnoreCase (v.u.s); |
253 | 0 | case FcTypeBool: |
254 | 0 | return (FcChar32)v.u.b; |
255 | 0 | case FcTypeMatrix: |
256 | 0 | return FcListMatrixHash (v.u.m); |
257 | 0 | case FcTypeCharSet: |
258 | 0 | return FcCharSetCount (v.u.c); |
259 | 0 | case FcTypeFTFace: |
260 | 0 | return (intptr_t)v.u.f; |
261 | 0 | case FcTypeLangSet: |
262 | 0 | return FcLangSetHash (v.u.l); |
263 | 0 | case FcTypeRange: |
264 | 0 | return FcRangeHash (v.u.r); |
265 | 0 | } |
266 | 0 | return 0; |
267 | 0 | } |
268 | | |
269 | | static FcChar32 |
270 | | FcListValueListHash (FcValueListPtr list) |
271 | 0 | { |
272 | 0 | FcChar32 h = 0; |
273 | |
|
274 | 0 | while (list != NULL) { |
275 | 0 | h = h ^ FcListValueHash (&list->value); |
276 | 0 | list = FcValueListNext (list); |
277 | 0 | } |
278 | 0 | return h; |
279 | 0 | } |
280 | | |
281 | | static FcChar32 |
282 | | FcListPatternHash (FcPattern *font, |
283 | | FcObjectSet *os) |
284 | 0 | { |
285 | 0 | int n; |
286 | 0 | FcPatternElt *e; |
287 | 0 | FcChar32 h = 0; |
288 | |
|
289 | 0 | for (n = 0; n < os->nobjIds; n++) { |
290 | 0 | e = FcPatternObjectFindElt (font, os->objIds[n]); |
291 | 0 | if (e) |
292 | 0 | h = h ^ FcListValueListHash (FcPatternEltValues (e)); |
293 | 0 | } |
294 | 0 | return h; |
295 | 0 | } |
296 | | |
297 | | typedef struct _FcListBucket { |
298 | | struct _FcListBucket *next; |
299 | | FcChar32 hash; |
300 | | FcPattern *pattern; |
301 | | } FcListBucket; |
302 | | |
303 | 0 | #define FC_LIST_HASH_SIZE 4099 |
304 | | |
305 | | typedef struct _FcListHashTable { |
306 | | int entries; |
307 | | FcListBucket *buckets[FC_LIST_HASH_SIZE]; |
308 | | } FcListHashTable; |
309 | | |
310 | | static void |
311 | | FcListHashTableInit (FcListHashTable *table) |
312 | 0 | { |
313 | 0 | table->entries = 0; |
314 | 0 | memset (table->buckets, '\0', sizeof (table->buckets)); |
315 | 0 | } |
316 | | |
317 | | static void |
318 | | FcListHashTableCleanup (FcListHashTable *table) |
319 | 0 | { |
320 | 0 | int i; |
321 | 0 | FcListBucket *bucket, *next; |
322 | |
|
323 | 0 | for (i = 0; i < FC_LIST_HASH_SIZE; i++) { |
324 | 0 | for (bucket = table->buckets[i]; bucket; bucket = next) { |
325 | 0 | next = bucket->next; |
326 | 0 | FcPatternDestroy (bucket->pattern); |
327 | 0 | free (bucket); |
328 | 0 | } |
329 | 0 | table->buckets[i] = 0; |
330 | 0 | } |
331 | 0 | table->entries = 0; |
332 | 0 | } |
333 | | |
334 | | static int |
335 | | FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object, const FcChar8 *lang) |
336 | 0 | { |
337 | 0 | FcPatternElt *e = FcPatternObjectFindElt (font, object); |
338 | 0 | FcValueListPtr v; |
339 | 0 | FcValue value; |
340 | 0 | int idx = -1; |
341 | 0 | int defidx = -1; |
342 | 0 | int i; |
343 | |
|
344 | 0 | if (e) { |
345 | 0 | for (v = FcPatternEltValues (e), i = 0; v; v = FcValueListNext (v), ++i) { |
346 | 0 | value = FcValueCanonicalize (&v->value); |
347 | |
|
348 | 0 | if (value.type == FcTypeString) { |
349 | 0 | FcLangResult res = FcLangCompare (value.u.s, lang); |
350 | 0 | if (res == FcLangEqual) |
351 | 0 | return i; |
352 | | |
353 | 0 | if (res == FcLangDifferentCountry && idx < 0) |
354 | 0 | idx = i; |
355 | 0 | if (defidx < 0) { |
356 | | /* workaround for fonts that has non-English value |
357 | | * at the head of values. |
358 | | */ |
359 | 0 | res = FcLangCompare (value.u.s, (FcChar8 *)"en"); |
360 | 0 | if (res == FcLangEqual) |
361 | 0 | defidx = i; |
362 | 0 | } |
363 | 0 | } |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | 0 | return (idx > 0) ? idx : (defidx > 0) ? defidx |
368 | 0 | : 0; |
369 | 0 | } |
370 | | |
371 | | static FcBool |
372 | | FcListAppend (FcListHashTable *table, |
373 | | FcPattern *font, |
374 | | FcObjectSet *os, |
375 | | const FcChar8 *lang) |
376 | 0 | { |
377 | 0 | int o; |
378 | 0 | FcPatternElt *e; |
379 | 0 | FcValueListPtr v; |
380 | 0 | FcChar32 hash; |
381 | 0 | FcListBucket **prev, *bucket; |
382 | 0 | int familyidx = -1; |
383 | 0 | int fullnameidx = -1; |
384 | 0 | int styleidx = -1; |
385 | 0 | int defidx = 0; |
386 | 0 | int idx; |
387 | |
|
388 | 0 | hash = FcListPatternHash (font, os); |
389 | 0 | for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE]; |
390 | 0 | (bucket = *prev); prev = &(bucket->next)) { |
391 | 0 | if (bucket->hash == hash && |
392 | 0 | FcListPatternEqual (bucket->pattern, font, os)) |
393 | 0 | return FcTrue; |
394 | 0 | } |
395 | 0 | bucket = (FcListBucket *)malloc (sizeof (FcListBucket)); |
396 | 0 | if (!bucket) |
397 | 0 | goto bail0; |
398 | 0 | bucket->next = 0; |
399 | 0 | bucket->hash = hash; |
400 | 0 | bucket->pattern = FcPatternCreate(); |
401 | 0 | if (!bucket->pattern) |
402 | 0 | goto bail1; |
403 | | |
404 | 0 | for (o = 0; o < os->nobjIds; o++) { |
405 | 0 | if (os->objIds[o] == FC_FAMILY_OBJECT || os->objIds[o] == FC_FAMILYLANG_OBJECT) { |
406 | 0 | if (familyidx < 0) |
407 | 0 | familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT, lang); |
408 | 0 | defidx = familyidx; |
409 | 0 | } else if (os->objIds[o] == FC_FULLNAME_OBJECT || os->objIds[o] == FC_FULLNAMELANG_OBJECT) { |
410 | 0 | if (fullnameidx < 0) |
411 | 0 | fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT, lang); |
412 | 0 | defidx = fullnameidx; |
413 | 0 | } else if (os->objIds[o] == FC_STYLE_OBJECT || os->objIds[o] == FC_STYLELANG_OBJECT) { |
414 | 0 | if (styleidx < 0) |
415 | 0 | styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT, lang); |
416 | 0 | defidx = styleidx; |
417 | 0 | } else |
418 | 0 | defidx = 0; |
419 | |
|
420 | 0 | e = FcPatternObjectFindElt (font, os->objIds[o]); |
421 | 0 | if (e) { |
422 | 0 | for (v = FcPatternEltValues (e), idx = 0; v; |
423 | 0 | v = FcValueListNext (v), ++idx) { |
424 | 0 | if (!FcPatternObjectAdd (bucket->pattern, |
425 | 0 | os->objIds[o], |
426 | 0 | FcValueCanonicalize (&v->value), defidx != idx)) |
427 | 0 | goto bail2; |
428 | 0 | } |
429 | 0 | } |
430 | 0 | } |
431 | 0 | *prev = bucket; |
432 | 0 | ++table->entries; |
433 | |
|
434 | 0 | return FcTrue; |
435 | | |
436 | 0 | bail2: |
437 | 0 | FcPatternDestroy (bucket->pattern); |
438 | 0 | bail1: |
439 | 0 | free (bucket); |
440 | 0 | bail0: |
441 | 0 | return FcFalse; |
442 | 0 | } |
443 | | |
444 | | FcFontSet * |
445 | | FcFontSetList (FcConfig *config, |
446 | | FcFontSet **sets, |
447 | | int nsets, |
448 | | FcPattern *p, |
449 | | FcObjectSet *os) |
450 | 0 | { |
451 | 0 | FcFontSet *ret; |
452 | 0 | FcFontSet *s; |
453 | 0 | int f; |
454 | 0 | int set; |
455 | 0 | FcListHashTable table; |
456 | 0 | int i; |
457 | 0 | FcListBucket *bucket; |
458 | 0 | int destroy_os = 0; |
459 | |
|
460 | 0 | if (!config) { |
461 | 0 | if (!FcInitBringUptoDate()) |
462 | 0 | goto bail0; |
463 | 0 | } |
464 | 0 | config = FcConfigReference (config); |
465 | 0 | if (!config) |
466 | 0 | goto bail0; |
467 | 0 | FcListHashTableInit (&table); |
468 | |
|
469 | 0 | if (!os) { |
470 | 0 | os = FcObjectGetSet(); |
471 | 0 | destroy_os = 1; |
472 | 0 | } |
473 | | |
474 | | /* |
475 | | * Walk all available fonts adding those that |
476 | | * match to the hash table |
477 | | */ |
478 | 0 | for (set = 0; set < nsets; set++) { |
479 | 0 | s = sets[set]; |
480 | 0 | if (!s) |
481 | 0 | continue; |
482 | 0 | for (f = 0; f < s->nfont; f++) |
483 | 0 | if (FcListPatternMatchAny (p, /* pattern */ |
484 | 0 | s->fonts[f])) /* font */ |
485 | 0 | { |
486 | 0 | FcChar8 *lang; |
487 | |
|
488 | 0 | if (FcPatternObjectGetString (p, FC_NAMELANG_OBJECT, 0, &lang) != FcResultMatch) { |
489 | 0 | lang = FcConfigGetDefaultLang (config); |
490 | 0 | } |
491 | 0 | if (!FcListAppend (&table, s->fonts[f], os, lang)) |
492 | 0 | goto bail1; |
493 | 0 | } |
494 | 0 | } |
495 | | #if 0 |
496 | | { |
497 | | int max = 0; |
498 | | int full = 0; |
499 | | int ents = 0; |
500 | | int len; |
501 | | for (i = 0; i < FC_LIST_HASH_SIZE; i++) |
502 | | { |
503 | | if ((bucket = table.buckets[i])) |
504 | | { |
505 | | len = 0; |
506 | | for (; bucket; bucket = bucket->next) |
507 | | { |
508 | | ents++; |
509 | | len++; |
510 | | } |
511 | | if (len > max) |
512 | | max = len; |
513 | | full++; |
514 | | } |
515 | | } |
516 | | printf ("used: %d max: %d avg: %g\n", full, max, |
517 | | (double) ents / FC_LIST_HASH_SIZE); |
518 | | } |
519 | | #endif |
520 | | /* |
521 | | * Walk the hash table and build |
522 | | * a font set |
523 | | */ |
524 | 0 | ret = FcFontSetCreate(); |
525 | 0 | if (!ret) |
526 | 0 | goto bail1; |
527 | 0 | for (i = 0; i < FC_LIST_HASH_SIZE; i++) |
528 | 0 | while ((bucket = table.buckets[i])) { |
529 | 0 | if (!FcFontSetAdd (ret, bucket->pattern)) |
530 | 0 | goto bail2; |
531 | 0 | table.buckets[i] = bucket->next; |
532 | 0 | free (bucket); |
533 | 0 | } |
534 | | |
535 | 0 | if (destroy_os) |
536 | 0 | FcObjectSetDestroy (os); |
537 | 0 | FcConfigDestroy (config); |
538 | |
|
539 | 0 | return ret; |
540 | | |
541 | 0 | bail2: |
542 | 0 | FcFontSetDestroy (ret); |
543 | 0 | bail1: |
544 | 0 | FcListHashTableCleanup (&table); |
545 | 0 | FcConfigDestroy (config); |
546 | 0 | bail0: |
547 | 0 | if (destroy_os) |
548 | 0 | FcObjectSetDestroy (os); |
549 | 0 | return 0; |
550 | 0 | } |
551 | | |
552 | | FcFontSet * |
553 | | FcFontList (FcConfig *config, |
554 | | FcPattern *p, |
555 | | FcObjectSet *os) |
556 | 0 | { |
557 | 0 | FcFontSet *sets[2], *ret; |
558 | 0 | int nsets; |
559 | |
|
560 | 0 | if (!config) { |
561 | 0 | if (!FcInitBringUptoDate()) |
562 | 0 | return 0; |
563 | 0 | } |
564 | 0 | config = FcConfigReference (config); |
565 | 0 | if (!config) |
566 | 0 | return NULL; |
567 | 0 | nsets = 0; |
568 | 0 | if (config->fonts[FcSetSystem]) |
569 | 0 | sets[nsets++] = config->fonts[FcSetSystem]; |
570 | 0 | if (config->fonts[FcSetApplication]) |
571 | 0 | sets[nsets++] = config->fonts[FcSetApplication]; |
572 | 0 | ret = FcFontSetList (config, sets, nsets, p, os); |
573 | 0 | FcConfigDestroy (config); |
574 | |
|
575 | 0 | return ret; |
576 | 0 | } |
577 | | #define __fclist__ |
578 | | #include "fcaliastail.h" |
579 | | #undef __fclist__ |