Revert to original FcFontSetMatch algorithm to avoid losing fonts.
[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 "fcint.h"
26 #include <string.h>
27 #include <ctype.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     FcObjectPtr     objectPtr;
178     double          (*compare) (FcValue *value1, FcValue *value2);
179     int             strong, weak;
180 } FcMatcher;
181
182 /*
183  * Order is significant, it defines the precedence of
184  * each value, earlier values are more significant than
185  * later values
186  */
187 static FcMatcher _FcMatchers [] = {
188     { FC_FOUNDRY,       0, FcCompareString,     0, 0 },
189 #define MATCH_FOUNDRY       0
190 #define MATCH_FOUNDRY_INDEX 0
191     
192     { FC_CHARSET,       0, FcCompareCharSet,    1, 1 },
193 #define MATCH_CHARSET       1
194 #define MATCH_CHARSET_INDEX 1
195     
196     { FC_FAMILY,        0, FcCompareFamily,     2, 4 },
197 #define MATCH_FAMILY        2
198 #define MATCH_FAMILY_STRONG_INDEX   2
199 #define MATCH_FAMILY_WEAK_INDEX     4
200     
201     { FC_LANG,          0, FcCompareLang,       3, 3 },
202 #define MATCH_LANG          3
203 #define MATCH_LANG_INDEX    3
204     
205     { FC_SPACING,       0, FcCompareNumber,     5, 5 },
206 #define MATCH_SPACING       4
207 #define MATCH_SPACING_INDEX 5
208     
209     { FC_PIXEL_SIZE,    0, FcCompareSize,       6, 6 },
210 #define MATCH_PIXEL_SIZE    5
211 #define MATCH_PIXEL_SIZE_INDEX  6
212     
213     { FC_STYLE,         0, FcCompareString,     7, 7 },
214 #define MATCH_STYLE         6
215 #define MATCH_STYLE_INDEX   7
216     
217     { FC_SLANT,         0, FcCompareNumber,     8, 8 },
218 #define MATCH_SLANT         7
219 #define MATCH_SLANT_INDEX   8
220     
221     { FC_WEIGHT,        0, FcCompareNumber,     9, 9 },
222 #define MATCH_WEIGHT        8
223 #define MATCH_WEIGHT_INDEX  9
224     
225     { FC_WIDTH,         0, FcCompareNumber,     10, 10 },
226 #define MATCH_WIDTH         9
227 #define MATCH_WIDTH_INDEX   10
228     
229     { FC_ANTIALIAS,     0, FcCompareBool,       11, 11 },
230 #define MATCH_ANTIALIAS     10
231 #define MATCH_ANTIALIAS_INDEX       11
232     
233     { FC_RASTERIZER,    0, FcCompareString,     12, 12 },
234 #define MATCH_RASTERIZER    11
235 #define MATCH_RASTERIZER_INDEX    12
236
237     { FC_OUTLINE,       0, FcCompareBool,       13, 13 },
238 #define MATCH_OUTLINE       12
239 #define MATCH_OUTLINE_INDEX         13
240
241     { FC_FONTVERSION,   0, FcCompareNumber,     14, 14 },
242 #define MATCH_FONTVERSION   13
243 #define MATCH_FONTVERSION_INDEX   14
244 };
245
246 #define NUM_MATCH_VALUES    15
247
248 static FcBool matchObjectPtrsInit = FcFalse;
249
250 static void
251 FcMatchObjectPtrsInit (void)
252 {
253     _FcMatchers[MATCH_FOUNDRY].objectPtr = FcObjectToPtr(FC_FOUNDRY);
254     _FcMatchers[MATCH_CHARSET].objectPtr = FcObjectToPtr(FC_CHARSET);
255     _FcMatchers[MATCH_FAMILY].objectPtr = FcObjectToPtr(FC_FAMILY);
256     _FcMatchers[MATCH_LANG].objectPtr = FcObjectToPtr(FC_LANG);
257     _FcMatchers[MATCH_SPACING].objectPtr = FcObjectToPtr(FC_SPACING);
258     _FcMatchers[MATCH_PIXEL_SIZE].objectPtr = FcObjectToPtr(FC_PIXEL_SIZE);
259     _FcMatchers[MATCH_STYLE].objectPtr = FcObjectToPtr(FC_STYLE);
260     _FcMatchers[MATCH_SLANT].objectPtr = FcObjectToPtr(FC_SLANT);
261     _FcMatchers[MATCH_WEIGHT].objectPtr = FcObjectToPtr(FC_WEIGHT);
262     _FcMatchers[MATCH_WIDTH].objectPtr = FcObjectToPtr(FC_WIDTH);
263     _FcMatchers[MATCH_ANTIALIAS].objectPtr = FcObjectToPtr(FC_ANTIALIAS);
264     _FcMatchers[MATCH_RASTERIZER].objectPtr = FcObjectToPtr(FC_RASTERIZER);
265     _FcMatchers[MATCH_OUTLINE].objectPtr = FcObjectToPtr(FC_OUTLINE);
266     _FcMatchers[MATCH_FONTVERSION].objectPtr = FcObjectToPtr(FC_FONTVERSION);
267     matchObjectPtrsInit = FcTrue;
268 }
269
270 static FcMatcher*
271 FcObjectPtrToMatcher (FcObjectPtr o)
272 {
273     int         i;
274     const char  *object = FcObjectPtrU(o);
275
276     i = -1;
277     switch (object[0]) {
278     case 'f':
279         switch (object[1]) {
280         case 'o':
281             switch (object[2]) {
282             case 'u':
283                 i = MATCH_FOUNDRY; break;
284             case 'n':
285                 i = MATCH_FONTVERSION; break;
286             }
287             break;
288         case 'a':
289             i = MATCH_FAMILY; break;
290         }
291         break;
292     case 'c':
293         i = MATCH_CHARSET; break;
294     case 'a':
295         i = MATCH_ANTIALIAS; break;
296     case 'l':
297         i = MATCH_LANG; break;
298     case 's':
299         switch (object[1]) {
300         case 'p':
301             i = MATCH_SPACING; break;
302         case 't':
303             i = MATCH_STYLE; break;
304         case 'l':
305             i = MATCH_SLANT; break;
306         }
307         break;
308     case 'p':
309         i = MATCH_PIXEL_SIZE; break;
310     case 'w':
311         switch (object[1]) {
312         case 'i':
313             i = MATCH_WIDTH; break;
314         case 'e':
315             i = MATCH_WEIGHT; break;
316         }
317         break;
318     case 'r':
319         i = MATCH_RASTERIZER; break;
320     case 'o':
321         i = MATCH_OUTLINE; break;
322     }
323
324     if (i < 0)
325         return 0;
326
327     if (!matchObjectPtrsInit)
328         FcMatchObjectPtrsInit();
329
330     if (o != _FcMatchers[i].objectPtr)
331         return 0;
332
333     return _FcMatchers+i;
334 }
335
336 static FcBool
337 FcCompareValueList (FcObjectPtr o,
338                     FcValueListPtr v1orig,      /* pattern */
339                     FcValueListPtr v2orig,      /* target */
340                     FcValue     *bestValue,
341                     double      *value,
342                     FcResult    *result)
343 {
344     FcValueListPtr  v1, v2;
345     FcValueList     *v1_ptrU, *v2_ptrU;
346     double          v, best, bestStrong, bestWeak;
347     int             j;
348     const char      *object = FcObjectPtrU(o);
349     FcMatcher       *match = FcObjectPtrToMatcher(o);
350
351     if (!match)
352     {
353         if (bestValue)
354             *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
355         return FcTrue;
356     }
357
358     best = 1e99;
359     bestStrong = 1e99;
360     bestWeak = 1e99;
361     j = 0;
362     for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
363          v1 = v1_ptrU->next, v1_ptrU = FcValueListPtrU(v1))
364     {
365         for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); v2_ptrU;
366              v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
367         {
368             v = (match->compare) (&v1_ptrU->value, &v2_ptrU->value);
369             if (v < 0)
370             {
371                 *result = FcResultTypeMismatch;
372                 return FcFalse;
373             }
374             v = v * 100 + j;
375             if (v < best)
376             {
377                 if (bestValue)
378                     *bestValue = FcValueCanonicalize(&v2_ptrU->value);
379                 best = v;
380             }
381             if (v1_ptrU->binding == FcValueBindingStrong)
382             {
383                 if (v < bestStrong)
384                     bestStrong = v;
385             }
386             else
387             {
388                 if (v < bestWeak)
389                     bestWeak = v;
390             }
391         }
392         j++;
393     }
394     if (FcDebug () & FC_DBG_MATCHV)
395     {
396         printf (" %s: %g ", object, best);
397         FcValueListPrint (v1orig);
398         printf (", ");
399         FcValueListPrint (v2orig);
400         printf ("\n");
401     }
402     if (value)
403     {
404         int weak    = match->weak;
405         int strong  = match->strong;
406         if (weak == strong)
407             value[strong] += best;
408         else
409         {
410             value[weak] += bestWeak;
411             value[strong] += bestStrong;
412         }
413     }
414     return FcTrue;
415 }
416
417 /*
418  * Return a value indicating the distance between the two lists of
419  * values
420  */
421
422 static FcBool
423 FcCompare (FcPattern    *pat,
424            FcPattern    *fnt,
425            double       *value,
426            FcResult     *result)
427 {
428     int             i, i1, i2;
429     
430     for (i = 0; i < NUM_MATCH_VALUES; i++)
431         value[i] = 0.0;
432     
433     i1 = 0;
434     i2 = 0;
435     while (i1 < pat->num && i2 < fnt->num)
436     {
437         FcPatternElt *elt_i1 = FcPatternEltU(pat->elts)+i1;
438         FcPatternElt *elt_i2 = FcPatternEltU(fnt->elts)+i2;
439
440         i = FcObjectPtrCompare(elt_i1->object, elt_i2->object);
441         if (i > 0)
442             i2++;
443         else if (i < 0)
444             i1++;
445         else
446         {
447             if (!FcCompareValueList (elt_i1->object,
448                                      elt_i1->values, elt_i2->values,
449                                      0, value, result))
450                 return FcFalse;
451             i1++;
452             i2++;
453         }
454     }
455     return FcTrue;
456 }
457
458 FcPattern *
459 FcFontRenderPrepare (FcConfig       *config,
460                      FcPattern      *pat,
461                      FcPattern      *font)
462 {
463     FcPattern       *new;
464     int             i;
465     FcPatternElt    *fe, *pe;
466     FcValue         v;
467     FcResult        result;
468     
469     new = FcPatternCreate ();
470     if (!new)
471         return 0;
472     for (i = 0; i < font->num; i++)
473     {
474         fe = FcPatternEltU(font->elts)+i;
475         pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
476         if (pe)
477         {
478             if (!FcCompareValueList (pe->object, pe->values, 
479                                      fe->values, &v, 0, &result))
480             {
481                 FcPatternDestroy (new);
482                 return 0;
483             }
484         }
485         else
486             v = FcValueCanonicalize(&FcValueListPtrU(fe->values)->value);
487         FcPatternAdd (new, FcObjectPtrU(fe->object), v, FcFalse);
488     }
489     for (i = 0; i < pat->num; i++)
490     {
491         pe = FcPatternEltU(pat->elts)+i;
492         fe = FcPatternFindElt (font, FcObjectPtrU(pe->object));
493         if (!fe)
494             FcPatternAdd (new, FcObjectPtrU(pe->object), 
495                           FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
496     }
497
498     FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
499     return new;
500 }
501
502 FcPattern *
503 FcFontSetMatch (FcConfig    *config,
504                 FcFontSet   **sets,
505                 int         nsets,
506                 FcPattern   *p,
507                 FcResult    *result)
508 {
509     double          score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
510     int             f;
511     FcFontSet       *s;
512     FcPattern       *best;
513     int             i;
514     int             set;
515
516     for (i = 0; i < NUM_MATCH_VALUES; i++)
517         bestscore[i] = 0;
518     best = 0;
519     if (FcDebug () & FC_DBG_MATCH)
520     {
521         printf ("Match ");
522         FcPatternPrint (p);
523     }
524     if (!config)
525     {
526         config = FcConfigGetCurrent ();
527         if (!config)
528             return 0;
529     }
530     for (set = 0; set < nsets; set++)
531     {
532         s = sets[set];
533         if (!s)
534             continue;
535         for (f = 0; f < s->nfont; f++)
536         {
537             if (FcDebug () & FC_DBG_MATCHV)
538             {
539                 printf ("Font %d ", f);
540                 FcPatternPrint (s->fonts[f]);
541             }
542             if (!FcCompare (p, s->fonts[f], score, result))
543                 return 0;
544             if (FcDebug () & FC_DBG_MATCHV)
545             {
546                 printf ("Score");
547                 for (i = 0; i < NUM_MATCH_VALUES; i++)
548                 {
549                     printf (" %g", score[i]);
550                 }
551                 printf ("\n");
552             }
553             for (i = 0; i < NUM_MATCH_VALUES; i++)
554             {
555                 if (best && bestscore[i] < score[i])
556                     break;
557                 if (!best || score[i] < bestscore[i])
558                 {
559                     for (i = 0; i < NUM_MATCH_VALUES; i++)
560                         bestscore[i] = score[i];
561                     best = s->fonts[f];
562                     break;
563                 }
564             }
565         }
566     }
567     if (FcDebug () & FC_DBG_MATCH)
568     {
569         printf ("Best score");
570         for (i = 0; i < NUM_MATCH_VALUES; i++)
571             printf (" %g", bestscore[i]);
572         FcPatternPrint (best);
573     }
574     if (!best)
575     {
576         *result = FcResultNoMatch;
577         return 0;
578     }
579     return FcFontRenderPrepare (config, p, best);
580 }
581
582 FcPattern *
583 FcFontMatch (FcConfig   *config,
584              FcPattern  *p, 
585              FcResult   *result)
586 {
587     FcFontSet   *sets[2];
588     int         nsets;
589
590     if (!config)
591     {
592         config = FcConfigGetCurrent ();
593         if (!config)
594             return 0;
595     }
596     nsets = 0;
597     if (config->fonts[FcSetSystem])
598         sets[nsets++] = config->fonts[FcSetSystem];
599     if (config->fonts[FcSetApplication])
600         sets[nsets++] = config->fonts[FcSetApplication];
601     return FcFontSetMatch (config, sets, nsets, p, result);
602 }
603
604 typedef struct _FcSortNode {
605     FcPattern   *pattern;
606     double      score[NUM_MATCH_VALUES];
607 } FcSortNode;
608
609 static int
610 FcSortCompare (const void *aa, const void *ab)
611 {
612     FcSortNode  *a = *(FcSortNode **) aa;
613     FcSortNode  *b = *(FcSortNode **) ab;
614     double      *as = &a->score[0];
615     double      *bs = &b->score[0];
616     double      ad = 0, bd = 0;
617     int         i;
618
619     i = NUM_MATCH_VALUES;
620     while (i-- && (ad = *as++) == (bd = *bs++))
621         ;
622     return ad < bd ? -1 : ad > bd ? 1 : 0;
623 }
624
625 static FcBool
626 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim, FcBool build_cs)
627 {
628     FcCharSet   *ncs;
629     FcSortNode  *node;
630
631     while (nnode--)
632     {
633         node = *n++;
634         if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == 
635             FcResultMatch)
636         {
637             /*
638              * If this font isn't a subset of the previous fonts,
639              * add it to the list
640              */
641             if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
642             {
643                 if (trim || build_cs)
644                 {
645                     if (*cs)
646                     {
647                         ncs = FcCharSetUnion (ncs, *cs);
648                         if (!ncs)
649                             return FcFalse;
650                         FcCharSetDestroy (*cs);
651                     }
652                     else
653                         ncs = FcCharSetCopy (ncs);
654                     *cs = ncs;
655                 }
656
657                 FcPatternReference (node->pattern);
658                 if (FcDebug () & FC_DBG_MATCH)
659                 {
660                     printf ("Add ");
661                     FcPatternPrint (node->pattern);
662                 }
663                 if (!FcFontSetAdd (fs, node->pattern))
664                 {
665                     FcPatternDestroy (node->pattern);
666                     return FcFalse;
667                 }
668             }
669         }
670     }
671     return FcTrue;
672 }
673
674 void
675 FcFontSetSortDestroy (FcFontSet *fs)
676 {
677     FcFontSetDestroy (fs);
678 }
679
680 FcFontSet *
681 FcFontSetSort (FcConfig     *config,
682                FcFontSet    **sets,
683                int          nsets,
684                FcPattern    *p,
685                FcBool       trim,
686                FcCharSet    **csp,
687                FcResult     *result)
688 {
689     FcFontSet       *ret;
690     FcFontSet       *s;
691     FcSortNode      *nodes;
692     FcSortNode      **nodeps, **nodep;
693     int             nnodes;
694     FcSortNode      *new;
695     FcCharSet       *cs;
696     int             set;
697     int             f;
698     int             i;
699     int             nPatternLang;
700     FcBool          *patternLangSat;
701     FcValue         patternLang;
702
703     if (FcDebug () & FC_DBG_MATCH)
704     {
705         printf ("Sort ");
706         FcPatternPrint (p);
707     }
708     nnodes = 0;
709     for (set = 0; set < nsets; set++)
710     {
711         s = sets[set];
712         if (!s)
713             continue;
714         nnodes += s->nfont;
715     }
716     if (!nnodes)
717         goto bail0;
718     
719     for (nPatternLang = 0;
720          FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
721          nPatternLang++)
722         ;
723         
724     /* freed below */
725     nodes = malloc (nnodes * sizeof (FcSortNode) + 
726                     nnodes * sizeof (FcSortNode *) +
727                     nPatternLang * sizeof (FcBool));
728     if (!nodes)
729         goto bail0;
730     nodeps = (FcSortNode **) (nodes + nnodes);
731     patternLangSat = (FcBool *) (nodeps + nnodes);
732     
733     new = nodes;
734     nodep = nodeps;
735     for (set = 0; set < nsets; set++)
736     {
737         s = sets[set];
738         if (!s)
739             continue;
740         for (f = 0; f < s->nfont; f++)
741         {
742             if (FcDebug () & FC_DBG_MATCHV)
743             {
744                 printf ("Font %d ", f);
745                 FcPatternPrint (s->fonts[f]);
746             }
747             new->pattern = s->fonts[f];
748             if (!FcCompare (p, new->pattern, new->score, result))
749                 goto bail1;
750             if (FcDebug () & FC_DBG_MATCHV)
751             {
752                 printf ("Score");
753                 for (i = 0; i < NUM_MATCH_VALUES; i++)
754                 {
755                     printf (" %g", new->score[i]);
756                 }
757                 printf ("\n");
758             }
759             *nodep = new;
760             new++;
761             nodep++;
762         }
763     }
764
765     nnodes = new - nodes;
766     
767     qsort (nodeps, nnodes, sizeof (FcSortNode *),
768            FcSortCompare);
769     
770     for (i = 0; i < nPatternLang; i++)
771         patternLangSat[i] = FcFalse;
772     
773     for (f = 0; f < nnodes; f++)
774     {
775         FcBool  satisfies = FcFalse;
776         /*
777          * If this node matches any language, go check
778          * which ones and satisfy those entries
779          */
780         if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
781         {
782             for (i = 0; i < nPatternLang; i++)
783             {
784                 FcValue     nodeLang;
785                 
786                 if (!patternLangSat[i] &&
787                     FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
788                     FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
789                 {
790                     double  compare = FcCompareLang (&patternLang, &nodeLang);
791                     if (compare >= 0 && compare < 2)
792                     {
793                         if (FcDebug () & FC_DBG_MATCHV)
794                         {
795                             FcChar8 *family;
796                             FcChar8 *style;
797
798                             if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
799                                 FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
800                                 printf ("Font %s:%s matches language %d\n", family, style, i);
801                         }
802                         patternLangSat[i] = FcTrue;
803                         satisfies = FcTrue;
804                         break;
805                     }
806                 }
807             }
808         }
809         if (!satisfies)
810             nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
811     }
812
813     /*
814      * Re-sort once the language issues have been settled
815      */
816     qsort (nodeps, nnodes, sizeof (FcSortNode *),
817            FcSortCompare);
818
819     ret = FcFontSetCreate ();
820     if (!ret)
821         goto bail1;
822
823     cs = 0;
824
825     if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim, (csp!=0)))
826         goto bail2;
827
828     if (csp)
829         *csp = cs;
830     else
831     {
832         if (cs)
833             FcCharSetDestroy (cs);
834     }
835
836     free (nodes);
837
838     return ret;
839
840 bail2:
841     if (cs)
842         FcCharSetDestroy (cs);
843     FcFontSetDestroy (ret);
844 bail1:
845     free (nodes);
846 bail0:
847     return 0;
848 }
849
850 FcFontSet *
851 FcFontSort (FcConfig    *config,
852             FcPattern   *p, 
853             FcBool      trim,
854             FcCharSet   **csp,
855             FcResult    *result)
856 {
857     FcFontSet   *sets[2];
858     int         nsets;
859
860     if (!config)
861     {
862         config = FcConfigGetCurrent ();
863         if (!config)
864             return 0;
865     }
866     nsets = 0;
867     if (config->fonts[FcSetSystem])
868         sets[nsets++] = config->fonts[FcSetSystem];
869     if (config->fonts[FcSetApplication])
870         sets[nsets++] = config->fonts[FcSetApplication];
871     return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
872 }