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