2 * $XFree86: xc/lib/fontconfig/src/fcmatch.c,v 1.2 2002/02/15 06:01:28 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 { FC_CHARSET, FcCompareCharSet },
108 { FC_ANTIALIAS, FcCompareBool, },
109 { FC_LANG, FcCompareString },
110 { FC_FAMILY, FcCompareString, },
111 { FC_SPACING, FcCompareInteger, },
112 { FC_PIXEL_SIZE, FcCompareSize, },
113 { FC_STYLE, FcCompareString, },
114 { FC_SLANT, FcCompareInteger, },
115 { FC_WEIGHT, FcCompareInteger, },
116 { FC_RASTERIZER, FcCompareString, },
117 { FC_OUTLINE, FcCompareBool, },
120 #define NUM_MATCHER (sizeof _FcMatchers / sizeof _FcMatchers[0])
123 FcCompareValueList (const char *object,
124 FcValueList *v1orig, /* pattern */
125 FcValueList *v2orig, /* target */
130 FcValueList *v1, *v2;
135 for (i = 0; i < NUM_MATCHER; i++)
137 if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
141 if (i == NUM_MATCHER)
144 *bestValue = v2orig->value;
150 for (v1 = v1orig; v1; v1 = v1->next)
152 for (v2 = v2orig; v2; v2 = v2->next)
154 v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
159 *result = FcResultTypeMismatch;
162 if (FcDebug () & FC_DBG_MATCHV)
163 printf (" v %g j %d ", v, j);
168 *bestValue = v2->value;
174 if (FcDebug () & FC_DBG_MATCHV)
176 printf (" %s: %g ", object, best);
177 FcValueListPrint (v1orig);
179 FcValueListPrint (v2orig);
187 * Return a value indicating the distance between the two lists of
192 FcCompare (FcPattern *pat,
199 for (i = 0; i < NUM_MATCHER; i++)
202 for (i1 = 0; i1 < pat->num; i1++)
204 for (i2 = 0; i2 < fnt->num; i2++)
206 if (!FcStrCmpIgnoreCase ((FcChar8 *) pat->elts[i1].object,
207 (FcChar8 *) fnt->elts[i2].object))
209 if (!FcCompareValueList (pat->elts[i1].object,
210 pat->elts[i1].values,
211 fnt->elts[i2].values,
221 * Overspecified patterns are slightly penalized in
222 * case some other font includes the requested field
226 for (i2 = 0; i2 < NUM_MATCHER; i2++)
228 if (!FcStrCmpIgnoreCase (_FcMatchers[i2].object,
229 pat->elts[i1].object))
242 FcFontRenderPrepare (FcConfig *config,
248 FcPatternElt *fe, *pe;
250 double score[NUM_MATCHER];
253 new = FcPatternCreate ();
256 for (i = 0; i < font->num; i++)
259 pe = FcPatternFind (pat, fe->object, FcFalse);
262 if (!FcCompareValueList (pe->object, pe->values,
263 fe->values, &v, score, &result))
265 FcPatternDestroy (new);
270 v = fe->values->value;
271 FcPatternAdd (new, fe->object, v, FcTrue);
273 for (i = 0; i < pat->num; i++)
276 fe = FcPatternFind (font, pe->object, FcFalse);
278 FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
280 FcConfigSubstitute (config, new, FcMatchFont);
285 FcFontSetMatch (FcConfig *config,
291 double score[NUM_MATCHER], bestscore[NUM_MATCHER];
298 for (i = 0; i < NUM_MATCHER; i++)
301 if (FcDebug () & FC_DBG_MATCH)
308 config = FcConfigGetCurrent ();
312 for (set = 0; set < nsets; set++)
317 for (f = 0; f < s->nfont; f++)
319 if (FcDebug () & FC_DBG_MATCHV)
321 printf ("Font %d ", f);
322 FcPatternPrint (s->fonts[f]);
324 if (!FcCompare (p, s->fonts[f], score, result))
326 if (FcDebug () & FC_DBG_MATCHV)
329 for (i = 0; i < NUM_MATCHER; i++)
331 printf (" %g", score[i]);
335 for (i = 0; i < NUM_MATCHER; i++)
337 if (best && bestscore[i] < score[i])
339 if (!best || score[i] < bestscore[i])
341 for (i = 0; i < NUM_MATCHER; i++)
342 bestscore[i] = score[i];
349 if (FcDebug () & FC_DBG_MATCH)
351 printf ("Best score");
352 for (i = 0; i < NUM_MATCHER; i++)
353 printf (" %g", bestscore[i]);
354 FcPatternPrint (best);
358 *result = FcResultNoMatch;
361 return FcFontRenderPrepare (config, p, best);
365 FcFontMatch (FcConfig *config,
374 config = FcConfigGetCurrent ();
379 if (config->fonts[FcSetSystem])
380 sets[nsets++] = config->fonts[FcSetSystem];
381 if (config->fonts[FcSetApplication])
382 sets[nsets++] = config->fonts[FcSetApplication];
383 return FcFontSetMatch (config, sets, nsets, p, result);
386 typedef struct _FcSortNode {
388 double score[NUM_MATCHER];
392 FcSortCompare (const void *aa, const void *ab)
394 FcSortNode *a = *(FcSortNode **) aa;
395 FcSortNode *b = *(FcSortNode **) ab;
398 for (i = 0; i < NUM_MATCHER; i++)
400 if (a->score[i] > b->score[i])
402 if (a->score[i] < b->score[i])
409 FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
417 if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) ==
421 * If this font isn't a subset of the previous fonts,
424 if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
428 ncs = FcCharSetUnion (ncs, *cs);
431 FcCharSetDestroy (*cs);
434 ncs = FcCharSetCopy (ncs);
436 if (!FcFontSetAdd (fs, node->pattern))
445 FcFontSetSortDestroy (FcFontSet *fs)
448 FcFontSetDestroy (fs);
452 FcFontSetSort (FcConfig *config,
463 FcSortNode **nodeps, **nodep;
472 for (set = 0; set < nsets; set++)
481 nodes = malloc (nnodes * sizeof (FcSortNode) + nnodes * sizeof (FcSortNode *));
484 nodeps = (FcSortNode **) (nodes + nnodes);
488 for (set = 0; set < nsets; set++)
493 for (f = 0; f < s->nfont; f++)
495 if (FcDebug () & FC_DBG_MATCHV)
497 printf ("Font %d ", f);
498 FcPatternPrint (s->fonts[f]);
500 new->pattern = s->fonts[f];
501 if (!FcCompare (p, new->pattern, new->score, result))
503 if (FcDebug () & FC_DBG_MATCHV)
506 for (i = 0; i < NUM_MATCHER; i++)
508 printf (" %g", new->score[i]);
518 nnodes = new - nodes;
520 qsort (nodeps, nnodes, sizeof (FcSortNode *),
523 ret = FcFontSetCreate ();
529 if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
540 FcCharSetDestroy (cs);
541 FcFontSetDestroy (ret);