2 * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
4 * Copyright © 2000 Keith Packard
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.
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.
31 FcCompareNumber (FcValue
*value1
, FcValue
*value2
)
35 switch (value1
->type
) {
37 v1
= (double) value1
->u
.i
;
45 switch (value2
->type
) {
47 v2
= (double) value2
->u
.i
;
62 FcCompareString (FcValue
*v1
, FcValue
*v2
)
64 return (double) FcStrCmpIgnoreCase (fc_value_string(v1
), fc_value_string(v2
)) != 0;
68 FcCompareFamily (FcValue
*v1
, FcValue
*v2
)
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
);
75 if (FcToLower(*v1_string
) != FcToLower(*v2_string
))
78 return (double) FcStrCmpIgnoreBlanksAndCase (v1_string
, v2_string
) != 0;
82 FcCompareLang (FcValue
*v1
, FcValue
*v2
)
85 FcValue value1
= FcValueCanonicalize(v1
), value2
= FcValueCanonicalize(v2
);
87 switch (value1
.type
) {
89 switch (value2
.type
) {
91 result
= FcLangSetCompare (value1
.u
.l
, value2
.u
.l
);
94 result
= FcLangSetHasLang (value1
.u
.l
,
102 switch (value2
.type
) {
104 result
= FcLangSetHasLang (value2
.u
.l
, value1
.u
.s
);
107 result
= FcLangCompare (value1
.u
.s
,
120 case FcLangDifferentCountry
:
122 case FcLangDifferentLang
:
129 FcCompareBool (FcValue
*v1
, FcValue
*v2
)
131 if (fc_storage_type(v2
) != FcTypeBool
|| fc_storage_type(v1
) != FcTypeBool
)
133 return (double) v2
->u
.b
!= v1
->u
.b
;
137 FcCompareCharSet (FcValue
*v1
, FcValue
*v2
)
139 return (double) FcCharSetSubtractCount (fc_value_charset(v1
), fc_value_charset(v2
));
143 FcCompareSize (FcValue
*value1
, FcValue
*value2
)
147 switch (value1
->type
) {
157 switch (value2
->type
) {
175 typedef struct _FcMatcher
{
177 FcObjectPtr objectPtr
;
178 double (*compare
) (FcValue
*value1
, FcValue
*value2
);
183 * Order is significant, it defines the precedence of
184 * each value, earlier values are more significant than
187 static FcMatcher _FcMatchers
[] = {
188 { FC_FOUNDRY
, 0, FcCompareString
, 0, 0 },
189 #define MATCH_FOUNDRY 0
190 #define MATCH_FOUNDRY_INDEX 0
192 { FC_CHARSET
, 0, FcCompareCharSet
, 1, 1 },
193 #define MATCH_CHARSET 1
194 #define MATCH_CHARSET_INDEX 1
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
201 { FC_LANG
, 0, FcCompareLang
, 3, 3 },
203 #define MATCH_LANG_INDEX 3
205 { FC_SPACING
, 0, FcCompareNumber
, 5, 5 },
206 #define MATCH_SPACING 4
207 #define MATCH_SPACING_INDEX 5
209 { FC_PIXEL_SIZE
, 0, FcCompareSize
, 6, 6 },
210 #define MATCH_PIXEL_SIZE 5
211 #define MATCH_PIXEL_SIZE_INDEX 6
213 { FC_STYLE
, 0, FcCompareString
, 7, 7 },
214 #define MATCH_STYLE 6
215 #define MATCH_STYLE_INDEX 7
217 { FC_SLANT
, 0, FcCompareNumber
, 8, 8 },
218 #define MATCH_SLANT 7
219 #define MATCH_SLANT_INDEX 8
221 { FC_WEIGHT
, 0, FcCompareNumber
, 9, 9 },
222 #define MATCH_WEIGHT 8
223 #define MATCH_WEIGHT_INDEX 9
225 { FC_WIDTH
, 0, FcCompareNumber
, 10, 10 },
226 #define MATCH_WIDTH 9
227 #define MATCH_WIDTH_INDEX 10
229 { FC_ANTIALIAS
, 0, FcCompareBool
, 11, 11 },
230 #define MATCH_ANTIALIAS 10
231 #define MATCH_ANTIALIAS_INDEX 11
233 { FC_RASTERIZER
, 0, FcCompareString
, 12, 12 },
234 #define MATCH_RASTERIZER 11
235 #define MATCH_RASTERIZER_INDEX 12
237 { FC_OUTLINE
, 0, FcCompareBool
, 13, 13 },
238 #define MATCH_OUTLINE 12
239 #define MATCH_OUTLINE_INDEX 13
241 { FC_FONTVERSION
, 0, FcCompareNumber
, 14, 14 },
242 #define MATCH_FONTVERSION 13
243 #define MATCH_FONTVERSION_INDEX 14
246 #define NUM_MATCH_VALUES 15
248 static FcBool matchObjectPtrsInit
= FcFalse
;
251 FcMatchObjectPtrsInit (void)
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
;
271 FcObjectPtrToMatcher (FcObjectPtr o
)
274 const char *object
= FcObjectPtrU(o
);
283 i
= MATCH_FOUNDRY
; break;
285 i
= MATCH_FONTVERSION
; break;
289 i
= MATCH_FAMILY
; break;
293 i
= MATCH_CHARSET
; break;
295 i
= MATCH_ANTIALIAS
; break;
297 i
= MATCH_LANG
; break;
301 i
= MATCH_SPACING
; break;
303 i
= MATCH_STYLE
; break;
305 i
= MATCH_SLANT
; break;
309 i
= MATCH_PIXEL_SIZE
; break;
313 i
= MATCH_WIDTH
; break;
315 i
= MATCH_WEIGHT
; break;
319 i
= MATCH_RASTERIZER
; break;
321 i
= MATCH_OUTLINE
; break;
327 if (!matchObjectPtrsInit
)
328 FcMatchObjectPtrsInit();
330 if (o
!= _FcMatchers
[i
].objectPtr
)
333 return _FcMatchers
+i
;
337 FcCompareValueList (FcObjectPtr o
,
338 FcValueListPtr v1orig
, /* pattern */
339 FcValueListPtr v2orig
, /* target */
344 FcValueListPtr v1
, v2
;
345 FcValueList
*v1_ptrU
, *v2_ptrU
;
346 double v
, best
, bestStrong
, bestWeak
;
348 const char *object
= FcObjectPtrU(o
);
349 FcMatcher
*match
= FcObjectPtrToMatcher(o
);
354 *bestValue
= FcValueCanonicalize(&FcValueListPtrU(v2orig
)->value
);
362 for (v1
= v1orig
, v1_ptrU
= FcValueListPtrU(v1
); v1_ptrU
;
363 v1
= v1_ptrU
->next
, v1_ptrU
= FcValueListPtrU(v1
))
365 for (v2
= v2orig
, v2_ptrU
= FcValueListPtrU(v2
); v2_ptrU
;
366 v2
= v2_ptrU
->next
, v2_ptrU
= FcValueListPtrU(v2
))
368 v
= (match
->compare
) (&v1_ptrU
->value
, &v2_ptrU
->value
);
371 *result
= FcResultTypeMismatch
;
378 *bestValue
= FcValueCanonicalize(&v2_ptrU
->value
);
381 if (v1_ptrU
->binding
== FcValueBindingStrong
)
394 if (FcDebug () & FC_DBG_MATCHV
)
396 printf (" %s: %g ", object
, best
);
397 FcValueListPrint (v1orig
);
399 FcValueListPrint (v2orig
);
404 int weak
= match
->weak
;
405 int strong
= match
->strong
;
407 value
[strong
] += best
;
410 value
[weak
] += bestWeak
;
411 value
[strong
] += bestStrong
;
418 * Return a value indicating the distance between the two lists of
423 FcCompare (FcPattern
*pat
,
430 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
435 while (i1
< pat
->num
&& i2
< fnt
->num
)
437 FcPatternElt
*elt_i1
= FcPatternEltU(pat
->elts
)+i1
;
438 FcPatternElt
*elt_i2
= FcPatternEltU(fnt
->elts
)+i2
;
440 i
= FcObjectPtrCompare(elt_i1
->object
, elt_i2
->object
);
447 if (!FcCompareValueList (elt_i1
->object
,
448 elt_i1
->values
, elt_i2
->values
,
459 FcFontRenderPrepare (FcConfig
*config
,
465 FcPatternElt
*fe
, *pe
;
469 new = FcPatternCreate ();
472 for (i
= 0; i
< font
->num
; i
++)
474 fe
= FcPatternEltU(font
->elts
)+i
;
475 pe
= FcPatternFindElt (pat
, FcObjectPtrU(fe
->object
));
478 if (!FcCompareValueList (pe
->object
, pe
->values
,
479 fe
->values
, &v
, 0, &result
))
481 FcPatternDestroy (new);
486 v
= FcValueCanonicalize(&FcValueListPtrU(fe
->values
)->value
);
487 FcPatternAdd (new, FcObjectPtrU(fe
->object
), v
, FcFalse
);
489 for (i
= 0; i
< pat
->num
; i
++)
491 pe
= FcPatternEltU(pat
->elts
)+i
;
492 fe
= FcPatternFindElt (font
, FcObjectPtrU(pe
->object
));
494 FcPatternAdd (new, FcObjectPtrU(pe
->object
),
495 FcValueCanonicalize(&FcValueListPtrU(pe
->values
)->value
), FcTrue
);
498 FcConfigSubstituteWithPat (config
, new, pat
, FcMatchFont
);
503 FcFontSetMatch (FcConfig
*config
,
520 FcMatcher
*strong_matchers
[NUM_MATCH_VALUES
];
521 FcMatcher
*weak_matchers
[NUM_MATCH_VALUES
];
522 FcPatternElt
*pat_elts
[NUM_MATCH_VALUES
];
527 if (!nsets
|| !sets
|| !p
)
529 *result
= FcResultNoMatch
;
533 if (FcDebug () & FC_DBG_MATCH
)
540 config
= FcConfigGetCurrent ();
543 *result
= FcResultOutOfMemory
;
548 sets_offset
= (int *)calloc(nsets
, sizeof (int));
551 for (set
= 0; set
< nsets
; ++set
)
553 sets_offset
[set
] = nfonts
;
555 nfonts
+= sets
[set
]->nfont
;
560 match_blocked
= (int*)calloc(nfonts
, sizeof(int));
562 /* Find out all necessary matchers first, so we don't need to find them
566 memset(strong_matchers
, 0, sizeof (FcMatcher
*) * NUM_MATCH_VALUES
);
567 memset(weak_matchers
, 0, sizeof (FcMatcher
*) * NUM_MATCH_VALUES
);
568 memset(pat_elts
, 0, sizeof (FcPatternElt
*) * NUM_MATCH_VALUES
);
570 for (pat_elt
= 0; pat_elt
< p
->num
; ++pat_elt
)
572 matcher
= FcObjectPtrToMatcher
573 ((FcPatternEltU(p
->elts
)+pat_elt
)->object
);
576 strong_matchers
[matcher
->strong
] = matcher
;
577 weak_matchers
[matcher
->weak
] = matcher
;
578 pat_elts
[matcher
->strong
] = pat_elts
[matcher
->weak
] =
579 (FcPatternEltU(p
->elts
)+pat_elt
);
583 /* The old algorithm checked if each font beat 'best',
584 * scanning all of the value lists for all of the pattern elts. */
585 /* This algorithm checks each font on a element-by-element basis
586 * and blocks fonts that have already lost on some element from
587 * further consideration from being best. Basically, we've
588 * swapped the order of loops and short-circuited fonts that
589 * are out of contention right away.
590 * This saves a lot of time! */
593 for (scoring_index
= 0; scoring_index
< NUM_MATCH_VALUES
; ++scoring_index
)
596 FcValueList
*v1_ptrU
;
599 if (!strong_matchers
[scoring_index
] && !weak_matchers
[scoring_index
])
602 for (v1
= pat_elts
[scoring_index
]->values
, v1_ptrU
= FcValueListPtrU(v1
);
604 v1
= v1_ptrU
->next
, v1_ptrU
= FcValueListPtrU(v1
), ++v1_offset
)
606 matcher
= (v1_ptrU
->binding
== FcValueBindingWeak
) ?
607 weak_matchers
[scoring_index
] : strong_matchers
[scoring_index
];
609 if (!matcher
) continue;
613 if (FcDebug () & FC_DBG_MATCHV
)
615 printf("Scoring Index %d, Value %d: %d(%d) fonts left\n",
616 scoring_index
, v1_offset
, fonts_left
, nfonts
);
619 for (set
= 0; set
< nsets
; ++set
)
624 /* All fonts before block_start should have been knocked out. */
625 for (f
= (block_start
> sets_offset
[set
]) ? (block_start
- sets_offset
[set
]) : 0;
629 FcPatternElt
*cand_elts
;
631 if (match_blocked
[f
+ sets_offset
[set
]] == 1)
635 cand_elts
= FcPatternEltU(s
->fonts
[f
]->elts
);
637 /* Look for the appropriate element in this candidate
638 * pattern 'f' and evaluate its score wrt 'p'. */
639 for (cand_elt
= 0; cand_elt
< s
->fonts
[f
]->num
; ++cand_elt
)
641 if (cand_elts
[cand_elt
].object
== pat_elts
[scoring_index
]->object
)
644 FcValueList
*v2_ptrU
;
646 for (v2
= cand_elts
[cand_elt
].values
, v2_ptrU
= FcValueListPtrU(v2
);
648 v2
= v2_ptrU
->next
, v2_ptrU
= FcValueListPtrU(v2
))
650 double v
= (matcher
->compare
)(&v1_ptrU
->value
, &v2_ptrU
->value
);
654 *result
= FcResultTypeMismatch
;
655 free (match_blocked
);
660 /* I'm actually kind of surprised that
661 * this isn't v + 100 * v1_offset. -PL */
662 v
= v
* 100 + v1_offset
;
663 /* The old patch said score += v, which
664 * seems to be wrong when you have
665 * multiple matchers. This takes the
666 * best score it can find for that font. */
673 /* We had no matching, just try the next one */
676 match_blocked
[f
+ sets_offset
[set
]] = 2;
679 match_blocked
[f
+ sets_offset
[set
]] = 0;
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
)
691 for (b
= block_start
; b
< f
+ sets_offset
[set
]; ++b
)
692 if (!match_blocked
[b
])
694 match_blocked
[b
] = 1;
701 /* This kills too many fonts, unfortunately. */
702 /* block_start = f + sets_offset[set]; */
705 /* If f loses, then it's out too. */
706 if (best
&& score
> bestscore
)
708 match_blocked
[f
+ sets_offset
[set
]] = 1;
712 /* If there is only 1 font left and the best is set,
713 * then just return this font
715 if (fonts_left
== 1 && best
)
718 /* Otherwise, f is equal to best on this element.
719 * Carry on to next pattern element. */
722 if ((FcDebug () & FC_DBG_MATCHV
) && best
)
724 printf ("Best match (scoring index %d) candidate %d ", scoring_index
, block_start
);
725 FcPatternPrint (best
);
731 free (match_blocked
);
734 if ((FcDebug () & FC_DBG_MATCH
) && best
)
736 printf ("Best match (scoring index %d) %d ", scoring_index
, block_start
);
737 FcPatternPrint (best
);
741 *result
= FcResultNoMatch
;
744 return FcFontRenderPrepare (config
, p
, best
);
748 FcFontMatch (FcConfig
*config
,
757 config
= FcConfigGetCurrent ();
762 if (config
->fonts
[FcSetSystem
])
763 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
764 if (config
->fonts
[FcSetApplication
])
765 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
766 return FcFontSetMatch (config
, sets
, nsets
, p
, result
);
769 typedef struct _FcSortNode
{
771 double score
[NUM_MATCH_VALUES
];
775 FcSortCompare (const void *aa
, const void *ab
)
777 FcSortNode
*a
= *(FcSortNode
**) aa
;
778 FcSortNode
*b
= *(FcSortNode
**) ab
;
779 double *as
= &a
->score
[0];
780 double *bs
= &b
->score
[0];
781 double ad
= 0, bd
= 0;
784 i
= NUM_MATCH_VALUES
;
785 while (i
-- && (ad
= *as
++) == (bd
= *bs
++))
787 return ad
< bd
? -1 : ad
> bd
? 1 : 0;
791 FcSortWalk (FcSortNode
**n
, int nnode
, FcFontSet
*fs
, FcCharSet
**cs
, FcBool trim
, FcBool build_cs
)
799 if (FcPatternGetCharSet (node
->pattern
, FC_CHARSET
, 0, &ncs
) ==
803 * If this font isn't a subset of the previous fonts,
806 if (!trim
|| !*cs
|| !FcCharSetIsSubset (ncs
, *cs
))
808 if (trim
|| build_cs
)
812 ncs
= FcCharSetUnion (ncs
, *cs
);
815 FcCharSetDestroy (*cs
);
818 ncs
= FcCharSetCopy (ncs
);
822 FcPatternReference (node
->pattern
);
823 if (FcDebug () & FC_DBG_MATCH
)
826 FcPatternPrint (node
->pattern
);
828 if (!FcFontSetAdd (fs
, node
->pattern
))
830 FcPatternDestroy (node
->pattern
);
840 FcFontSetSortDestroy (FcFontSet
*fs
)
842 FcFontSetDestroy (fs
);
846 FcFontSetSort (FcConfig
*config
,
857 FcSortNode
**nodeps
, **nodep
;
865 FcBool
*patternLangSat
;
868 if (FcDebug () & FC_DBG_MATCH
)
874 for (set
= 0; set
< nsets
; set
++)
884 for (nPatternLang
= 0;
885 FcPatternGet (p
, FC_LANG
, nPatternLang
, &patternLang
) == FcResultMatch
;
890 nodes
= malloc (nnodes
* sizeof (FcSortNode
) +
891 nnodes
* sizeof (FcSortNode
*) +
892 nPatternLang
* sizeof (FcBool
));
895 nodeps
= (FcSortNode
**) (nodes
+ nnodes
);
896 patternLangSat
= (FcBool
*) (nodeps
+ nnodes
);
900 for (set
= 0; set
< nsets
; set
++)
905 for (f
= 0; f
< s
->nfont
; f
++)
907 if (FcDebug () & FC_DBG_MATCHV
)
909 printf ("Font %d ", f
);
910 FcPatternPrint (s
->fonts
[f
]);
912 new->pattern
= s
->fonts
[f
];
913 if (!FcCompare (p
, new->pattern
, new->score
, result
))
915 if (FcDebug () & FC_DBG_MATCHV
)
918 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
920 printf (" %g", new->score
[i
]);
930 nnodes
= new - nodes
;
932 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
935 for (i
= 0; i
< nPatternLang
; i
++)
936 patternLangSat
[i
] = FcFalse
;
938 for (f
= 0; f
< nnodes
; f
++)
940 FcBool satisfies
= FcFalse
;
942 * If this node matches any language, go check
943 * which ones and satisfy those entries
945 if (nodeps
[f
]->score
[MATCH_LANG_INDEX
] < nPatternLang
)
947 for (i
= 0; i
< nPatternLang
; i
++)
951 if (!patternLangSat
[i
] &&
952 FcPatternGet (p
, FC_LANG
, i
, &patternLang
) == FcResultMatch
&&
953 FcPatternGet (nodeps
[f
]->pattern
, FC_LANG
, 0, &nodeLang
) == FcResultMatch
)
955 double compare
= FcCompareLang (&patternLang
, &nodeLang
);
956 if (compare
>= 0 && compare
< 2)
958 if (FcDebug () & FC_DBG_MATCHV
)
963 if (FcPatternGetString (nodeps
[f
]->pattern
, FC_FAMILY
, 0, &family
) == FcResultMatch
&&
964 FcPatternGetString (nodeps
[f
]->pattern
, FC_STYLE
, 0, &style
) == FcResultMatch
)
965 printf ("Font %s:%s matches language %d\n", family
, style
, i
);
967 patternLangSat
[i
] = FcTrue
;
975 nodeps
[f
]->score
[MATCH_LANG_INDEX
] = 1000.0;
979 * Re-sort once the language issues have been settled
981 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
984 ret
= FcFontSetCreate ();
990 if (!FcSortWalk (nodeps
, nnodes
, ret
, &cs
, trim
, (csp
!=0)))
998 FcCharSetDestroy (cs
);
1007 FcCharSetDestroy (cs
);
1008 FcFontSetDestroy (ret
);
1016 FcFontSort (FcConfig
*config
,
1027 config
= FcConfigGetCurrent ();
1032 if (config
->fonts
[FcSetSystem
])
1033 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
1034 if (config
->fonts
[FcSetApplication
])
1035 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
1036 return FcFontSetSort (config
, sets
, nsets
, p
, trim
, csp
, result
);