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 FcCompareInteger (char *object, FcValue value1, FcValue value2)
35 if (value2.type != FcTypeInteger || value1.type != FcTypeInteger)
37 v = value2.u.i - value1.u.i;
44 FcCompareString (char *object, FcValue value1, FcValue value2)
46 if (value2.type != FcTypeString || value1.type != FcTypeString)
48 return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
52 FcCompareFamily (char *object, FcValue value1, FcValue value2)
54 if (value2.type != FcTypeString || value1.type != FcTypeString)
56 return (double) FcStrCmpIgnoreBlanksAndCase (value1.u.s, value2.u.s) != 0;
60 FcCompareLang (char *object, FcValue value1, FcValue value2)
64 switch (value1.type) {
66 switch (value2.type) {
68 result = FcLangSetCompare (value1.u.l, value2.u.l);
71 result = FcLangSetHasLang (value1.u.l, value2.u.s);
78 switch (value2.type) {
80 result = FcLangSetHasLang (value2.u.l, value1.u.s);
83 result = FcLangCompare (value1.u.s, value2.u.s);
95 case FcLangDifferentCountry:
97 case FcLangDifferentLang:
104 FcCompareBool (char *object, FcValue value1, FcValue value2)
106 if (value2.type != FcTypeBool || value1.type != FcTypeBool)
108 return (double) value2.u.b != value1.u.b;
112 FcCompareCharSet (char *object, FcValue value1, FcValue value2)
114 if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
116 return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
120 FcCompareSize (char *object, FcValue value1, FcValue value2)
124 switch (value1.type) {
134 switch (value2.type) {
152 typedef struct _FcMatcher {
154 double (*compare) (char *object, FcValue value1, FcValue value2);
159 * Order is significant, it defines the precedence of
160 * each value, earlier values are more significant than
163 static FcMatcher _FcMatchers [] = {
164 { FC_FOUNDRY, FcCompareString, 0, 0 },
165 #define MATCH_FOUNDRY 0
167 { FC_CHARSET, FcCompareCharSet, 1, 1 },
168 #define MATCH_CHARSET 1
170 { FC_FAMILY, FcCompareFamily, 2, 4 },
171 #define MATCH_FAMILY 2
173 { FC_LANG, FcCompareLang, 3, 3 },
176 { FC_SPACING, FcCompareInteger, 5, 5 },
177 #define MATCH_SPACING 4
179 { FC_PIXEL_SIZE, FcCompareSize, 6, 6 },
180 #define MATCH_PIXEL_SIZE 5
182 { FC_STYLE, FcCompareString, 7, 7 },
183 #define MATCH_STYLE 6
185 { FC_SLANT, FcCompareInteger, 8, 8 },
186 #define MATCH_SLANT 7
188 { FC_WEIGHT, FcCompareInteger, 9, 9 },
189 #define MATCH_WEIGHT 8
191 { FC_ANTIALIAS, FcCompareBool, 10, 10 },
192 #define MATCH_ANTIALIAS 9
194 { FC_RASTERIZER, FcCompareString, 11, 11 },
195 #define MATCH_RASTERIZER 10
197 { FC_OUTLINE, FcCompareBool, 12, 12 },
198 #define MATCH_OUTLINE 11
200 { FC_FONTVERSION, FcCompareInteger, 13, 13 },
201 #define MATCH_FONTVERSION 12
204 #define NUM_MATCH_VALUES 14
207 FcCompareValueList (const char *object,
208 FcValueList *v1orig, /* pattern */
209 FcValueList *v2orig, /* target */
214 FcValueList *v1, *v2;
215 double v, best, bestStrong, bestWeak;
220 * Locate the possible matching entry by examining the
221 * first few characters in object
224 switch (FcToLower (object[0])) {
226 switch (FcToLower (object[1])) {
228 switch (FcToLower (object[2])) {
230 i = MATCH_FOUNDRY; break;
232 i = MATCH_FONTVERSION; break;
236 i = MATCH_FAMILY; break;
240 i = MATCH_CHARSET; break;
242 i = MATCH_ANTIALIAS; break;
244 i = MATCH_LANG; break;
246 switch (FcToLower (object[1])) {
248 i = MATCH_SPACING; break;
250 i = MATCH_STYLE; break;
252 i = MATCH_SLANT; break;
256 i = MATCH_PIXEL_SIZE; break;
258 i = MATCH_WEIGHT; break;
260 i = MATCH_RASTERIZER; break;
262 i = MATCH_OUTLINE; break;
265 FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
266 (FcChar8 *) object) != 0)
269 *bestValue = v2orig->value;
273 for (i = 0; i < NUM_MATCHER; i++)
275 if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
279 if (i == NUM_MATCHER)
282 *bestValue = v2orig->value;
290 for (v1 = v1orig; v1; v1 = v1->next)
292 for (v2 = v2orig; v2; v2 = v2->next)
294 v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
299 *result = FcResultTypeMismatch;
302 if (FcDebug () & FC_DBG_MATCHV)
303 printf (" v %g j %d ", v, j);
308 *bestValue = v2->value;
311 if (v1->binding == FcValueBindingStrong)
324 if (FcDebug () & FC_DBG_MATCHV)
326 printf (" %s: %g ", object, best);
327 FcValueListPrint (v1orig);
329 FcValueListPrint (v2orig);
334 int weak = _FcMatchers[i].weak;
335 int strong = _FcMatchers[i].strong;
337 value[strong] += best;
340 value[weak] += bestWeak;
341 value[strong] += bestStrong;
348 * Return a value indicating the distance between the two lists of
353 FcCompare (FcPattern *pat,
360 for (i = 0; i < NUM_MATCH_VALUES; i++)
365 while (i1 < pat->num && i2 < fnt->num)
367 i = strcmp (pat->elts[i1].object, fnt->elts[i2].object);
374 if (!FcCompareValueList (pat->elts[i1].object,
375 pat->elts[i1].values,
376 fnt->elts[i2].values,
387 for (i1 = 0; i1 < pat->num; i1++)
389 for (i2 = 0; i2 < fnt->num; i2++)
391 if (!strcmp (pat->elts[i1].object, fnt->elts[i2].object))
402 FcFontRenderPrepare (FcConfig *config,
408 FcPatternElt *fe, *pe;
412 new = FcPatternCreate ();
415 for (i = 0; i < font->num; i++)
418 pe = FcPatternFindElt (pat, fe->object);
421 if (!FcCompareValueList (pe->object, pe->values,
422 fe->values, &v, 0, &result))
424 FcPatternDestroy (new);
429 v = fe->values->value;
430 FcPatternAdd (new, fe->object, v, FcFalse);
432 for (i = 0; i < pat->num; i++)
435 fe = FcPatternFindElt (font, pe->object);
437 FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
439 FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
444 FcFontSetMatch (FcConfig *config,
450 double score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
457 for (i = 0; i < NUM_MATCH_VALUES; i++)
460 if (FcDebug () & FC_DBG_MATCH)
467 config = FcConfigGetCurrent ();
471 for (set = 0; set < nsets; set++)
476 for (f = 0; f < s->nfont; f++)
478 if (FcDebug () & FC_DBG_MATCHV)
480 printf ("Font %d ", f);
481 FcPatternPrint (s->fonts[f]);
483 if (!FcCompare (p, s->fonts[f], score, result))
485 if (FcDebug () & FC_DBG_MATCHV)
488 for (i = 0; i < NUM_MATCH_VALUES; i++)
490 printf (" %g", score[i]);
494 for (i = 0; i < NUM_MATCH_VALUES; i++)
496 if (best && bestscore[i] < score[i])
498 if (!best || score[i] < bestscore[i])
500 for (i = 0; i < NUM_MATCH_VALUES; i++)
501 bestscore[i] = score[i];
508 if (FcDebug () & FC_DBG_MATCH)
510 printf ("Best score");
511 for (i = 0; i < NUM_MATCH_VALUES; i++)
512 printf (" %g", bestscore[i]);
513 FcPatternPrint (best);
517 *result = FcResultNoMatch;
520 return FcFontRenderPrepare (config, p, best);
524 FcFontMatch (FcConfig *config,
533 config = FcConfigGetCurrent ();
538 if (config->fonts[FcSetSystem])
539 sets[nsets++] = config->fonts[FcSetSystem];
540 if (config->fonts[FcSetApplication])
541 sets[nsets++] = config->fonts[FcSetApplication];
542 return FcFontSetMatch (config, sets, nsets, p, result);
545 typedef struct _FcSortNode {
547 double score[NUM_MATCH_VALUES];
551 FcSortCompare (const void *aa, const void *ab)
553 FcSortNode *a = *(FcSortNode **) aa;
554 FcSortNode *b = *(FcSortNode **) ab;
555 double *as = &a->score[0];
556 double *bs = &b->score[0];
557 double ad = 0, bd = 0;
560 i = NUM_MATCH_VALUES;
561 while (i-- && (ad = *as++) == (bd = *bs++))
563 return ad < bd ? -1 : ad > bd ? 1 : 0;
567 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
575 if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) ==
579 * If this font isn't a subset of the previous fonts,
582 if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
586 ncs = FcCharSetUnion (ncs, *cs);
589 FcCharSetDestroy (*cs);
592 ncs = FcCharSetCopy (ncs);
594 FcPatternReference (node->pattern);
595 if (FcDebug () & FC_DBG_MATCH)
598 FcPatternPrint (node->pattern);
600 if (!FcFontSetAdd (fs, node->pattern))
602 FcPatternDestroy (node->pattern);
612 FcFontSetSortDestroy (FcFontSet *fs)
614 FcFontSetDestroy (fs);
618 FcFontSetSort (FcConfig *config,
629 FcSortNode **nodeps, **nodep;
637 if (FcDebug () & FC_DBG_MATCH)
643 for (set = 0; set < nsets; set++)
653 nodes = malloc (nnodes * sizeof (FcSortNode) + nnodes * sizeof (FcSortNode *));
656 nodeps = (FcSortNode **) (nodes + nnodes);
660 for (set = 0; set < nsets; set++)
665 for (f = 0; f < s->nfont; f++)
667 if (FcDebug () & FC_DBG_MATCHV)
669 printf ("Font %d ", f);
670 FcPatternPrint (s->fonts[f]);
672 new->pattern = s->fonts[f];
673 if (!FcCompare (p, new->pattern, new->score, result))
675 if (FcDebug () & FC_DBG_MATCHV)
678 for (i = 0; i < NUM_MATCH_VALUES; i++)
680 printf (" %g", new->score[i]);
690 nnodes = new - nodes;
692 qsort (nodeps, nnodes, sizeof (FcSortNode *),
695 ret = FcFontSetCreate ();
701 if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
707 FcCharSetDestroy (cs);
715 FcCharSetDestroy (cs);
716 FcFontSetDestroy (ret);
724 FcFontSort (FcConfig *config,
735 config = FcConfigGetCurrent ();
740 if (config->fonts[FcSetSystem])
741 sets[nsets++] = config->fonts[FcSetSystem];
742 if (config->fonts[FcSetApplication])
743 sets[nsets++] = config->fonts[FcSetApplication];
744 return FcFontSetSort (config, sets, nsets, p, trim, csp, result);