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