2 * $XFree86: xc/lib/fontconfig/src/fcmatch.c,v 1.11 2002/06/08 17:32:04 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 FcCompareBool (char *object, FcValue value1, FcValue value2)
54 if (value2.type != FcTypeBool || value1.type != FcTypeBool)
56 return (double) value2.u.b != value1.u.b;
60 FcCompareCharSet (char *object, FcValue value1, FcValue value2)
62 if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
64 return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
68 FcCompareSize (char *object, FcValue value1, FcValue value2)
72 switch (value1.type) {
82 switch (value2.type) {
101 * Order is significant, it defines the precedence of
102 * each value, earlier values are more significant than
105 static FcMatcher _FcMatchers [] = {
106 { FC_FOUNDRY, FcCompareString, },
107 #define MATCH_FOUNDRY 0
109 { FC_CHARSET, FcCompareCharSet },
110 #define MATCH_CHARSET 1
112 { FC_LANG, FcCompareString },
115 { FC_FAMILY, FcCompareString, },
116 #define MATCH_FAMILY 3
118 { FC_SPACING, FcCompareInteger, },
119 #define MATCH_SPACING 4
121 { FC_PIXEL_SIZE, FcCompareSize, },
122 #define MATCH_PIXEL_SIZE 5
124 { FC_STYLE, FcCompareString, },
125 #define MATCH_STYLE 6
127 { FC_SLANT, FcCompareInteger, },
128 #define MATCH_SLANT 7
130 { FC_WEIGHT, FcCompareInteger, },
131 #define MATCH_WEIGHT 8
133 { FC_ANTIALIAS, FcCompareBool, },
134 #define MATCH_ANTIALIAS 9
136 { FC_RASTERIZER, FcCompareString, },
137 #define MATCH_RASTERIZER 10
139 { FC_OUTLINE, FcCompareBool, },
140 #define MATCH_OUTLINE 11
143 #define NUM_MATCHER (sizeof _FcMatchers / sizeof _FcMatchers[0])
146 FcCompareValueList (const char *object,
147 FcValueList *v1orig, /* pattern */
148 FcValueList *v2orig, /* target */
153 FcValueList *v1, *v2;
159 * Locate the possible matching entry by examining the
160 * first few characters in object
163 switch (FcToLower (object[0])) {
165 switch (FcToLower (object[1])) {
167 i = MATCH_FOUNDRY; break;
169 i = MATCH_FAMILY; break;
173 i = MATCH_CHARSET; break;
175 i = MATCH_ANTIALIAS; break;
177 i = MATCH_LANG; break;
179 switch (FcToLower (object[1])) {
181 i = MATCH_SPACING; break;
183 i = MATCH_STYLE; break;
185 i = MATCH_SLANT; break;
189 i = MATCH_PIXEL_SIZE; break;
191 i = MATCH_WEIGHT; break;
193 i = MATCH_RASTERIZER; break;
195 i = MATCH_OUTLINE; break;
198 FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
199 (FcChar8 *) object) != 0)
202 *bestValue = v2orig->value;
206 for (i = 0; i < NUM_MATCHER; i++)
208 if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
212 if (i == NUM_MATCHER)
215 *bestValue = v2orig->value;
221 for (v1 = v1orig; v1; v1 = v1->next)
223 for (v2 = v2orig; v2; v2 = v2->next)
225 v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
230 *result = FcResultTypeMismatch;
233 if (FcDebug () & FC_DBG_MATCHV)
234 printf (" v %g j %d ", v, j);
239 *bestValue = v2->value;
245 if (FcDebug () & FC_DBG_MATCHV)
247 printf (" %s: %g ", object, best);
248 FcValueListPrint (v1orig);
250 FcValueListPrint (v2orig);
259 * Return a value indicating the distance between the two lists of
264 FcCompare (FcPattern *pat,
271 for (i = 0; i < NUM_MATCHER; i++)
276 while (i1 < pat->num && i2 < fnt->num)
278 i = strcmp (pat->elts[i1].object, fnt->elts[i2].object);
285 if (!FcCompareValueList (pat->elts[i1].object,
286 pat->elts[i1].values,
287 fnt->elts[i2].values,
298 for (i1 = 0; i1 < pat->num; i1++)
300 for (i2 = 0; i2 < fnt->num; i2++)
302 if (!strcmp (pat->elts[i1].object, fnt->elts[i2].object))
313 FcFontRenderPrepare (FcConfig *config,
319 FcPatternElt *fe, *pe;
323 new = FcPatternCreate ();
326 for (i = 0; i < font->num; i++)
329 pe = FcPatternFindElt (pat, fe->object);
333 double score[NUM_MATCHER];
335 for (j = 0; j < NUM_MATCHER; j++)
337 if (!FcCompareValueList (pe->object, pe->values,
338 fe->values, &v, 0, &result))
340 FcPatternDestroy (new);
343 for (j = 0; j < NUM_MATCHER; j++)
344 if (score[j] >= 100.0)
348 for (pv = pe->values; pv; pv = pv->next)
349 FcPatternAdd (new, fe->object, pv->value, FcTrue);
354 v = fe->values->value;
355 FcPatternAdd (new, fe->object, v, FcFalse);
357 for (i = 0; i < pat->num; i++)
360 fe = FcPatternFindElt (font, pe->object);
362 FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
364 FcConfigSubstitute (config, new, FcMatchFont);
369 FcFontSetMatch (FcConfig *config,
375 double score[NUM_MATCHER], bestscore[NUM_MATCHER];
382 for (i = 0; i < NUM_MATCHER; i++)
385 if (FcDebug () & FC_DBG_MATCH)
392 config = FcConfigGetCurrent ();
396 for (set = 0; set < nsets; set++)
401 for (f = 0; f < s->nfont; f++)
403 if (FcDebug () & FC_DBG_MATCHV)
405 printf ("Font %d ", f);
406 FcPatternPrint (s->fonts[f]);
408 if (!FcCompare (p, s->fonts[f], score, result))
410 if (FcDebug () & FC_DBG_MATCHV)
413 for (i = 0; i < NUM_MATCHER; i++)
415 printf (" %g", score[i]);
419 for (i = 0; i < NUM_MATCHER; i++)
421 if (best && bestscore[i] < score[i])
423 if (!best || score[i] < bestscore[i])
425 for (i = 0; i < NUM_MATCHER; i++)
426 bestscore[i] = score[i];
433 if (FcDebug () & FC_DBG_MATCH)
435 printf ("Best score");
436 for (i = 0; i < NUM_MATCHER; i++)
437 printf (" %g", bestscore[i]);
438 FcPatternPrint (best);
442 *result = FcResultNoMatch;
445 return FcFontRenderPrepare (config, p, best);
449 FcFontMatch (FcConfig *config,
458 config = FcConfigGetCurrent ();
463 if (config->fonts[FcSetSystem])
464 sets[nsets++] = config->fonts[FcSetSystem];
465 if (config->fonts[FcSetApplication])
466 sets[nsets++] = config->fonts[FcSetApplication];
467 return FcFontSetMatch (config, sets, nsets, p, result);
470 typedef struct _FcSortNode {
472 double score[NUM_MATCHER];
476 FcSortCompare (const void *aa, const void *ab)
478 FcSortNode *a = *(FcSortNode **) aa;
479 FcSortNode *b = *(FcSortNode **) ab;
480 double *as = &a->score[0];
481 double *bs = &b->score[0];
482 double ad = 0, bd = 0;
486 while (i-- && (ad = *as++) == (bd = *bs++))
488 return ad < bd ? -1 : ad > bd ? 1 : 0;
492 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
500 if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) ==
504 * If this font isn't a subset of the previous fonts,
507 if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
511 ncs = FcCharSetUnion (ncs, *cs);
514 FcCharSetDestroy (*cs);
517 ncs = FcCharSetCopy (ncs);
519 FcPatternReference (node->pattern);
520 if (!FcFontSetAdd (fs, node->pattern))
522 FcPatternDestroy (node->pattern);
532 FcFontSetSortDestroy (FcFontSet *fs)
534 FcFontSetDestroy (fs);
538 FcFontSetSort (FcConfig *config,
549 FcSortNode **nodeps, **nodep;
558 for (set = 0; set < nsets; set++)
567 nodes = malloc (nnodes * sizeof (FcSortNode) + nnodes * sizeof (FcSortNode *));
570 nodeps = (FcSortNode **) (nodes + nnodes);
574 for (set = 0; set < nsets; set++)
579 for (f = 0; f < s->nfont; f++)
581 if (FcDebug () & FC_DBG_MATCHV)
583 printf ("Font %d ", f);
584 FcPatternPrint (s->fonts[f]);
586 new->pattern = s->fonts[f];
587 if (!FcCompare (p, new->pattern, new->score, result))
589 if (FcDebug () & FC_DBG_MATCHV)
592 for (i = 0; i < NUM_MATCHER; i++)
594 printf (" %g", new->score[i]);
604 nnodes = new - nodes;
606 qsort (nodeps, nnodes, sizeof (FcSortNode *),
609 ret = FcFontSetCreate ();
615 if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
621 FcCharSetDestroy (cs);
629 FcCharSetDestroy (cs);
630 FcFontSetDestroy (ret);
638 FcFontSort (FcConfig *config,
649 config = FcConfigGetCurrent ();
654 if (config->fonts[FcSetSystem])
655 sets[nsets++] = config->fonts[FcSetSystem];
656 if (config->fonts[FcSetApplication])
657 sets[nsets++] = config->fonts[FcSetApplication];
658 return FcFontSetSort (config, sets, nsets, p, trim, csp, result);