Pass the FcObjectPtr to FcCompareValueList, not the char * (perf).
[platform/upstream/fontconfig.git] / src / fcmatch.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
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 Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes 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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD 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 <string.h>
26 #include <ctype.h>
27 #include "fcint.h"
28 #include <stdio.h>
29
30 static double
31 FcCompareNumber (FcValue *value1, FcValue *value2)
32 {
33     double  v1, v2, v;
34     
35     switch (value1->type) {
36     case FcTypeInteger:
37         v1 = (double) value1->u.i;
38         break;
39     case FcTypeDouble:
40         v1 = value1->u.d;
41         break;
42     default:
43         return -1.0;
44     }
45     switch (value2->type) {
46     case FcTypeInteger:
47         v2 = (double) value2->u.i;
48         break;
49     case FcTypeDouble:
50         v2 = value2->u.d;
51         break;
52     default:
53         return -1.0;
54     }
55     v = v2 - v1;
56     if (v < 0)
57         v = -v;
58     return v;
59 }
60
61 static double
62 FcCompareString (FcValue *v1, FcValue *v2)
63 {
64     return (double) FcStrCmpIgnoreCase (fc_value_string(v1), fc_value_string(v2)) != 0;
65 }
66
67 static double
68 FcCompareFamily (FcValue *v1, FcValue *v2)
69 {
70     /* rely on the guarantee in FcPatternAddWithBinding that
71      * families are always FcTypeString. */
72     const FcChar8* v1_string = fc_value_string(v1);
73     const FcChar8* v2_string = fc_value_string(v2);
74
75     if (FcToLower(*v1_string) != FcToLower(*v2_string))
76        return 1.0;
77
78     return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
79 }
80
81 static double
82 FcCompareLang (FcValue *v1, FcValue *v2)
83 {
84     FcLangResult    result;
85     FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
86     
87     switch (value1.type) {
88     case FcTypeLangSet:
89         switch (value2.type) {
90         case FcTypeLangSet:
91             result = FcLangSetCompare (value1.u.l, value2.u.l);
92             break;
93         case FcTypeString:
94             result = FcLangSetHasLang (value1.u.l, 
95                                        value2.u.s);
96             break;
97         default:
98             return -1.0;
99         }
100         break;
101     case FcTypeString:
102         switch (value2.type) {
103         case FcTypeLangSet:
104             result = FcLangSetHasLang (value2.u.l, value1.u.s);
105             break;
106         case FcTypeString:
107             result = FcLangCompare (value1.u.s, 
108                                     value2.u.s);
109             break;
110         default:
111             return -1.0;
112         }
113         break;
114     default:
115         return -1.0;
116     }
117     switch (result) {
118     case FcLangEqual:
119         return 0;
120     case FcLangDifferentCountry:
121         return 1;
122     case FcLangDifferentLang:
123     default:
124         return 2;
125     }
126 }
127
128 static double
129 FcCompareBool (FcValue *v1, FcValue *v2)
130 {
131     if (fc_storage_type(v2) != FcTypeBool || fc_storage_type(v1) != FcTypeBool)
132         return -1.0;
133     return (double) v2->u.b != v1->u.b;
134 }
135
136 static double
137 FcCompareCharSet (FcValue *v1, FcValue *v2)
138 {
139     return (double) FcCharSetSubtractCount (fc_value_charset(v1), fc_value_charset(v2));
140 }
141
142 static double
143 FcCompareSize (FcValue *value1, FcValue *value2)
144 {
145     double  v1, v2, v;
146
147     switch (value1->type) {
148     case FcTypeInteger:
149         v1 = value1->u.i;
150         break;
151     case FcTypeDouble:
152         v1 = value1->u.d;
153         break;
154     default:
155         return -1;
156     }
157     switch (value2->type) {
158     case FcTypeInteger:
159         v2 = value2->u.i;
160         break;
161     case FcTypeDouble:
162         v2 = value2->u.d;
163         break;
164     default:
165         return -1;
166     }
167     if (v2 == 0)
168         return 0;
169     v = v2 - v1;
170     if (v < 0)
171         v = -v;
172     return v;
173 }
174
175 typedef struct _FcMatcher {
176     const char      *object;
177     double          (*compare) (FcValue *value1, FcValue *value2);
178     int             strong, weak;
179 } FcMatcher;
180
181 /*
182  * Order is significant, it defines the precedence of
183  * each value, earlier values are more significant than
184  * later values
185  */
186 static FcMatcher _FcMatchers [] = {
187     { FC_FOUNDRY,       FcCompareString,        0, 0 },
188 #define MATCH_FOUNDRY       0
189 #define MATCH_FOUNDRY_INDEX 0
190     
191     { FC_CHARSET,       FcCompareCharSet,       1, 1 },
192 #define MATCH_CHARSET       1
193 #define MATCH_CHARSET_INDEX 1
194     
195     { FC_FAMILY,        FcCompareFamily,        2, 4 },
196 #define MATCH_FAMILY        2
197 #define MATCH_FAMILY_STRONG_INDEX   2
198 #define MATCH_FAMILY_WEAK_INDEX     4
199     
200     { FC_LANG,          FcCompareLang,          3, 3 },
201 #define MATCH_LANG          3
202 #define MATCH_LANG_INDEX    3
203     
204     { FC_SPACING,       FcCompareNumber,        5, 5 },
205 #define MATCH_SPACING       4
206 #define MATCH_SPACING_INDEX 5
207     
208     { FC_PIXEL_SIZE,    FcCompareSize,          6, 6 },
209 #define MATCH_PIXEL_SIZE    5
210 #define MATCH_PIXEL_SIZE_INDEX  6
211     
212     { FC_STYLE,         FcCompareString,        7, 7 },
213 #define MATCH_STYLE         6
214 #define MATCH_STYLE_INDEX   7
215     
216     { FC_SLANT,         FcCompareNumber,        8, 8 },
217 #define MATCH_SLANT         7
218 #define MATCH_SLANT_INDEX   8
219     
220     { FC_WEIGHT,        FcCompareNumber,        9, 9 },
221 #define MATCH_WEIGHT        8
222 #define MATCH_WEIGHT_INDEX  9
223     
224     { FC_WIDTH,         FcCompareNumber,        10, 10 },
225 #define MATCH_WIDTH         9
226 #define MATCH_WIDTH_INDEX   10
227     
228     { FC_ANTIALIAS,     FcCompareBool,          11, 11 },
229 #define MATCH_ANTIALIAS     10
230 #define MATCH_ANTIALIAS_INDEX       11
231     
232     { FC_RASTERIZER,    FcCompareString,        12, 12 },
233 #define MATCH_RASTERIZER    11
234 #define MATCH_RASTERIZER_INDEX    12
235
236     { FC_OUTLINE,       FcCompareBool,          13, 13 },
237 #define MATCH_OUTLINE       12
238 #define MATCH_OUTLINE_INDEX         13
239
240     { FC_FONTVERSION,   FcCompareNumber,        14, 14 },
241 #define MATCH_FONTVERSION   13
242 #define MATCH_FONTVERSION_INDEX   14
243 };
244
245 #define NUM_MATCH_VALUES    15
246
247 static FcBool
248 FcCompareValueList (FcObjectPtr o,
249                     FcValueListPtr v1orig,      /* pattern */
250                     FcValueListPtr v2orig,      /* target */
251                     FcValue     *bestValue,
252                     double      *value,
253                     FcResult    *result)
254 {
255     FcValueListPtr  v1, v2;
256     FcValueList     *v1_ptrU, *v2_ptrU;
257     double          v, best, bestStrong, bestWeak;
258     int             i;
259     int             j;
260     const char* object = FcObjectPtrU(o);
261
262     /*
263      * Locate the possible matching entry by examining the
264      * first few characters in object
265      */
266     i = -1;
267     switch (object[0]) {
268     case 'f':
269         switch (object[1]) {
270         case 'o':
271             switch (object[2]) {
272             case 'u':
273                 i = MATCH_FOUNDRY; break;
274             case 'n':
275                 i = MATCH_FONTVERSION; break;
276             }
277             break;
278         case 'a':
279             i = MATCH_FAMILY; break;
280         }
281         break;
282     case 'c':
283         i = MATCH_CHARSET; break;
284     case 'a':
285         i = MATCH_ANTIALIAS; break;
286     case 'l':
287         i = MATCH_LANG; break;
288     case 's':
289         switch (object[1]) {
290         case 'p':
291             i = MATCH_SPACING; break;
292         case 't':
293             i = MATCH_STYLE; break;
294         case 'l':
295             i = MATCH_SLANT; break;
296         }
297         break;
298     case 'p':
299         i = MATCH_PIXEL_SIZE; break;
300     case 'w':
301         switch (object[1]) {
302         case 'i':
303             i = MATCH_WIDTH; break;
304         case 'e':
305             i = MATCH_WEIGHT; break;
306         }
307         break;
308     case 'r':
309         i = MATCH_RASTERIZER; break;
310     case 'o':
311         i = MATCH_OUTLINE; break;
312     }
313     if (i == -1 || 
314         FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
315                             (FcChar8 *) object) != 0)
316     {
317         if (bestValue)
318             *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
319         return FcTrue;
320     }
321     best = 1e99;
322     bestStrong = 1e99;
323     bestWeak = 1e99;
324     j = 0;
325     for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
326          v1 = FcValueListPtrU(v1)->next, v1_ptrU = FcValueListPtrU(v1))
327     {
328         for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); FcValueListPtrU(v2); 
329              v2 = FcValueListPtrU(v2)->next)
330         {
331             v = (*_FcMatchers[i].compare) (&v1_ptrU->value,
332                                            &v2_ptrU->value);
333             if (v < 0)
334             {
335                 *result = FcResultTypeMismatch;
336                 return FcFalse;
337             }
338             v = v * 100 + j;
339             if (v < best)
340             {
341                 if (bestValue)
342                     *bestValue = FcValueCanonicalize(&v2_ptrU->value);
343                 best = v;
344             }
345             if (v1_ptrU->binding == FcValueBindingStrong)
346             {
347                 if (v < bestStrong)
348                     bestStrong = v;
349             }
350             else
351             {
352                 if (v < bestWeak)
353                     bestWeak = v;
354             }
355         }
356         j++;
357     }
358     if (FcDebug () & FC_DBG_MATCHV)
359     {
360         printf (" %s: %g ", object, best);
361         FcValueListPrint (v1orig);
362         printf (", ");
363         FcValueListPrint (v2orig);
364         printf ("\n");
365     }
366     if (value)
367     {
368         int weak    = _FcMatchers[i].weak;
369         int strong  = _FcMatchers[i].strong;
370         if (weak == strong)
371             value[strong] += best;
372         else
373         {
374             value[weak] += bestWeak;
375             value[strong] += bestStrong;
376         }
377     }
378     return FcTrue;
379 }
380
381 /*
382  * Return a value indicating the distance between the two lists of
383  * values
384  */
385
386 static FcBool
387 FcCompare (FcPattern    *pat,
388            FcPattern    *fnt,
389            double       *value,
390            FcResult     *result)
391 {
392     int             i, i1, i2;
393     
394     for (i = 0; i < NUM_MATCH_VALUES; i++)
395         value[i] = 0.0;
396     
397     i1 = 0;
398     i2 = 0;
399     while (i1 < pat->num && i2 < fnt->num)
400     {
401         FcPatternElt *elt_i1 = FcPatternEltU(pat->elts)+i1;
402         FcPatternElt *elt_i2 = FcPatternEltU(fnt->elts)+i2;
403
404         i = FcObjectPtrCompare(elt_i1->object, elt_i2->object);
405         if (i > 0)
406             i2++;
407         else if (i < 0)
408             i1++;
409         else
410         {
411             if (!FcCompareValueList (elt_i1->object,
412                                      elt_i1->values, elt_i2->values,
413                                      0, value, result))
414                 return FcFalse;
415             i1++;
416             i2++;
417         }
418     }
419     return FcTrue;
420 }
421
422 FcPattern *
423 FcFontRenderPrepare (FcConfig       *config,
424                      FcPattern      *pat,
425                      FcPattern      *font)
426 {
427     FcPattern       *new;
428     int             i;
429     FcPatternElt    *fe, *pe;
430     FcValue         v;
431     FcResult        result;
432     
433     new = FcPatternCreate ();
434     if (!new)
435         return 0;
436     for (i = 0; i < font->num; i++)
437     {
438         fe = FcPatternEltU(font->elts)+i;
439         pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
440         if (pe)
441         {
442             if (!FcCompareValueList (pe->object, pe->values, 
443                                      fe->values, &v, 0, &result))
444             {
445                 FcPatternDestroy (new);
446                 return 0;
447             }
448         }
449         else
450             v = FcValueCanonicalize(&FcValueListPtrU(fe->values)->value);
451         FcPatternAdd (new, FcObjectPtrU(fe->object), v, FcFalse);
452     }
453     for (i = 0; i < pat->num; i++)
454     {
455         pe = FcPatternEltU(pat->elts)+i;
456         fe = FcPatternFindElt (font, FcObjectPtrU(pe->object));
457         if (!fe)
458             FcPatternAdd (new, FcObjectPtrU(pe->object), 
459                           FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
460     }
461
462     if (FcPatternFindElt (font, FC_FILE))
463         FcPatternTransferFullFname (new, font);
464
465     FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
466     return new;
467 }
468
469 FcPattern *
470 FcFontSetMatch (FcConfig    *config,
471                 FcFontSet   **sets,
472                 int         nsets,
473                 FcPattern   *p,
474                 FcResult    *result)
475 {
476     double          score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
477     int             f;
478     FcFontSet       *s;
479     FcPattern       *best;
480     int             i;
481     int             set;
482
483     for (i = 0; i < NUM_MATCH_VALUES; i++)
484         bestscore[i] = 0;
485     best = 0;
486     if (FcDebug () & FC_DBG_MATCH)
487     {
488         printf ("Match ");
489         FcPatternPrint (p);
490     }
491     if (!config)
492     {
493         config = FcConfigGetCurrent ();
494         if (!config)
495         {
496             *result = FcResultOutOfMemory;
497             return 0;
498         }
499     }
500     for (set = 0; set < nsets; set++)
501     {
502         s = sets[set];
503         if (!s)
504             continue;
505         for (f = 0; f < s->nfont; f++)
506         {
507             if (FcDebug () & FC_DBG_MATCHV)
508             {
509                 printf ("Font %d ", f);
510                 FcPatternPrint (s->fonts[f]);
511             }
512             if (!FcCompare (p, s->fonts[f], score, result))
513                 return 0;
514             if (FcDebug () & FC_DBG_MATCHV)
515             {
516                 printf ("Score");
517                 for (i = 0; i < NUM_MATCH_VALUES; i++)
518                 {
519                     printf (" %g", score[i]);
520                 }
521                 printf ("\n");
522             }
523             for (i = 0; i < NUM_MATCH_VALUES; i++)
524             {
525                 if (best && bestscore[i] < score[i])
526                     break;
527                 if (!best || score[i] < bestscore[i])
528                 {
529                     for (i = 0; i < NUM_MATCH_VALUES; i++)
530                         bestscore[i] = score[i];
531                     best = s->fonts[f];
532                     break;
533                 }
534             }
535         }
536     }
537     if (FcDebug () & FC_DBG_MATCH)
538     {
539         printf ("Best score");
540         for (i = 0; i < NUM_MATCH_VALUES; i++)
541             printf (" %g", bestscore[i]);
542         FcPatternPrint (best);
543     }
544     if (!best)
545     {
546         *result = FcResultNoMatch;
547         return 0;
548     }
549     return FcFontRenderPrepare (config, p, best);
550 }
551
552 FcPattern *
553 FcFontMatch (FcConfig   *config,
554              FcPattern  *p, 
555              FcResult   *result)
556 {
557     FcFontSet   *sets[2];
558     int         nsets;
559
560     if (!config)
561     {
562         config = FcConfigGetCurrent ();
563         if (!config)
564             return 0;
565     }
566     nsets = 0;
567     if (config->fonts[FcSetSystem])
568         sets[nsets++] = config->fonts[FcSetSystem];
569     if (config->fonts[FcSetApplication])
570         sets[nsets++] = config->fonts[FcSetApplication];
571     return FcFontSetMatch (config, sets, nsets, p, result);
572 }
573
574 typedef struct _FcSortNode {
575     FcPattern   *pattern;
576     double      score[NUM_MATCH_VALUES];
577 } FcSortNode;
578
579 static int
580 FcSortCompare (const void *aa, const void *ab)
581 {
582     FcSortNode  *a = *(FcSortNode **) aa;
583     FcSortNode  *b = *(FcSortNode **) ab;
584     double      *as = &a->score[0];
585     double      *bs = &b->score[0];
586     double      ad = 0, bd = 0;
587     int         i;
588
589     i = NUM_MATCH_VALUES;
590     while (i-- && (ad = *as++) == (bd = *bs++))
591         ;
592     return ad < bd ? -1 : ad > bd ? 1 : 0;
593 }
594
595 static FcBool
596 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
597 {
598     FcCharSet   *ncs;
599     FcSortNode  *node;
600
601     while (nnode--)
602     {
603         node = *n++;
604         if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == 
605             FcResultMatch)
606         {
607             /*
608              * If this font isn't a subset of the previous fonts,
609              * add it to the list
610              */
611             if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
612             {
613                 if (*cs)
614                 {
615                     ncs = FcCharSetUnion (ncs, *cs);
616                     if (!ncs)
617                         return FcFalse;
618                     FcCharSetDestroy (*cs);
619                 }
620                 else
621                     ncs = FcCharSetCopy (ncs);
622                 *cs = ncs;
623                 FcPatternReference (node->pattern);
624                 if (FcDebug () & FC_DBG_MATCH)
625                 {
626                     printf ("Add ");
627                     FcPatternPrint (node->pattern);
628                 }
629                 if (!FcFontSetAdd (fs, node->pattern))
630                 {
631                     FcPatternDestroy (node->pattern);
632                     return FcFalse;
633                 }
634             }
635         }
636     }
637     return FcTrue;
638 }
639
640 void
641 FcFontSetSortDestroy (FcFontSet *fs)
642 {
643     FcFontSetDestroy (fs);
644 }
645
646 FcFontSet *
647 FcFontSetSort (FcConfig     *config,
648                FcFontSet    **sets,
649                int          nsets,
650                FcPattern    *p,
651                FcBool       trim,
652                FcCharSet    **csp,
653                FcResult     *result)
654 {
655     FcFontSet       *ret;
656     FcFontSet       *s;
657     FcSortNode      *nodes;
658     FcSortNode      **nodeps, **nodep;
659     int             nnodes;
660     FcSortNode      *new;
661     FcCharSet       *cs;
662     int             set;
663     int             f;
664     int             i;
665     int             nPatternLang;
666     FcBool          *patternLangSat;
667     FcValue         patternLang;
668
669     if (FcDebug () & FC_DBG_MATCH)
670     {
671         printf ("Sort ");
672         FcPatternPrint (p);
673     }
674     nnodes = 0;
675     for (set = 0; set < nsets; set++)
676     {
677         s = sets[set];
678         if (!s)
679             continue;
680         nnodes += s->nfont;
681     }
682     if (!nnodes)
683         goto bail0;
684     
685     for (nPatternLang = 0;
686          FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
687          nPatternLang++)
688         ;
689         
690     /* freed below */
691     nodes = malloc (nnodes * sizeof (FcSortNode) + 
692                     nnodes * sizeof (FcSortNode *) +
693                     nPatternLang * sizeof (FcBool));
694     if (!nodes)
695         goto bail0;
696     nodeps = (FcSortNode **) (nodes + nnodes);
697     patternLangSat = (FcBool *) (nodeps + nnodes);
698     
699     new = nodes;
700     nodep = nodeps;
701     for (set = 0; set < nsets; set++)
702     {
703         s = sets[set];
704         if (!s)
705             continue;
706         for (f = 0; f < s->nfont; f++)
707         {
708             if (FcDebug () & FC_DBG_MATCHV)
709             {
710                 printf ("Font %d ", f);
711                 FcPatternPrint (s->fonts[f]);
712             }
713             new->pattern = s->fonts[f];
714             if (!FcCompare (p, new->pattern, new->score, result))
715                 goto bail1;
716             if (FcDebug () & FC_DBG_MATCHV)
717             {
718                 printf ("Score");
719                 for (i = 0; i < NUM_MATCH_VALUES; i++)
720                 {
721                     printf (" %g", new->score[i]);
722                 }
723                 printf ("\n");
724             }
725             *nodep = new;
726             new++;
727             nodep++;
728         }
729     }
730
731     nnodes = new - nodes;
732     
733     qsort (nodeps, nnodes, sizeof (FcSortNode *),
734            FcSortCompare);
735     
736     for (i = 0; i < nPatternLang; i++)
737         patternLangSat[i] = FcFalse;
738     
739     for (f = 0; f < nnodes; f++)
740     {
741         FcBool  satisfies = FcFalse;
742         /*
743          * If this node matches any language, go check
744          * which ones and satisfy those entries
745          */
746         if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
747         {
748             for (i = 0; i < nPatternLang; i++)
749             {
750                 FcValue     nodeLang;
751                 
752                 if (!patternLangSat[i] &&
753                     FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
754                     FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
755                 {
756                     double  compare = FcCompareLang (&patternLang, &nodeLang);
757                     if (compare >= 0 && compare < 2)
758                     {
759                         if (FcDebug () & FC_DBG_MATCHV)
760                         {
761                             FcChar8 *family;
762                             FcChar8 *style;
763
764                             if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
765                                 FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
766                                 printf ("Font %s:%s matches language %d\n", family, style, i);
767                         }
768                         patternLangSat[i] = FcTrue;
769                         satisfies = FcTrue;
770                         break;
771                     }
772                 }
773             }
774         }
775         if (!satisfies)
776             nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
777     }
778
779     /*
780      * Re-sort once the language issues have been settled
781      */
782     qsort (nodeps, nnodes, sizeof (FcSortNode *),
783            FcSortCompare);
784
785     ret = FcFontSetCreate ();
786     if (!ret)
787         goto bail1;
788
789     cs = 0;
790
791     if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
792         goto bail2;
793
794     if (csp)
795         *csp = cs;
796     else
797         FcCharSetDestroy (cs);
798
799     free (nodes);
800
801     return ret;
802
803 bail2:
804     if (cs)
805         FcCharSetDestroy (cs);
806     FcFontSetDestroy (ret);
807 bail1:
808     free (nodes);
809 bail0:
810     return 0;
811 }
812
813 FcFontSet *
814 FcFontSort (FcConfig    *config,
815             FcPattern   *p, 
816             FcBool      trim,
817             FcCharSet   **csp,
818             FcResult    *result)
819 {
820     FcFontSet   *sets[2];
821     int         nsets;
822
823     if (!config)
824     {
825         config = FcConfigGetCurrent ();
826         if (!config)
827             return 0;
828     }
829     nsets = 0;
830     if (config->fonts[FcSetSystem])
831         sets[nsets++] = config->fonts[FcSetSystem];
832     if (config->fonts[FcSetApplication])
833         sets[nsets++] = config->fonts[FcSetApplication];
834     return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
835 }