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