2 * $XFree86: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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 (char *object, 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 (char *object, FcValue value1, FcValue value2)
64 if (value2.type != FcTypeString || value1.type != FcTypeString)
66 return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
70 FcCompareFamily (char *object, FcValue value1, FcValue value2)
72 if (value2.type != FcTypeString || value1.type != FcTypeString)
74 return (double) FcStrCmpIgnoreBlanksAndCase (value1.u.s, value2.u.s) != 0;
78 FcCompareLang (char *object, FcValue value1, FcValue value2)
82 switch (value1.type) {
84 switch (value2.type) {
86 result = FcLangSetCompare (value1.u.l, value2.u.l);
89 result = FcLangSetHasLang (value1.u.l, value2.u.s);
96 switch (value2.type) {
98 result = FcLangSetHasLang (value2.u.l, value1.u.s);
101 result = FcLangCompare (value1.u.s, value2.u.s);
113 case FcLangDifferentCountry:
115 case FcLangDifferentLang:
122 FcCompareBool (char *object, FcValue value1, FcValue value2)
124 if (value2.type != FcTypeBool || value1.type != FcTypeBool)
126 return (double) value2.u.b != value1.u.b;
130 FcCompareCharSet (char *object, FcValue value1, FcValue value2)
132 if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
134 return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
138 FcCompareSize (char *object, FcValue value1, FcValue value2)
142 switch (value1.type) {
152 switch (value2.type) {
170 typedef struct _FcMatcher {
172 double (*compare) (char *object, FcValue value1, FcValue value2);
177 * Order is significant, it defines the precedence of
178 * each value, earlier values are more significant than
181 static FcMatcher _FcMatchers [] = {
182 { FC_FOUNDRY, FcCompareString, 0, 0 },
183 #define MATCH_FOUNDRY 0
185 { FC_CHARSET, FcCompareCharSet, 1, 1 },
186 #define MATCH_CHARSET 1
188 { FC_FAMILY, FcCompareFamily, 2, 4 },
189 #define MATCH_FAMILY 2
191 { FC_LANG, FcCompareLang, 3, 3 },
194 { FC_SPACING, FcCompareNumber, 5, 5 },
195 #define MATCH_SPACING 4
197 { FC_PIXEL_SIZE, FcCompareSize, 6, 6 },
198 #define MATCH_PIXEL_SIZE 5
200 { FC_STYLE, FcCompareString, 7, 7 },
201 #define MATCH_STYLE 6
203 { FC_SLANT, FcCompareNumber, 8, 8 },
204 #define MATCH_SLANT 7
206 { FC_WEIGHT, FcCompareNumber, 9, 9 },
207 #define MATCH_WEIGHT 8
209 { FC_ANTIALIAS, FcCompareBool, 10, 10 },
210 #define MATCH_ANTIALIAS 9
212 { FC_RASTERIZER, FcCompareString, 11, 11 },
213 #define MATCH_RASTERIZER 10
215 { FC_OUTLINE, FcCompareBool, 12, 12 },
216 #define MATCH_OUTLINE 11
218 { FC_FONTVERSION, FcCompareNumber, 13, 13 },
219 #define MATCH_FONTVERSION 12
222 #define NUM_MATCH_VALUES 14
225 FcCompareValueList (const char *object,
226 FcValueList *v1orig, /* pattern */
227 FcValueList *v2orig, /* target */
232 FcValueList *v1, *v2;
233 double v, best, bestStrong, bestWeak;
238 * Locate the possible matching entry by examining the
239 * first few characters in object
242 switch (FcToLower (object[0])) {
244 switch (FcToLower (object[1])) {
246 switch (FcToLower (object[2])) {
248 i = MATCH_FOUNDRY; break;
250 i = MATCH_FONTVERSION; break;
254 i = MATCH_FAMILY; break;
258 i = MATCH_CHARSET; break;
260 i = MATCH_ANTIALIAS; break;
262 i = MATCH_LANG; break;
264 switch (FcToLower (object[1])) {
266 i = MATCH_SPACING; break;
268 i = MATCH_STYLE; break;
270 i = MATCH_SLANT; break;
274 i = MATCH_PIXEL_SIZE; break;
276 i = MATCH_WEIGHT; break;
278 i = MATCH_RASTERIZER; break;
280 i = MATCH_OUTLINE; break;
283 FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
284 (FcChar8 *) object) != 0)
287 *bestValue = v2orig->value;
291 for (i = 0; i < NUM_MATCHER; i++)
293 if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
297 if (i == NUM_MATCHER)
300 *bestValue = v2orig->value;
308 for (v1 = v1orig; v1; v1 = v1->next)
310 for (v2 = v2orig; v2; v2 = v2->next)
312 v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
317 *result = FcResultTypeMismatch;
320 if (FcDebug () & FC_DBG_MATCHV)
321 printf (" v %g j %d ", v, j);
326 *bestValue = v2->value;
329 if (v1->binding == FcValueBindingStrong)
342 if (FcDebug () & FC_DBG_MATCHV)
344 printf (" %s: %g ", object, best);
345 FcValueListPrint (v1orig);
347 FcValueListPrint (v2orig);
352 int weak = _FcMatchers[i].weak;
353 int strong = _FcMatchers[i].strong;
355 value[strong] += best;
358 value[weak] += bestWeak;
359 value[strong] += bestStrong;
366 * Return a value indicating the distance between the two lists of
371 FcCompare (FcPattern *pat,
378 for (i = 0; i < NUM_MATCH_VALUES; i++)
383 while (i1 < pat->num && i2 < fnt->num)
385 i = strcmp (pat->elts[i1].object, fnt->elts[i2].object);
392 if (!FcCompareValueList (pat->elts[i1].object,
393 pat->elts[i1].values,
394 fnt->elts[i2].values,
405 for (i1 = 0; i1 < pat->num; i1++)
407 for (i2 = 0; i2 < fnt->num; i2++)
409 if (!strcmp (pat->elts[i1].object, fnt->elts[i2].object))
420 FcFontRenderPrepare (FcConfig *config,
426 FcPatternElt *fe, *pe;
430 new = FcPatternCreate ();
433 for (i = 0; i < font->num; i++)
436 pe = FcPatternFindElt (pat, fe->object);
439 if (!FcCompareValueList (pe->object, pe->values,
440 fe->values, &v, 0, &result))
442 FcPatternDestroy (new);
447 v = fe->values->value;
448 FcPatternAdd (new, fe->object, v, FcFalse);
450 for (i = 0; i < pat->num; i++)
453 fe = FcPatternFindElt (font, pe->object);
455 FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
457 FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
462 FcFontSetMatch (FcConfig *config,
468 double score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
475 for (i = 0; i < NUM_MATCH_VALUES; i++)
478 if (FcDebug () & FC_DBG_MATCH)
485 config = FcConfigGetCurrent ();
489 for (set = 0; set < nsets; set++)
494 for (f = 0; f < s->nfont; f++)
496 if (FcDebug () & FC_DBG_MATCHV)
498 printf ("Font %d ", f);
499 FcPatternPrint (s->fonts[f]);
501 if (!FcCompare (p, s->fonts[f], score, result))
503 if (FcDebug () & FC_DBG_MATCHV)
506 for (i = 0; i < NUM_MATCH_VALUES; i++)
508 printf (" %g", score[i]);
512 for (i = 0; i < NUM_MATCH_VALUES; i++)
514 if (best && bestscore[i] < score[i])
516 if (!best || score[i] < bestscore[i])
518 for (i = 0; i < NUM_MATCH_VALUES; i++)
519 bestscore[i] = score[i];
526 if (FcDebug () & FC_DBG_MATCH)
528 printf ("Best score");
529 for (i = 0; i < NUM_MATCH_VALUES; i++)
530 printf (" %g", bestscore[i]);
531 FcPatternPrint (best);
535 *result = FcResultNoMatch;
538 return FcFontRenderPrepare (config, p, best);
542 FcFontMatch (FcConfig *config,
551 config = FcConfigGetCurrent ();
556 if (config->fonts[FcSetSystem])
557 sets[nsets++] = config->fonts[FcSetSystem];
558 if (config->fonts[FcSetApplication])
559 sets[nsets++] = config->fonts[FcSetApplication];
560 return FcFontSetMatch (config, sets, nsets, p, result);
563 typedef struct _FcSortNode {
565 double score[NUM_MATCH_VALUES];
569 FcSortCompare (const void *aa, const void *ab)
571 FcSortNode *a = *(FcSortNode **) aa;
572 FcSortNode *b = *(FcSortNode **) ab;
573 double *as = &a->score[0];
574 double *bs = &b->score[0];
575 double ad = 0, bd = 0;
578 i = NUM_MATCH_VALUES;
579 while (i-- && (ad = *as++) == (bd = *bs++))
581 return ad < bd ? -1 : ad > bd ? 1 : 0;
585 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
593 if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) ==
597 * If this font isn't a subset of the previous fonts,
600 if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
604 ncs = FcCharSetUnion (ncs, *cs);
607 FcCharSetDestroy (*cs);
610 ncs = FcCharSetCopy (ncs);
612 FcPatternReference (node->pattern);
613 if (FcDebug () & FC_DBG_MATCH)
616 FcPatternPrint (node->pattern);
618 if (!FcFontSetAdd (fs, node->pattern))
620 FcPatternDestroy (node->pattern);
630 FcFontSetSortDestroy (FcFontSet *fs)
632 FcFontSetDestroy (fs);
636 FcFontSetSort (FcConfig *config,
647 FcSortNode **nodeps, **nodep;
655 if (FcDebug () & FC_DBG_MATCH)
661 for (set = 0; set < nsets; set++)
671 nodes = malloc (nnodes * sizeof (FcSortNode) + nnodes * sizeof (FcSortNode *));
674 nodeps = (FcSortNode **) (nodes + nnodes);
678 for (set = 0; set < nsets; set++)
683 for (f = 0; f < s->nfont; f++)
685 if (FcDebug () & FC_DBG_MATCHV)
687 printf ("Font %d ", f);
688 FcPatternPrint (s->fonts[f]);
690 new->pattern = s->fonts[f];
691 if (!FcCompare (p, new->pattern, new->score, result))
693 if (FcDebug () & FC_DBG_MATCHV)
696 for (i = 0; i < NUM_MATCH_VALUES; i++)
698 printf (" %g", new->score[i]);
708 nnodes = new - nodes;
710 qsort (nodeps, nnodes, sizeof (FcSortNode *),
713 ret = FcFontSetCreate ();
719 if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
725 FcCharSetDestroy (cs);
733 FcCharSetDestroy (cs);
734 FcFontSetDestroy (ret);
742 FcFontSort (FcConfig *config,
753 config = FcConfigGetCurrent ();
758 if (config->fonts[FcSetSystem])
759 sets[nsets++] = config->fonts[FcSetSystem];
760 if (config->fonts[FcSetApplication])
761 sets[nsets++] = config->fonts[FcSetApplication];
762 return FcFontSetSort (config, sets, nsets, p, trim, csp, result);