]> git.wh0rd.org Git - fontconfig.git/blob - src/fcmatch.c
2040515dae01a6cb83e9a7b5f61a622c62e5b346
[fontconfig.git] / src / fcmatch.c
1 /*
2  * $XFree86: $
3  *
4  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5  *
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.
15  *
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.
23  */
24
25 #include <string.h>
26 #include <ctype.h>
27 #include "fcint.h"
28 #include <stdio.h>
29
30 static double
31 FcCompareInteger (char *object, FcValue value1, FcValue value2)
32 {
33     int v;
34     
35     if (value2.type != FcTypeInteger || value1.type != FcTypeInteger)
36         return -1.0;
37     v = value2.u.i - value1.u.i;
38     if (v < 0)
39         v = -v;
40     return (double) v;
41 }
42
43 static double
44 FcCompareString (char *object, FcValue value1, FcValue value2)
45 {
46     if (value2.type != FcTypeString || value1.type != FcTypeString)
47         return -1.0;
48     return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
49 }
50
51 static double
52 FcCompareBool (char *object, FcValue value1, FcValue value2)
53 {
54     if (value2.type != FcTypeBool || value1.type != FcTypeBool)
55         return -1.0;
56     return (double) value2.u.b != value1.u.b;
57 }
58
59 static double
60 FcCompareCharSet (char *object, FcValue value1, FcValue value2)
61 {
62     if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
63         return -1.0;
64     return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
65 }
66
67 static double
68 FcCompareSize (char *object, FcValue value1, FcValue value2)
69 {
70     double  v1, v2, v;
71
72     switch (value1.type) {
73     case FcTypeInteger:
74         v1 = value1.u.i;
75         break;
76     case FcTypeDouble:
77         v1 = value1.u.d;
78         break;
79     default:
80         return -1;
81     }
82     switch (value2.type) {
83     case FcTypeInteger:
84         v2 = value2.u.i;
85         break;
86     case FcTypeDouble:
87         v2 = value2.u.d;
88         break;
89     default:
90         return -1;
91     }
92     if (v2 == 0)
93         return 0;
94     v = v2 - v1;
95     if (v < 0)
96         v = -v;
97     return v;
98 }
99
100 /*
101  * Order is significant, it defines the precedence of
102  * each value, earlier values are more significant than
103  * later values
104  */
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, },
118 };
119
120 #define NUM_MATCHER (sizeof _FcMatchers / sizeof _FcMatchers[0])
121
122 static FcBool
123 FcCompareValueList (const char  *object,
124                     FcValueList *v1orig,        /* pattern */
125                     FcValueList *v2orig,        /* target */
126                     FcValue     *bestValue,
127                     double      *value,
128                     FcResult    *result)
129 {
130     FcValueList    *v1, *v2;
131     double          v, best;
132     int             j;
133     int             i;
134     
135     for (i = 0; i < NUM_MATCHER; i++)
136     {
137         if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
138                                  (FcChar8 *) object))
139             break;
140     }
141     if (i == NUM_MATCHER)
142     {
143         if (bestValue)
144             *bestValue = v2orig->value;
145         return FcTrue;
146     }
147     
148     best = 1e99;
149     j = 0;
150     for (v1 = v1orig; v1; v1 = v1->next)
151     {
152         for (v2 = v2orig; v2; v2 = v2->next)
153         {
154             v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
155                                             v1->value,
156                                             v2->value);
157             if (v < 0)
158             {
159                 *result = FcResultTypeMismatch;
160                 return FcFalse;
161             }
162             if (FcDebug () & FC_DBG_MATCHV)
163                 printf (" v %g j %d ", v, j);
164             v = v * 100 + j;
165             if (v < best)
166             {
167                 if (bestValue)
168                     *bestValue = v2->value;
169                 best = v;
170             }
171         }
172         j++;
173     }
174     if (FcDebug () & FC_DBG_MATCHV)
175     {
176         printf (" %s: %g ", object, best);
177         FcValueListPrint (v1orig);
178         printf (", ");
179         FcValueListPrint (v2orig);
180         printf ("\n");
181     }
182     value[i] += best;
183     return FcTrue;
184 }
185
186 /*
187  * Return a value indicating the distance between the two lists of
188  * values
189  */
190
191 static FcBool
192 FcCompare (FcPattern    *pat,
193            FcPattern    *fnt,
194            double       *value,
195            FcResult     *result)
196 {
197     int             i, i1, i2;
198     
199     for (i = 0; i < NUM_MATCHER; i++)
200         value[i] = 0.0;
201     
202     for (i1 = 0; i1 < pat->num; i1++)
203     {
204         for (i2 = 0; i2 < fnt->num; i2++)
205         {
206             if (!FcStrCmpIgnoreCase ((FcChar8 *) pat->elts[i1].object,
207                                      (FcChar8 *) fnt->elts[i2].object))
208             {
209                 if (!FcCompareValueList (pat->elts[i1].object,
210                                          pat->elts[i1].values,
211                                          fnt->elts[i2].values,
212                                          0,
213                                          value,
214                                          result))
215                     return FcFalse;
216                 break;
217             }
218         }
219 #if 0
220         /*
221          * Overspecified patterns are slightly penalized in
222          * case some other font includes the requested field
223          */
224         if (i2 == fnt->num)
225         {
226             for (i2 = 0; i2 < NUM_MATCHER; i2++)
227             {
228                 if (!FcStrCmpIgnoreCase (_FcMatchers[i2].object,
229                                          pat->elts[i1].object))
230                 {
231                     value[i2] = 1.0;
232                     break;
233                 }
234             }
235         }
236 #endif
237     }
238     return FcTrue;
239 }
240
241 FcPattern *
242 FcFontMatch (FcConfig   *config,
243              FcPattern  *p, 
244              FcResult   *result)
245 {
246     double          score[NUM_MATCHER], bestscore[NUM_MATCHER];
247     int             f;
248     FcFontSet       *s;
249     FcPattern       *best;
250     FcPattern       *new;
251     FcPatternElt   *fe, *pe;
252     FcValue         v;
253     int             i;
254     FcSetName       set;
255
256     for (i = 0; i < NUM_MATCHER; i++)
257         bestscore[i] = 0;
258     best = 0;
259     if (FcDebug () & FC_DBG_MATCH)
260     {
261         printf ("Match ");
262         FcPatternPrint (p);
263     }
264     if (!config)
265     {
266         config = FcConfigGetCurrent ();
267         if (!config)
268             return 0;
269     }
270     for (set = FcSetSystem; set <= FcSetApplication; set++)
271     {
272         s = config->fonts[set];
273         if (!s)
274             continue;
275         for (f = 0; f < s->nfont; f++)
276         {
277             if (FcDebug () & FC_DBG_MATCHV)
278             {
279                 printf ("Font %d ", f);
280                 FcPatternPrint (s->fonts[f]);
281             }
282             if (!FcCompare (p, s->fonts[f], score, result))
283                 return 0;
284             if (FcDebug () & FC_DBG_MATCHV)
285             {
286                 printf ("Score");
287                 for (i = 0; i < NUM_MATCHER; i++)
288                 {
289                     printf (" %g", score[i]);
290                 }
291                 printf ("\n");
292             }
293             for (i = 0; i < NUM_MATCHER; i++)
294             {
295                 if (best && bestscore[i] < score[i])
296                     break;
297                 if (!best || score[i] < bestscore[i])
298                 {
299                     for (i = 0; i < NUM_MATCHER; i++)
300                         bestscore[i] = score[i];
301                     best = s->fonts[f];
302                     break;
303                 }
304             }
305         }
306     }
307     if (FcDebug () & FC_DBG_MATCH)
308     {
309         printf ("Best score");
310         for (i = 0; i < NUM_MATCHER; i++)
311             printf (" %g", bestscore[i]);
312         FcPatternPrint (best);
313     }
314     if (!best)
315     {
316         *result = FcResultNoMatch;
317         return 0;
318     }
319     new = FcPatternCreate ();
320     if (!new)
321         return 0;
322     for (i = 0; i < best->num; i++)
323     {
324         fe = &best->elts[i];
325         pe = FcPatternFind (p, fe->object, FcFalse);
326         if (pe)
327         {
328             if (!FcCompareValueList (pe->object, pe->values, 
329                                      fe->values, &v, score, result))
330             {
331                 FcPatternDestroy (new);
332                 return 0;
333             }
334         }
335         else
336             v = fe->values->value;
337         FcPatternAdd (new, fe->object, v, FcTrue);
338     }
339     for (i = 0; i < p->num; i++)
340     {
341         pe = &p->elts[i];
342         fe = FcPatternFind (best, pe->object, FcFalse);
343         if (!fe)
344             FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
345     }
346     FcConfigSubstitute (config, new, FcMatchFont);
347     return new;
348 }