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