fcmatch: Set FcResultMatch at the end if the return value is valid.
[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     /* assuming that 'result' is initialized with FcResultNoMatch
505      * outside this function */
506     if (best)
507         *result = FcResultMatch;
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     *result = FcResultNoMatch;
526
527     if (!config)
528     {
529         config = FcConfigGetCurrent ();
530         if (!config)
531             return 0;
532     }
533     best = FcFontSetMatchInternal (config, sets, nsets, p, result);
534     if (best)
535         return FcFontRenderPrepare (config, p, best);
536     else
537         return NULL;
538 }
539
540 FcPattern *
541 FcFontMatch (FcConfig   *config,
542              FcPattern  *p,
543              FcResult   *result)
544 {
545     FcFontSet   *sets[2];
546     int         nsets;
547     FcPattern   *best;
548
549     assert (p != NULL);
550     assert (result != NULL);
551
552     *result = FcResultNoMatch;
553
554     if (!config)
555     {
556         config = FcConfigGetCurrent ();
557         if (!config)
558             return 0;
559     }
560     nsets = 0;
561     if (config->fonts[FcSetSystem])
562         sets[nsets++] = config->fonts[FcSetSystem];
563     if (config->fonts[FcSetApplication])
564         sets[nsets++] = config->fonts[FcSetApplication];
565
566     best = FcFontSetMatchInternal (config, sets, nsets, p, result);
567     if (best)
568         return FcFontRenderPrepare (config, p, best);
569     else
570         return NULL;
571 }
572
573 typedef struct _FcSortNode {
574     FcPattern   *pattern;
575     double      score[NUM_MATCH_VALUES];
576 } FcSortNode;
577
578 static int
579 FcSortCompare (const void *aa, const void *ab)
580 {
581     FcSortNode  *a = *(FcSortNode **) aa;
582     FcSortNode  *b = *(FcSortNode **) ab;
583     double      *as = &a->score[0];
584     double      *bs = &b->score[0];
585     double      ad = 0, bd = 0;
586     int         i;
587
588     i = NUM_MATCH_VALUES;
589     while (i-- && (ad = *as++) == (bd = *bs++))
590         ;
591     return ad < bd ? -1 : ad > bd ? 1 : 0;
592 }
593
594 static FcBool
595 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
596 {
597     FcBool ret = FcFalse;
598     FcCharSet *cs;
599
600     cs = 0;
601     if (trim || csp)
602     {
603         cs = FcCharSetCreate ();
604         if (cs == NULL)
605             goto bail;
606     }
607
608     while (nnode--)
609     {
610         FcSortNode      *node = *n++;
611         FcBool          adds_chars = FcFalse;
612
613         /*
614          * Only fetch node charset if we'd need it
615          */
616         if (cs)
617         {
618             FcCharSet   *ncs;
619
620             if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
621                 FcResultMatch)
622                 continue;
623
624             if (!FcCharSetMerge (cs, ncs, &adds_chars))
625                 goto bail;
626         }
627
628         /*
629          * If this font isn't a subset of the previous fonts,
630          * add it to the list
631          */
632         if (!trim || adds_chars)
633         {
634             FcPatternReference (node->pattern);
635             if (FcDebug () & FC_DBG_MATCHV)
636             {
637                 printf ("Add ");
638                 FcPatternPrint (node->pattern);
639             }
640             if (!FcFontSetAdd (fs, node->pattern))
641             {
642                 FcPatternDestroy (node->pattern);
643                 goto bail;
644             }
645         }
646     }
647     if (csp)
648     {
649         *csp = cs;
650         cs = 0;
651     }
652
653     ret = FcTrue;
654
655 bail:
656     if (cs)
657         FcCharSetDestroy (cs);
658
659     return ret;
660 }
661
662 void
663 FcFontSetSortDestroy (FcFontSet *fs)
664 {
665     FcFontSetDestroy (fs);
666 }
667
668 FcFontSet *
669 FcFontSetSort (FcConfig     *config,
670                FcFontSet    **sets,
671                int          nsets,
672                FcPattern    *p,
673                FcBool       trim,
674                FcCharSet    **csp,
675                FcResult     *result)
676 {
677     FcFontSet       *ret;
678     FcFontSet       *s;
679     FcSortNode      *nodes;
680     FcSortNode      **nodeps, **nodep;
681     int             nnodes;
682     FcSortNode      *new;
683     int             set;
684     int             f;
685     int             i;
686     int             nPatternLang;
687     FcBool          *patternLangSat;
688     FcValue         patternLang;
689
690     assert (sets != NULL);
691     assert (p != NULL);
692     assert (result != NULL);
693
694     /* There are some implementation that relying on the result of
695      * "result" to check if the return value of FcFontSetSort
696      * is valid or not.
697      * So we should initialize it to the conservative way since
698      * this function doesn't return NULL anymore.
699      */
700     if (result)
701         *result = FcResultNoMatch;
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         return FcFontSetCreate ();
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] < 2000)
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] = 10000.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     if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
824         goto bail2;
825
826     free (nodes);
827
828     if (FcDebug() & FC_DBG_MATCH)
829     {
830         printf ("First font ");
831         FcPatternPrint (ret->fonts[0]);
832     }
833     if (ret->nfont > 0)
834         *result = FcResultMatch;
835
836     return ret;
837
838 bail2:
839     FcFontSetDestroy (ret);
840 bail1:
841     free (nodes);
842 bail0:
843     return 0;
844 }
845
846 FcFontSet *
847 FcFontSort (FcConfig    *config,
848             FcPattern   *p,
849             FcBool      trim,
850             FcCharSet   **csp,
851             FcResult    *result)
852 {
853     FcFontSet   *sets[2];
854     int         nsets;
855
856     assert (p != NULL);
857     assert (result != NULL);
858
859     *result = FcResultNoMatch;
860
861     if (!config)
862     {
863         config = FcConfigGetCurrent ();
864         if (!config)
865             return 0;
866     }
867     nsets = 0;
868     if (config->fonts[FcSetSystem])
869         sets[nsets++] = config->fonts[FcSetSystem];
870     if (config->fonts[FcSetApplication])
871         sets[nsets++] = config->fonts[FcSetApplication];
872     return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
873 }
874 #define __fcmatch__
875 #include "fcaliastail.h"
876 #undef __fcmatch__