]> git.wh0rd.org Git - fontconfig.git/blob - src/fcmatch.c
Don't kill fonts because they don't declare an element that's being matched
[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     FcObjectPtr     objectPtr;
178     double          (*compare) (FcValue *value1, FcValue *value2);
179     int             strong, weak;
180 } FcMatcher;
181
182 /*
183  * Order is significant, it defines the precedence of
184  * each value, earlier values are more significant than
185  * later values
186  */
187 static FcMatcher _FcMatchers [] = {
188     { FC_FOUNDRY,       0, FcCompareString,     0, 0 },
189 #define MATCH_FOUNDRY       0
190 #define MATCH_FOUNDRY_INDEX 0
191     
192     { FC_CHARSET,       0, FcCompareCharSet,    1, 1 },
193 #define MATCH_CHARSET       1
194 #define MATCH_CHARSET_INDEX 1
195     
196     { FC_FAMILY,        0, FcCompareFamily,     2, 4 },
197 #define MATCH_FAMILY        2
198 #define MATCH_FAMILY_STRONG_INDEX   2
199 #define MATCH_FAMILY_WEAK_INDEX     4
200     
201     { FC_LANG,          0, FcCompareLang,       3, 3 },
202 #define MATCH_LANG          3
203 #define MATCH_LANG_INDEX    3
204     
205     { FC_SPACING,       0, FcCompareNumber,     5, 5 },
206 #define MATCH_SPACING       4
207 #define MATCH_SPACING_INDEX 5
208     
209     { FC_PIXEL_SIZE,    0, FcCompareSize,       6, 6 },
210 #define MATCH_PIXEL_SIZE    5
211 #define MATCH_PIXEL_SIZE_INDEX  6
212     
213     { FC_STYLE,         0, FcCompareString,     7, 7 },
214 #define MATCH_STYLE         6
215 #define MATCH_STYLE_INDEX   7
216     
217     { FC_SLANT,         0, FcCompareNumber,     8, 8 },
218 #define MATCH_SLANT         7
219 #define MATCH_SLANT_INDEX   8
220     
221     { FC_WEIGHT,        0, FcCompareNumber,     9, 9 },
222 #define MATCH_WEIGHT        8
223 #define MATCH_WEIGHT_INDEX  9
224     
225     { FC_WIDTH,         0, FcCompareNumber,     10, 10 },
226 #define MATCH_WIDTH         9
227 #define MATCH_WIDTH_INDEX   10
228     
229     { FC_ANTIALIAS,     0, FcCompareBool,       11, 11 },
230 #define MATCH_ANTIALIAS     10
231 #define MATCH_ANTIALIAS_INDEX       11
232     
233     { FC_RASTERIZER,    0, FcCompareString,     12, 12 },
234 #define MATCH_RASTERIZER    11
235 #define MATCH_RASTERIZER_INDEX    12
236
237     { FC_OUTLINE,       0, FcCompareBool,       13, 13 },
238 #define MATCH_OUTLINE       12
239 #define MATCH_OUTLINE_INDEX         13
240
241     { FC_FONTVERSION,   0, FcCompareNumber,     14, 14 },
242 #define MATCH_FONTVERSION   13
243 #define MATCH_FONTVERSION_INDEX   14
244 };
245
246 #define NUM_MATCH_VALUES    15
247
248 static FcBool matchObjectPtrsInit = FcFalse;
249
250 static void
251 FcMatchObjectPtrsInit (void)
252 {
253     _FcMatchers[MATCH_FOUNDRY].objectPtr = FcObjectToPtr(FC_FOUNDRY);
254     _FcMatchers[MATCH_CHARSET].objectPtr = FcObjectToPtr(FC_CHARSET);
255     _FcMatchers[MATCH_FAMILY].objectPtr = FcObjectToPtr(FC_FAMILY);
256     _FcMatchers[MATCH_LANG].objectPtr = FcObjectToPtr(FC_LANG);
257     _FcMatchers[MATCH_SPACING].objectPtr = FcObjectToPtr(FC_SPACING);
258     _FcMatchers[MATCH_PIXEL_SIZE].objectPtr = FcObjectToPtr(FC_PIXEL_SIZE);
259     _FcMatchers[MATCH_STYLE].objectPtr = FcObjectToPtr(FC_STYLE);
260     _FcMatchers[MATCH_SLANT].objectPtr = FcObjectToPtr(FC_SLANT);
261     _FcMatchers[MATCH_WEIGHT].objectPtr = FcObjectToPtr(FC_WEIGHT);
262     _FcMatchers[MATCH_WIDTH].objectPtr = FcObjectToPtr(FC_WIDTH);
263     _FcMatchers[MATCH_ANTIALIAS].objectPtr = FcObjectToPtr(FC_ANTIALIAS);
264     _FcMatchers[MATCH_RASTERIZER].objectPtr = FcObjectToPtr(FC_RASTERIZER);
265     _FcMatchers[MATCH_OUTLINE].objectPtr = FcObjectToPtr(FC_OUTLINE);
266     _FcMatchers[MATCH_FONTVERSION].objectPtr = FcObjectToPtr(FC_FONTVERSION);
267     matchObjectPtrsInit = FcTrue;
268 }
269
270 static FcMatcher*
271 FcObjectPtrToMatcher (FcObjectPtr o)
272 {
273     int         i;
274     const char  *object = FcObjectPtrU(o);
275
276     i = -1;
277     switch (object[0]) {
278     case 'f':
279         switch (object[1]) {
280         case 'o':
281             switch (object[2]) {
282             case 'u':
283                 i = MATCH_FOUNDRY; break;
284             case 'n':
285                 i = MATCH_FONTVERSION; break;
286             }
287             break;
288         case 'a':
289             i = MATCH_FAMILY; break;
290         }
291         break;
292     case 'c':
293         i = MATCH_CHARSET; break;
294     case 'a':
295         i = MATCH_ANTIALIAS; break;
296     case 'l':
297         i = MATCH_LANG; break;
298     case 's':
299         switch (object[1]) {
300         case 'p':
301             i = MATCH_SPACING; break;
302         case 't':
303             i = MATCH_STYLE; break;
304         case 'l':
305             i = MATCH_SLANT; break;
306         }
307         break;
308     case 'p':
309         i = MATCH_PIXEL_SIZE; break;
310     case 'w':
311         switch (object[1]) {
312         case 'i':
313             i = MATCH_WIDTH; break;
314         case 'e':
315             i = MATCH_WEIGHT; break;
316         }
317         break;
318     case 'r':
319         i = MATCH_RASTERIZER; break;
320     case 'o':
321         i = MATCH_OUTLINE; break;
322     }
323
324     if (i < 0)
325         return 0;
326
327     if (!matchObjectPtrsInit)
328         FcMatchObjectPtrsInit();
329
330     if (o != _FcMatchers[i].objectPtr)
331         return 0;
332
333     return _FcMatchers+i;
334 }
335
336 static FcBool
337 FcCompareValueList (FcObjectPtr o,
338                     FcValueListPtr v1orig,      /* pattern */
339                     FcValueListPtr v2orig,      /* target */
340                     FcValue     *bestValue,
341                     double      *value,
342                     FcResult    *result)
343 {
344     FcValueListPtr  v1, v2;
345     FcValueList     *v1_ptrU, *v2_ptrU;
346     double          v, best, bestStrong, bestWeak;
347     int             j;
348     const char      *object = FcObjectPtrU(o);
349     FcMatcher       *match = FcObjectPtrToMatcher(o);
350
351     if (!match)
352     {
353         if (bestValue)
354             *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
355         return FcTrue;
356     }
357
358     best = 1e99;
359     bestStrong = 1e99;
360     bestWeak = 1e99;
361     j = 0;
362     for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
363          v1 = v1_ptrU->next, v1_ptrU = FcValueListPtrU(v1))
364     {
365         for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); v2_ptrU;
366              v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
367         {
368             v = (match->compare) (&v1_ptrU->value, &v2_ptrU->value);
369             if (v < 0)
370             {
371                 *result = FcResultTypeMismatch;
372                 return FcFalse;
373             }
374             v = v * 100 + j;
375             if (v < best)
376             {
377                 if (bestValue)
378                     *bestValue = FcValueCanonicalize(&v2_ptrU->value);
379                 best = v;
380             }
381             if (v1_ptrU->binding == FcValueBindingStrong)
382             {
383                 if (v < bestStrong)
384                     bestStrong = v;
385             }
386             else
387             {
388                 if (v < bestWeak)
389                     bestWeak = v;
390             }
391         }
392         j++;
393     }
394     if (FcDebug () & FC_DBG_MATCHV)
395     {
396         printf (" %s: %g ", object, best);
397         FcValueListPrint (v1orig);
398         printf (", ");
399         FcValueListPrint (v2orig);
400         printf ("\n");
401     }
402     if (value)
403     {
404         int weak    = match->weak;
405         int strong  = match->strong;
406         if (weak == strong)
407             value[strong] += best;
408         else
409         {
410             value[weak] += bestWeak;
411             value[strong] += bestStrong;
412         }
413     }
414     return FcTrue;
415 }
416
417 /*
418  * Return a value indicating the distance between the two lists of
419  * values
420  */
421
422 static FcBool
423 FcCompare (FcPattern    *pat,
424            FcPattern    *fnt,
425            double       *value,
426            FcResult     *result)
427 {
428     int             i, i1, i2;
429     
430     for (i = 0; i < NUM_MATCH_VALUES; i++)
431         value[i] = 0.0;
432     
433     i1 = 0;
434     i2 = 0;
435     while (i1 < pat->num && i2 < fnt->num)
436     {
437         FcPatternElt *elt_i1 = FcPatternEltU(pat->elts)+i1;
438         FcPatternElt *elt_i2 = FcPatternEltU(fnt->elts)+i2;
439
440         i = FcObjectPtrCompare(elt_i1->object, elt_i2->object);
441         if (i > 0)
442             i2++;
443         else if (i < 0)
444             i1++;
445         else
446         {
447             if (!FcCompareValueList (elt_i1->object,
448                                      elt_i1->values, elt_i2->values,
449                                      0, value, result))
450                 return FcFalse;
451             i1++;
452             i2++;
453         }
454     }
455     return FcTrue;
456 }
457
458 FcPattern *
459 FcFontRenderPrepare (FcConfig       *config,
460                      FcPattern      *pat,
461                      FcPattern      *font)
462 {
463     FcPattern       *new;
464     int             i;
465     FcPatternElt    *fe, *pe;
466     FcValue         v;
467     FcResult        result;
468     
469     new = FcPatternCreate ();
470     if (!new)
471         return 0;
472     for (i = 0; i < font->num; i++)
473     {
474         fe = FcPatternEltU(font->elts)+i;
475         pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
476         if (pe)
477         {
478             if (!FcCompareValueList (pe->object, pe->values, 
479                                      fe->values, &v, 0, &result))
480             {
481                 FcPatternDestroy (new);
482                 return 0;
483             }
484         }
485         else
486             v = FcValueCanonicalize(&FcValueListPtrU(fe->values)->value);
487         FcPatternAdd (new, FcObjectPtrU(fe->object), v, FcFalse);
488     }
489     for (i = 0; i < pat->num; i++)
490     {
491         pe = FcPatternEltU(pat->elts)+i;
492         fe = FcPatternFindElt (font, FcObjectPtrU(pe->object));
493         if (!fe)
494             FcPatternAdd (new, FcObjectPtrU(pe->object), 
495                           FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
496     }
497
498     if (FcPatternFindElt (font, FC_FILE))
499         FcPatternTransferFullFname (new, font);
500
501     FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
502     return new;
503 }
504
505 FcPattern *
506 FcFontSetMatch (FcConfig    *config,
507                 FcFontSet   **sets,
508                 int         nsets,
509                 FcPattern   *p,
510                 FcResult    *result)
511 {
512     double          score;
513     double          bestscore;
514     int             f;
515     FcFontSet       *s;
516     FcPattern       *best;
517     int             scoring_index;
518     int             *sets_offset;
519     int             set;
520     int             nfonts;
521     int             fonts_left;
522     FcMatcher       *matcher;
523     FcMatcher       *strong_matchers[NUM_MATCH_VALUES];
524     FcMatcher       *weak_matchers[NUM_MATCH_VALUES];
525     FcPatternElt    *pat_elts[NUM_MATCH_VALUES];
526     int             pat_elt;
527     FcBool          *match_blocked;
528     int             block_start;
529
530     if (!nsets || !sets || !p)
531     {
532         *result = FcResultNoMatch;
533         return 0;
534     }
535
536     if (FcDebug () & FC_DBG_MATCH)
537     {
538         printf ("Match ");
539         FcPatternPrint (p);
540     }
541     if (!config)
542     {
543         config = FcConfigGetCurrent ();
544         if (!config)
545         {
546             *result = FcResultOutOfMemory;
547             return 0;
548         }
549     }
550
551     sets_offset = (int *)calloc(nsets, sizeof (int));
552
553     nfonts = 0;
554     for (set = 0; set < nsets; ++set)
555     {
556         sets_offset[set] = nfonts;
557         if (sets[set]) 
558             nfonts += sets[set]->nfont;
559     }
560
561     fonts_left = nfonts;
562
563     match_blocked = (FcBool*)calloc(nfonts, sizeof(FcBool));
564
565     /* Find out all necessary matchers first, so we don't need to find them
566      * in every loop.
567      */
568
569     memset(strong_matchers, 0, sizeof (FcMatcher*) * NUM_MATCH_VALUES);
570     memset(weak_matchers, 0, sizeof (FcMatcher*) * NUM_MATCH_VALUES);
571     memset(pat_elts, 0, sizeof (FcPatternElt*) * NUM_MATCH_VALUES);
572
573     for (pat_elt = 0; pat_elt < p->num; ++pat_elt)
574     {
575         matcher = FcObjectPtrToMatcher
576                         ((FcPatternEltU(p->elts)+pat_elt)->object);
577         if (matcher)
578         {
579             strong_matchers[matcher->strong] = matcher;
580             weak_matchers[matcher->weak] = matcher;
581             pat_elts [matcher->strong] = pat_elts [matcher->weak] =
582                     (FcPatternEltU(p->elts)+pat_elt);
583         }
584     }
585
586     /* The old algorithm checked if each font beat 'best', 
587      * scanning all of the value lists for all of the pattern elts. */
588     /* This algorithm checks each font on a element-by-element basis
589      * and blocks fonts that have already lost on some element from
590      * further consideration from being best.  Basically, we've
591      * swapped the order of loops and short-circuited fonts that
592      * are out of contention right away.
593      * This saves a lot of time! */
594     best = 0;
595     block_start = 0;
596     for (scoring_index = 0; scoring_index < NUM_MATCH_VALUES; ++scoring_index)
597     {
598         FcValueListPtr  v1;
599         FcValueList     *v1_ptrU;
600         int             v1_offset = 0;
601
602         if (!strong_matchers [scoring_index] && !weak_matchers [scoring_index])
603             continue;
604
605         for (v1 = pat_elts[scoring_index]->values, v1_ptrU = FcValueListPtrU(v1);
606              v1_ptrU;
607              v1 = v1_ptrU->next, v1_ptrU = FcValueListPtrU(v1), ++v1_offset)
608         {
609             matcher = (v1_ptrU->binding == FcValueBindingWeak) ?
610                 weak_matchers[scoring_index] : strong_matchers[scoring_index];
611
612             if (!matcher) continue;
613
614             bestscore = 1e99;
615
616             if (FcDebug () & FC_DBG_MATCHV)
617             {
618                 printf("Scoring Index %d, Value %d: %d(%d) fonts left\n",
619                         scoring_index, v1_offset, fonts_left, nfonts);
620             }
621
622             for (set = 0; set < nsets; ++set)
623             {
624                 s = sets[set];
625                 if (!s) continue;
626
627                 /* All fonts before block_start should have been knocked out. */
628                 for (f = (block_start > sets_offset[set]) ? (block_start - sets_offset[set]) : 0;
629                      f < s->nfont; ++f)
630                 {
631                     int             cand_elt;
632                     FcPatternElt    *cand_elts;
633
634                     if (match_blocked[f + sets_offset[set]])
635                         continue;
636
637                     score = 1e99;
638                     cand_elts = FcPatternEltU(s->fonts[f]->elts);
639
640                     /* Look for the appropriate element in this candidate
641                      * pattern 'f' and evaluate its score wrt 'p'. */
642                     for (cand_elt = 0; cand_elt < s->fonts[f]->num; ++cand_elt)
643                     {
644                         if (cand_elts[cand_elt].object == pat_elts[scoring_index]->object)
645                         {
646                             FcValueListPtr  v2;
647                             FcValueList     *v2_ptrU;
648
649                             for (v2 = cand_elts[cand_elt].values, v2_ptrU = FcValueListPtrU(v2);
650                                  v2_ptrU;
651                                  v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
652                             {
653                                 double v = (matcher->compare)(&v1_ptrU->value, &v2_ptrU->value);
654
655                                 if (v < 0)
656                                 {
657                                     *result = FcResultTypeMismatch;
658                                     free (match_blocked);
659                                     free (sets_offset);
660                                     return 0;
661                                 }
662
663                                 /* I'm actually kind of surprised that
664                                  * this isn't v + 100 * v1_offset. -PL */
665                                 v = v * 100 + v1_offset;
666                                 /* The old patch said score += v, which
667                                  * seems to be wrong when you have
668                                  * multiple matchers.  This takes the
669                                  * best score it can find for that font. */
670                                 if (v < score)
671                                     score = v;
672                             }
673                         }
674                     }
675
676                     /* We had no matching, just try the next one */
677                     if (score == 1e99)
678                         continue;
679
680                     /* If there's a previous champion, and current score
681                      * beats previous best score, on this element, then
682                      * knock out the previous champion and anything
683                      * else that we would have visited previous to f;
684                      * clearly anything previous to f would have been
685                      * less than f on this score. */
686                     if (!best || score < bestscore)
687                     {
688                         if (best) 
689                         {
690                             int b;
691                             for (b = block_start; b < f + sets_offset[set]; ++b)
692                                 if (!match_blocked[b])
693                                 {
694                                     match_blocked[b] = FcTrue;
695                                     --fonts_left;
696                                 }
697                         }
698
699                         bestscore = score;
700                         best = s->fonts[f];
701                         block_start = f + sets_offset[set];
702                     }
703
704                     /* If f loses, then it's out too. */
705                     if (best && score > bestscore)
706                     {
707                         match_blocked[f + sets_offset[set]] = FcTrue;
708                         --fonts_left;
709                     }
710
711                     /* If there is only 1 font left and the best is set,
712                      * then just return this font
713                      */
714                     if (fonts_left == 1 && best)
715                         goto end;
716
717                     /* Otherwise, f is equal to best on this element.
718                      * Carry on to next pattern element. */
719                 }
720             }
721             if ((FcDebug () & FC_DBG_MATCHV) && best)
722             {
723                 printf ("Best match (scoring index %d) candidate %d ", scoring_index, block_start);
724                 FcPatternPrint (best);
725             }
726         }
727     }
728
729 end:
730     free (match_blocked);
731     free (sets_offset);
732
733     if ((FcDebug () & FC_DBG_MATCH) && best)
734     {
735         printf ("Best match (scoring index %d) %d ", scoring_index, block_start);
736         FcPatternPrint (best);
737     }
738     if (!best)
739     {
740         *result = FcResultNoMatch;
741         return 0;
742     }
743     return FcFontRenderPrepare (config, p, best);
744 }
745
746 FcPattern *
747 FcFontMatch (FcConfig   *config,
748              FcPattern  *p, 
749              FcResult   *result)
750 {
751     FcFontSet   *sets[2];
752     int         nsets;
753
754     if (!config)
755     {
756         config = FcConfigGetCurrent ();
757         if (!config)
758             return 0;
759     }
760     nsets = 0;
761     if (config->fonts[FcSetSystem])
762         sets[nsets++] = config->fonts[FcSetSystem];
763     if (config->fonts[FcSetApplication])
764         sets[nsets++] = config->fonts[FcSetApplication];
765     return FcFontSetMatch (config, sets, nsets, p, result);
766 }
767
768 typedef struct _FcSortNode {
769     FcPattern   *pattern;
770     double      score[NUM_MATCH_VALUES];
771 } FcSortNode;
772
773 static int
774 FcSortCompare (const void *aa, const void *ab)
775 {
776     FcSortNode  *a = *(FcSortNode **) aa;
777     FcSortNode  *b = *(FcSortNode **) ab;
778     double      *as = &a->score[0];
779     double      *bs = &b->score[0];
780     double      ad = 0, bd = 0;
781     int         i;
782
783     i = NUM_MATCH_VALUES;
784     while (i-- && (ad = *as++) == (bd = *bs++))
785         ;
786     return ad < bd ? -1 : ad > bd ? 1 : 0;
787 }
788
789 static FcBool
790 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
791 {
792     FcCharSet   *ncs;
793     FcSortNode  *node;
794
795     while (nnode--)
796     {
797         node = *n++;
798         if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == 
799             FcResultMatch)
800         {
801             /*
802              * If this font isn't a subset of the previous fonts,
803              * add it to the list
804              */
805             if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
806             {
807                 if (*cs)
808                 {
809                     ncs = FcCharSetUnion (ncs, *cs);
810                     if (!ncs)
811                         return FcFalse;
812                     FcCharSetDestroy (*cs);
813                 }
814                 else
815                     ncs = FcCharSetCopy (ncs);
816                 *cs = ncs;
817                 FcPatternReference (node->pattern);
818                 if (FcDebug () & FC_DBG_MATCH)
819                 {
820                     printf ("Add ");
821                     FcPatternPrint (node->pattern);
822                 }
823                 if (!FcFontSetAdd (fs, node->pattern))
824                 {
825                     FcPatternDestroy (node->pattern);
826                     return FcFalse;
827                 }
828             }
829         }
830     }
831     return FcTrue;
832 }
833
834 void
835 FcFontSetSortDestroy (FcFontSet *fs)
836 {
837     FcFontSetDestroy (fs);
838 }
839
840 FcFontSet *
841 FcFontSetSort (FcConfig     *config,
842                FcFontSet    **sets,
843                int          nsets,
844                FcPattern    *p,
845                FcBool       trim,
846                FcCharSet    **csp,
847                FcResult     *result)
848 {
849     FcFontSet       *ret;
850     FcFontSet       *s;
851     FcSortNode      *nodes;
852     FcSortNode      **nodeps, **nodep;
853     int             nnodes;
854     FcSortNode      *new;
855     FcCharSet       *cs;
856     int             set;
857     int             f;
858     int             i;
859     int             nPatternLang;
860     FcBool          *patternLangSat;
861     FcValue         patternLang;
862
863     if (FcDebug () & FC_DBG_MATCH)
864     {
865         printf ("Sort ");
866         FcPatternPrint (p);
867     }
868     nnodes = 0;
869     for (set = 0; set < nsets; set++)
870     {
871         s = sets[set];
872         if (!s)
873             continue;
874         nnodes += s->nfont;
875     }
876     if (!nnodes)
877         goto bail0;
878     
879     for (nPatternLang = 0;
880          FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
881          nPatternLang++)
882         ;
883         
884     /* freed below */
885     nodes = malloc (nnodes * sizeof (FcSortNode) + 
886                     nnodes * sizeof (FcSortNode *) +
887                     nPatternLang * sizeof (FcBool));
888     if (!nodes)
889         goto bail0;
890     nodeps = (FcSortNode **) (nodes + nnodes);
891     patternLangSat = (FcBool *) (nodeps + nnodes);
892     
893     new = nodes;
894     nodep = nodeps;
895     for (set = 0; set < nsets; set++)
896     {
897         s = sets[set];
898         if (!s)
899             continue;
900         for (f = 0; f < s->nfont; f++)
901         {
902             if (FcDebug () & FC_DBG_MATCHV)
903             {
904                 printf ("Font %d ", f);
905                 FcPatternPrint (s->fonts[f]);
906             }
907             new->pattern = s->fonts[f];
908             if (!FcCompare (p, new->pattern, new->score, result))
909                 goto bail1;
910             if (FcDebug () & FC_DBG_MATCHV)
911             {
912                 printf ("Score");
913                 for (i = 0; i < NUM_MATCH_VALUES; i++)
914                 {
915                     printf (" %g", new->score[i]);
916                 }
917                 printf ("\n");
918             }
919             *nodep = new;
920             new++;
921             nodep++;
922         }
923     }
924
925     nnodes = new - nodes;
926     
927     qsort (nodeps, nnodes, sizeof (FcSortNode *),
928            FcSortCompare);
929     
930     for (i = 0; i < nPatternLang; i++)
931         patternLangSat[i] = FcFalse;
932     
933     for (f = 0; f < nnodes; f++)
934     {
935         FcBool  satisfies = FcFalse;
936         /*
937          * If this node matches any language, go check
938          * which ones and satisfy those entries
939          */
940         if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
941         {
942             for (i = 0; i < nPatternLang; i++)
943             {
944                 FcValue     nodeLang;
945                 
946                 if (!patternLangSat[i] &&
947                     FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
948                     FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
949                 {
950                     double  compare = FcCompareLang (&patternLang, &nodeLang);
951                     if (compare >= 0 && compare < 2)
952                     {
953                         if (FcDebug () & FC_DBG_MATCHV)
954                         {
955                             FcChar8 *family;
956                             FcChar8 *style;
957
958                             if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
959                                 FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
960                                 printf ("Font %s:%s matches language %d\n", family, style, i);
961                         }
962                         patternLangSat[i] = FcTrue;
963                         satisfies = FcTrue;
964                         break;
965                     }
966                 }
967             }
968         }
969         if (!satisfies)
970             nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
971     }
972
973     /*
974      * Re-sort once the language issues have been settled
975      */
976     qsort (nodeps, nnodes, sizeof (FcSortNode *),
977            FcSortCompare);
978
979     ret = FcFontSetCreate ();
980     if (!ret)
981         goto bail1;
982
983     cs = 0;
984
985     if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
986         goto bail2;
987
988     if (csp)
989         *csp = cs;
990     else
991         FcCharSetDestroy (cs);
992
993     free (nodes);
994
995     return ret;
996
997 bail2:
998     if (cs)
999         FcCharSetDestroy (cs);
1000     FcFontSetDestroy (ret);
1001 bail1:
1002     free (nodes);
1003 bail0:
1004     return 0;
1005 }
1006
1007 FcFontSet *
1008 FcFontSort (FcConfig    *config,
1009             FcPattern   *p, 
1010             FcBool      trim,
1011             FcCharSet   **csp,
1012             FcResult    *result)
1013 {
1014     FcFontSet   *sets[2];
1015     int         nsets;
1016
1017     if (!config)
1018     {
1019         config = FcConfigGetCurrent ();
1020         if (!config)
1021             return 0;
1022     }
1023     nsets = 0;
1024     if (config->fonts[FcSetSystem])
1025         sets[nsets++] = config->fonts[FcSetSystem];
1026     if (config->fonts[FcSetApplication])
1027         sets[nsets++] = config->fonts[FcSetApplication];
1028     return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
1029 }