bc75aa619cfce65c5bfe3f0ce587d26df579d614
[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 (const char  *object,
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     
261     /*
262      * Locate the possible matching entry by examining the
263      * first few characters in object
264      */
265     i = -1;
266     switch (FcToLower (object[0])) {
267     case 'f':
268         switch (FcToLower (object[1])) {
269         case 'o':
270             switch (FcToLower (object[2])) {
271             case 'u':
272                 i = MATCH_FOUNDRY; break;
273             case 'n':
274                 i = MATCH_FONTVERSION; break;
275             }
276             break;
277         case 'a':
278             i = MATCH_FAMILY; break;
279         }
280         break;
281     case 'c':
282         i = MATCH_CHARSET; break;
283     case 'a':
284         i = MATCH_ANTIALIAS; break;
285     case 'l':
286         i = MATCH_LANG; break;
287     case 's':
288         switch (FcToLower (object[1])) {
289         case 'p':
290             i = MATCH_SPACING; break;
291         case 't':
292             i = MATCH_STYLE; break;
293         case 'l':
294             i = MATCH_SLANT; break;
295         }
296         break;
297     case 'p':
298         i = MATCH_PIXEL_SIZE; break;
299     case 'w':
300         switch (FcToLower (object[1])) {
301         case 'i':
302             i = MATCH_WIDTH; break;
303         case 'e':
304             i = MATCH_WEIGHT; break;
305         }
306         break;
307     case 'r':
308         i = MATCH_RASTERIZER; break;
309     case 'o':
310         i = MATCH_OUTLINE; break;
311     }
312     if (i == -1 || 
313         FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
314                             (FcChar8 *) object) != 0)
315     {
316         if (bestValue)
317             *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
318         return FcTrue;
319     }
320 #if 0
321     for (i = 0; i < NUM_MATCHER; i++)
322     {
323         if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
324                                  (FcChar8 *) object))
325             break;
326     }
327     if (i == NUM_MATCHER)
328     {
329         if (bestValue)
330             *bestValue = v2orig->value;
331         return FcTrue;
332     }
333 #endif
334     best = 1e99;
335     bestStrong = 1e99;
336     bestWeak = 1e99;
337     j = 0;
338     for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
339          v1 = FcValueListPtrU(v1)->next, v1_ptrU = FcValueListPtrU(v1))
340     {
341         for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); FcValueListPtrU(v2); 
342              v2 = FcValueListPtrU(v2)->next)
343         {
344             v = (*_FcMatchers[i].compare) (&v1_ptrU->value,
345                                            &v2_ptrU->value);
346             if (v < 0)
347             {
348                 *result = FcResultTypeMismatch;
349                 return FcFalse;
350             }
351             if (FcDebug () & FC_DBG_MATCHV)
352                 printf (" v %g j %d ", v, j);
353             v = v * 100 + j;
354             if (v < best)
355             {
356                 if (bestValue)
357                     *bestValue = FcValueCanonicalize(&v2_ptrU->value);
358                 best = v;
359             }
360             if (v1_ptrU->binding == FcValueBindingStrong)
361             {
362                 if (v < bestStrong)
363                     bestStrong = v;
364             }
365             else
366             {
367                 if (v < bestWeak)
368                     bestWeak = v;
369             }
370         }
371         j++;
372     }
373     if (FcDebug () & FC_DBG_MATCHV)
374     {
375         printf (" %s: %g ", object, best);
376         FcValueListPrint (v1orig);
377         printf (", ");
378         FcValueListPrint (v2orig);
379         printf ("\n");
380     }
381     if (value)
382     {
383         int weak    = _FcMatchers[i].weak;
384         int strong  = _FcMatchers[i].strong;
385         if (weak == strong)
386             value[strong] += best;
387         else
388         {
389             value[weak] += bestWeak;
390             value[strong] += bestStrong;
391         }
392     }
393     return FcTrue;
394 }
395
396 /*
397  * Return a value indicating the distance between the two lists of
398  * values
399  */
400
401 static FcBool
402 FcCompare (FcPattern    *pat,
403            FcPattern    *fnt,
404            double       *value,
405            FcResult     *result)
406 {
407     int             i, i1, i2;
408     
409     for (i = 0; i < NUM_MATCH_VALUES; i++)
410         value[i] = 0.0;
411     
412     i1 = 0;
413     i2 = 0;
414     while (i1 < pat->num && i2 < fnt->num)
415     {
416         FcPatternElt *elt_i1 = FcPatternEltU(pat->elts)+i1;
417         FcPatternElt *elt_i2 = FcPatternEltU(fnt->elts)+i2;
418
419         i = FcObjectPtrCompare(elt_i1->object, elt_i2->object);
420         if (i > 0)
421             i2++;
422         else if (i < 0)
423             i1++;
424         else
425         {
426             if (!FcCompareValueList (FcObjectPtrU(elt_i1->object), 
427                                      elt_i1->values, elt_i2->values,
428                                      0, value, result))
429                 return FcFalse;
430             i1++;
431             i2++;
432         }
433     }
434     return FcTrue;
435 }
436
437 FcPattern *
438 FcFontRenderPrepare (FcConfig       *config,
439                      FcPattern      *pat,
440                      FcPattern      *font)
441 {
442     FcPattern       *new;
443     int             i;
444     FcPatternElt    *fe, *pe;
445     FcValue         v;
446     FcResult        result;
447     
448     new = FcPatternCreate ();
449     if (!new)
450         return 0;
451     for (i = 0; i < font->num; i++)
452     {
453         fe = FcPatternEltU(font->elts)+i;
454         pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
455         if (pe)
456         {
457             if (!FcCompareValueList (FcObjectPtrU(pe->object), pe->values, 
458                                      fe->values, &v, 0, &result))
459             {
460                 FcPatternDestroy (new);
461                 return 0;
462             }
463         }
464         else
465             v = FcValueCanonicalize(&FcValueListPtrU(fe->values)->value);
466         FcPatternAdd (new, FcObjectPtrU(fe->object), v, FcFalse);
467     }
468     for (i = 0; i < pat->num; i++)
469     {
470         pe = FcPatternEltU(pat->elts)+i;
471         fe = FcPatternFindElt (font, FcObjectPtrU(pe->object));
472         if (!fe)
473             FcPatternAdd (new, FcObjectPtrU(pe->object), 
474                           FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
475     }
476
477     if (FcPatternFindElt (font, FC_FILE))
478         FcPatternTransferFullFname (new, font);
479
480     FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
481     return new;
482 }
483
484 FcPattern *
485 FcFontSetMatch (FcConfig    *config,
486                 FcFontSet   **sets,
487                 int         nsets,
488                 FcPattern   *p,
489                 FcResult    *result)
490 {
491     double          score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
492     int             f;
493     FcFontSet       *s;
494     FcPattern       *best;
495     int             i;
496     int             set;
497
498     for (i = 0; i < NUM_MATCH_VALUES; i++)
499         bestscore[i] = 0;
500     best = 0;
501     if (FcDebug () & FC_DBG_MATCH)
502     {
503         printf ("Match ");
504         FcPatternPrint (p);
505     }
506     if (!config)
507     {
508         config = FcConfigGetCurrent ();
509         if (!config)
510         {
511             *result = FcResultOutOfMemory;
512             return 0;
513         }
514     }
515     for (set = 0; set < nsets; set++)
516     {
517         s = sets[set];
518         if (!s)
519             continue;
520         for (f = 0; f < s->nfont; f++)
521         {
522             if (FcDebug () & FC_DBG_MATCHV)
523             {
524                 printf ("Font %d ", f);
525                 FcPatternPrint (s->fonts[f]);
526             }
527             if (!FcCompare (p, s->fonts[f], score, result))
528                 return 0;
529             if (FcDebug () & FC_DBG_MATCHV)
530             {
531                 printf ("Score");
532                 for (i = 0; i < NUM_MATCH_VALUES; i++)
533                 {
534                     printf (" %g", score[i]);
535                 }
536                 printf ("\n");
537             }
538             for (i = 0; i < NUM_MATCH_VALUES; i++)
539             {
540                 if (best && bestscore[i] < score[i])
541                     break;
542                 if (!best || score[i] < bestscore[i])
543                 {
544                     for (i = 0; i < NUM_MATCH_VALUES; i++)
545                         bestscore[i] = score[i];
546                     best = s->fonts[f];
547                     break;
548                 }
549             }
550         }
551     }
552     if (FcDebug () & FC_DBG_MATCH)
553     {
554         printf ("Best score");
555         for (i = 0; i < NUM_MATCH_VALUES; i++)
556             printf (" %g", bestscore[i]);
557         FcPatternPrint (best);
558     }
559     if (!best)
560     {
561         *result = FcResultNoMatch;
562         return 0;
563     }
564     return FcFontRenderPrepare (config, p, best);
565 }
566
567 FcPattern *
568 FcFontMatch (FcConfig   *config,
569              FcPattern  *p, 
570              FcResult   *result)
571 {
572     FcFontSet   *sets[2];
573     int         nsets;
574
575     if (!config)
576     {
577         config = FcConfigGetCurrent ();
578         if (!config)
579             return 0;
580     }
581     nsets = 0;
582     if (config->fonts[FcSetSystem])
583         sets[nsets++] = config->fonts[FcSetSystem];
584     if (config->fonts[FcSetApplication])
585         sets[nsets++] = config->fonts[FcSetApplication];
586     return FcFontSetMatch (config, sets, nsets, p, result);
587 }
588
589 typedef struct _FcSortNode {
590     FcPattern   *pattern;
591     double      score[NUM_MATCH_VALUES];
592 } FcSortNode;
593
594 static int
595 FcSortCompare (const void *aa, const void *ab)
596 {
597     FcSortNode  *a = *(FcSortNode **) aa;
598     FcSortNode  *b = *(FcSortNode **) ab;
599     double      *as = &a->score[0];
600     double      *bs = &b->score[0];
601     double      ad = 0, bd = 0;
602     int         i;
603
604     i = NUM_MATCH_VALUES;
605     while (i-- && (ad = *as++) == (bd = *bs++))
606         ;
607     return ad < bd ? -1 : ad > bd ? 1 : 0;
608 }
609
610 static FcBool
611 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
612 {
613     FcCharSet   *ncs;
614     FcSortNode  *node;
615
616     while (nnode--)
617     {
618         node = *n++;
619         if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == 
620             FcResultMatch)
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 (*cs)
629                 {
630                     ncs = FcCharSetUnion (ncs, *cs);
631                     if (!ncs)
632                         return FcFalse;
633                     FcCharSetDestroy (*cs);
634                 }
635                 else
636                     ncs = FcCharSetCopy (ncs);
637                 *cs = ncs;
638                 FcPatternReference (node->pattern);
639                 if (FcDebug () & FC_DBG_MATCH)
640                 {
641                     printf ("Add ");
642                     FcPatternPrint (node->pattern);
643                 }
644                 if (!FcFontSetAdd (fs, node->pattern))
645                 {
646                     FcPatternDestroy (node->pattern);
647                     return FcFalse;
648                 }
649             }
650         }
651     }
652     return FcTrue;
653 }
654
655 void
656 FcFontSetSortDestroy (FcFontSet *fs)
657 {
658     FcFontSetDestroy (fs);
659 }
660
661 FcFontSet *
662 FcFontSetSort (FcConfig     *config,
663                FcFontSet    **sets,
664                int          nsets,
665                FcPattern    *p,
666                FcBool       trim,
667                FcCharSet    **csp,
668                FcResult     *result)
669 {
670     FcFontSet       *ret;
671     FcFontSet       *s;
672     FcSortNode      *nodes;
673     FcSortNode      **nodeps, **nodep;
674     int             nnodes;
675     FcSortNode      *new;
676     FcCharSet       *cs;
677     int             set;
678     int             f;
679     int             i;
680     int             nPatternLang;
681     FcBool          *patternLangSat;
682     FcValue         patternLang;
683
684     if (FcDebug () & FC_DBG_MATCH)
685     {
686         printf ("Sort ");
687         FcPatternPrint (p);
688     }
689     nnodes = 0;
690     for (set = 0; set < nsets; set++)
691     {
692         s = sets[set];
693         if (!s)
694             continue;
695         nnodes += s->nfont;
696     }
697     if (!nnodes)
698         goto bail0;
699     
700     for (nPatternLang = 0;
701          FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
702          nPatternLang++)
703         ;
704         
705     /* freed below */
706     nodes = malloc (nnodes * sizeof (FcSortNode) + 
707                     nnodes * sizeof (FcSortNode *) +
708                     nPatternLang * sizeof (FcBool));
709     if (!nodes)
710         goto bail0;
711     nodeps = (FcSortNode **) (nodes + nnodes);
712     patternLangSat = (FcBool *) (nodeps + nnodes);
713     
714     new = nodes;
715     nodep = nodeps;
716     for (set = 0; set < nsets; set++)
717     {
718         s = sets[set];
719         if (!s)
720             continue;
721         for (f = 0; f < s->nfont; f++)
722         {
723             if (FcDebug () & FC_DBG_MATCHV)
724             {
725                 printf ("Font %d ", f);
726                 FcPatternPrint (s->fonts[f]);
727             }
728             new->pattern = s->fonts[f];
729             if (!FcCompare (p, new->pattern, new->score, result))
730                 goto bail1;
731             if (FcDebug () & FC_DBG_MATCHV)
732             {
733                 printf ("Score");
734                 for (i = 0; i < NUM_MATCH_VALUES; i++)
735                 {
736                     printf (" %g", new->score[i]);
737                 }
738                 printf ("\n");
739             }
740             *nodep = new;
741             new++;
742             nodep++;
743         }
744     }
745
746     nnodes = new - nodes;
747     
748     qsort (nodeps, nnodes, sizeof (FcSortNode *),
749            FcSortCompare);
750     
751     for (i = 0; i < nPatternLang; i++)
752         patternLangSat[i] = FcFalse;
753     
754     for (f = 0; f < nnodes; f++)
755     {
756         FcBool  satisfies = FcFalse;
757         /*
758          * If this node matches any language, go check
759          * which ones and satisfy those entries
760          */
761         if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
762         {
763             for (i = 0; i < nPatternLang; i++)
764             {
765                 FcValue     nodeLang;
766                 
767                 if (!patternLangSat[i] &&
768                     FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
769                     FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
770                 {
771                     double  compare = FcCompareLang (&patternLang, &nodeLang);
772                     if (compare >= 0 && compare < 2)
773                     {
774                         if (FcDebug () & FC_DBG_MATCHV)
775                         {
776                             FcChar8 *family;
777                             FcChar8 *style;
778
779                             if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
780                                 FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
781                                 printf ("Font %s:%s matches language %d\n", family, style, i);
782                         }
783                         patternLangSat[i] = FcTrue;
784                         satisfies = FcTrue;
785                         break;
786                     }
787                 }
788             }
789         }
790         if (!satisfies)
791             nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
792     }
793
794     /*
795      * Re-sort once the language issues have been settled
796      */
797     qsort (nodeps, nnodes, sizeof (FcSortNode *),
798            FcSortCompare);
799
800     ret = FcFontSetCreate ();
801     if (!ret)
802         goto bail1;
803
804     cs = 0;
805
806     if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
807         goto bail2;
808
809     if (csp)
810         *csp = cs;
811     else
812         FcCharSetDestroy (cs);
813
814     free (nodes);
815
816     return ret;
817
818 bail2:
819     if (cs)
820         FcCharSetDestroy (cs);
821     FcFontSetDestroy (ret);
822 bail1:
823     free (nodes);
824 bail0:
825     return 0;
826 }
827
828 FcFontSet *
829 FcFontSort (FcConfig    *config,
830             FcPattern   *p, 
831             FcBool      trim,
832             FcCharSet   **csp,
833             FcResult    *result)
834 {
835     FcFontSet   *sets[2];
836     int         nsets;
837
838     if (!config)
839     {
840         config = FcConfigGetCurrent ();
841         if (!config)
842             return 0;
843     }
844     nsets = 0;
845     if (config->fonts[FcSetSystem])
846         sets[nsets++] = config->fonts[FcSetSystem];
847     if (config->fonts[FcSetApplication])
848         sets[nsets++] = config->fonts[FcSetApplication];
849     return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
850 }