]> git.wh0rd.org - fontconfig.git/blame - src/fcmatch.c
Fix incorrect merge.
[fontconfig.git] / src / fcmatch.c
CommitLineData
24330d27 1/*
4bd4418a 2 * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
24330d27 3 *
46b51147 4 * Copyright © 2000 Keith Packard
24330d27
KP
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
30static double
9ab79bdf 31FcCompareNumber (FcValue *value1, FcValue *value2)
24330d27 32{
2d39321f 33 double v1, v2, v;
24330d27 34
4262e0b3 35 switch (value1->type) {
2d39321f 36 case FcTypeInteger:
4262e0b3 37 v1 = (double) value1->u.i;
2d39321f
KP
38 break;
39 case FcTypeDouble:
4262e0b3 40 v1 = value1->u.d;
2d39321f
KP
41 break;
42 default:
24330d27 43 return -1.0;
2d39321f 44 }
4262e0b3 45 switch (value2->type) {
2d39321f 46 case FcTypeInteger:
4262e0b3 47 v2 = (double) value2->u.i;
2d39321f
KP
48 break;
49 case FcTypeDouble:
4262e0b3 50 v2 = value2->u.d;
2d39321f
KP
51 break;
52 default:
53 return -1.0;
54 }
55 v = v2 - v1;
24330d27
KP
56 if (v < 0)
57 v = -v;
4f8b266f 58 return v;
24330d27
KP
59}
60
61static double
9ab79bdf 62FcCompareString (FcValue *v1, FcValue *v2)
24330d27 63{
1c9fdcca 64 return (double) FcStrCmpIgnoreCase (fc_value_string(v1), fc_value_string(v2)) != 0;
24330d27
KP
65}
66
82f4243f 67static double
9ab79bdf 68FcCompareFamily (FcValue *v1, FcValue *v2)
82f4243f 69{
4f8b266f
PL
70 /* rely on the guarantee in FcPatternAddWithBinding that
71 * families are always FcTypeString. */
4f8b266f
PL
72 const FcChar8* v1_string = fc_value_string(v1);
73 const FcChar8* v2_string = fc_value_string(v2);
74
75 if (FcToLower(*v1_string) != FcToLower(*v2_string))
76 return 1.0;
77
78 return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
82f4243f
KP
79}
80
81static double
9ab79bdf 82FcCompareLang (FcValue *v1, FcValue *v2)
82f4243f
KP
83{
84 FcLangResult result;
4262e0b3 85 FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
82f4243f 86
d8d73958
KP
87 switch (value1.type) {
88 case FcTypeLangSet:
89 switch (value2.type) {
90 case FcTypeLangSet:
4262e0b3 91 result = FcLangSetCompare (value1.u.l, value2.u.l);
d8d73958
KP
92 break;
93 case FcTypeString:
4262e0b3
PL
94 result = FcLangSetHasLang (value1.u.l,
95 value2.u.s);
d8d73958
KP
96 break;
97 default:
98 return -1.0;
99 }
100 break;
101 case FcTypeString:
102 switch (value2.type) {
103 case FcTypeLangSet:
4262e0b3 104 result = FcLangSetHasLang (value2.u.l, value1.u.s);
d8d73958
KP
105 break;
106 case FcTypeString:
4262e0b3
PL
107 result = FcLangCompare (value1.u.s,
108 value2.u.s);
d8d73958
KP
109 break;
110 default:
111 return -1.0;
112 }
113 break;
114 default:
82f4243f 115 return -1.0;
d8d73958 116 }
82f4243f
KP
117 switch (result) {
118 case FcLangEqual:
119 return 0;
120 case FcLangDifferentCountry:
121 return 1;
122 case FcLangDifferentLang:
123 default:
124 return 2;
125 }
126}
127
24330d27 128static double
9ab79bdf 129FcCompareBool (FcValue *v1, FcValue *v2)
24330d27 130{
1c9fdcca 131 if (fc_storage_type(v2) != FcTypeBool || fc_storage_type(v1) != FcTypeBool)
24330d27 132 return -1.0;
1c9fdcca 133 return (double) v2->u.b != v1->u.b;
24330d27
KP
134}
135
136static double
9ab79bdf 137FcCompareCharSet (FcValue *v1, FcValue *v2)
24330d27 138{
1c9fdcca 139 return (double) FcCharSetSubtractCount (fc_value_charset(v1), fc_value_charset(v2));
24330d27
KP
140}
141
142static double
9ab79bdf 143FcCompareSize (FcValue *value1, FcValue *value2)
24330d27
KP
144{
145 double v1, v2, v;
146
4262e0b3 147 switch (value1->type) {
24330d27 148 case FcTypeInteger:
4262e0b3 149 v1 = value1->u.i;
24330d27
KP
150 break;
151 case FcTypeDouble:
4262e0b3 152 v1 = value1->u.d;
24330d27
KP
153 break;
154 default:
155 return -1;
156 }
4262e0b3 157 switch (value2->type) {
24330d27 158 case FcTypeInteger:
4262e0b3 159 v2 = value2->u.i;
24330d27
KP
160 break;
161 case FcTypeDouble:
4262e0b3 162 v2 = value2->u.d;
24330d27
KP
163 break;
164 default:
165 return -1;
166 }
167 if (v2 == 0)
168 return 0;
169 v = v2 - v1;
170 if (v < 0)
171 v = -v;
172 return v;
173}
174
4c003605 175typedef struct _FcMatcher {
67accef4 176 const char *object;
cbe1df81 177 FcObjectPtr objectPtr;
9ab79bdf 178 double (*compare) (FcValue *value1, FcValue *value2);
4c003605
KP
179 int strong, weak;
180} FcMatcher;
181
24330d27
KP
182/*
183 * Order is significant, it defines the precedence of
184 * each value, earlier values are more significant than
185 * later values
186 */
187static FcMatcher _FcMatchers [] = {
cbe1df81 188 { FC_FOUNDRY, 0, FcCompareString, 0, 0 },
4c003605 189#define MATCH_FOUNDRY 0
5cf8c536 190#define MATCH_FOUNDRY_INDEX 0
bc9469ba 191
cbe1df81 192 { FC_CHARSET, 0, FcCompareCharSet, 1, 1 },
4c003605 193#define MATCH_CHARSET 1
5cf8c536 194#define MATCH_CHARSET_INDEX 1
bc9469ba 195
cbe1df81 196 { FC_FAMILY, 0, FcCompareFamily, 2, 4 },
4c003605 197#define MATCH_FAMILY 2
5cf8c536
KP
198#define MATCH_FAMILY_STRONG_INDEX 2
199#define MATCH_FAMILY_WEAK_INDEX 4
bc9469ba 200
cbe1df81 201 { FC_LANG, 0, FcCompareLang, 3, 3 },
4c003605 202#define MATCH_LANG 3
5cf8c536 203#define MATCH_LANG_INDEX 3
bc9469ba 204
cbe1df81 205 { FC_SPACING, 0, FcCompareNumber, 5, 5 },
4c003605 206#define MATCH_SPACING 4
5cf8c536 207#define MATCH_SPACING_INDEX 5
bc9469ba 208
cbe1df81 209 { FC_PIXEL_SIZE, 0, FcCompareSize, 6, 6 },
4c003605 210#define MATCH_PIXEL_SIZE 5
5cf8c536 211#define MATCH_PIXEL_SIZE_INDEX 6
bc9469ba 212
cbe1df81 213 { FC_STYLE, 0, FcCompareString, 7, 7 },
4c003605 214#define MATCH_STYLE 6
5cf8c536 215#define MATCH_STYLE_INDEX 7
bc9469ba 216
cbe1df81 217 { FC_SLANT, 0, FcCompareNumber, 8, 8 },
4c003605 218#define MATCH_SLANT 7
5cf8c536 219#define MATCH_SLANT_INDEX 8
bc9469ba 220
cbe1df81 221 { FC_WEIGHT, 0, FcCompareNumber, 9, 9 },
4c003605 222#define MATCH_WEIGHT 8
5cf8c536 223#define MATCH_WEIGHT_INDEX 9
f534109f 224
cbe1df81 225 { FC_WIDTH, 0, FcCompareNumber, 10, 10 },
81fa16c3 226#define MATCH_WIDTH 9
5cf8c536 227#define MATCH_WIDTH_INDEX 10
bc9469ba 228
cbe1df81 229 { FC_ANTIALIAS, 0, FcCompareBool, 11, 11 },
81fa16c3 230#define MATCH_ANTIALIAS 10
5cf8c536 231#define MATCH_ANTIALIAS_INDEX 11
bc9469ba 232
cbe1df81 233 { FC_RASTERIZER, 0, FcCompareString, 12, 12 },
81fa16c3 234#define MATCH_RASTERIZER 11
5cf8c536
KP
235#define MATCH_RASTERIZER_INDEX 12
236
cbe1df81 237 { FC_OUTLINE, 0, FcCompareBool, 13, 13 },
81fa16c3 238#define MATCH_OUTLINE 12
5cf8c536 239#define MATCH_OUTLINE_INDEX 13
a342e87d 240
cbe1df81 241 { FC_FONTVERSION, 0, FcCompareNumber, 14, 14 },
81fa16c3 242#define MATCH_FONTVERSION 13
5cf8c536 243#define MATCH_FONTVERSION_INDEX 14
24330d27
KP
244};
245
81fa16c3 246#define NUM_MATCH_VALUES 15
24330d27 247
cbe1df81
PL
248static FcBool matchObjectPtrsInit = FcFalse;
249
250static void
251FcMatchObjectPtrsInit (void)
252{
253 _FcMatchers[MATCH_FOUNDRY].objectPtr = FcObjectToPtr(FC_FOUNDRY);
254 _FcMatchers[MATCH_CHARSET].objectPtr = FcObjectToPtr(FC_CHARSET);
255 _FcMatchers[MATCH_FAMILY].objectPtr = FcObjectToPtr(FC_FAMILY);
256 _FcMatchers[MATCH_LANG].objectPtr = FcObjectToPtr(FC_LANG);
257 _FcMatchers[MATCH_SPACING].objectPtr = FcObjectToPtr(FC_SPACING);
258 _FcMatchers[MATCH_PIXEL_SIZE].objectPtr = FcObjectToPtr(FC_PIXEL_SIZE);
259 _FcMatchers[MATCH_STYLE].objectPtr = FcObjectToPtr(FC_STYLE);
260 _FcMatchers[MATCH_SLANT].objectPtr = FcObjectToPtr(FC_SLANT);
261 _FcMatchers[MATCH_WEIGHT].objectPtr = FcObjectToPtr(FC_WEIGHT);
262 _FcMatchers[MATCH_WIDTH].objectPtr = FcObjectToPtr(FC_WIDTH);
263 _FcMatchers[MATCH_ANTIALIAS].objectPtr = FcObjectToPtr(FC_ANTIALIAS);
264 _FcMatchers[MATCH_RASTERIZER].objectPtr = FcObjectToPtr(FC_RASTERIZER);
265 _FcMatchers[MATCH_OUTLINE].objectPtr = FcObjectToPtr(FC_OUTLINE);
266 _FcMatchers[MATCH_FONTVERSION].objectPtr = FcObjectToPtr(FC_FONTVERSION);
267 matchObjectPtrsInit = FcTrue;
268}
269
24330d27 270static FcBool
d854eaf8 271FcCompareValueList (FcObjectPtr o,
cd2ec1a9
PL
272 FcValueListPtr v1orig, /* pattern */
273 FcValueListPtr v2orig, /* target */
24330d27
KP
274 FcValue *bestValue,
275 double *value,
276 FcResult *result)
277{
adac22f2
PL
278 FcValueListPtr v1, v2;
279 FcValueList *v1_ptrU, *v2_ptrU;
4c003605 280 double v, best, bestStrong, bestWeak;
24330d27 281 int i;
4c003605 282 int j;
cbe1df81 283 const char *object = FcObjectPtrU(o);
d854eaf8 284
bc9469ba
KP
285 /*
286 * Locate the possible matching entry by examining the
287 * first few characters in object
288 */
289 i = -1;
d854eaf8 290 switch (object[0]) {
bc9469ba 291 case 'f':
d854eaf8 292 switch (object[1]) {
bc9469ba 293 case 'o':
d854eaf8 294 switch (object[2]) {
a342e87d
KP
295 case 'u':
296 i = MATCH_FOUNDRY; break;
297 case 'n':
298 i = MATCH_FONTVERSION; break;
299 }
300 break;
bc9469ba
KP
301 case 'a':
302 i = MATCH_FAMILY; break;
303 }
304 break;
305 case 'c':
306 i = MATCH_CHARSET; break;
307 case 'a':
308 i = MATCH_ANTIALIAS; break;
309 case 'l':
310 i = MATCH_LANG; break;
311 case 's':
d854eaf8 312 switch (object[1]) {
bc9469ba
KP
313 case 'p':
314 i = MATCH_SPACING; break;
315 case 't':
316 i = MATCH_STYLE; break;
317 case 'l':
318 i = MATCH_SLANT; break;
319 }
320 break;
321 case 'p':
322 i = MATCH_PIXEL_SIZE; break;
323 case 'w':
d854eaf8 324 switch (object[1]) {
81fa16c3
KP
325 case 'i':
326 i = MATCH_WIDTH; break;
327 case 'e':
328 i = MATCH_WEIGHT; break;
329 }
330 break;
bc9469ba
KP
331 case 'r':
332 i = MATCH_RASTERIZER; break;
333 case 'o':
334 i = MATCH_OUTLINE; break;
335 }
cbe1df81
PL
336
337 if (!matchObjectPtrsInit)
338 FcMatchObjectPtrsInit();
339 if (_FcMatchers[i].objectPtr != o) i = -1;
340
bc9469ba
KP
341 if (i == -1 ||
342 FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
343 (FcChar8 *) object) != 0)
344 {
345 if (bestValue)
4262e0b3 346 *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
bc9469ba
KP
347 return FcTrue;
348 }
24330d27 349 best = 1e99;
4c003605
KP
350 bestStrong = 1e99;
351 bestWeak = 1e99;
24330d27 352 j = 0;
adac22f2 353 for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
200a44fe 354 v1 = v1_ptrU->next, v1_ptrU = FcValueListPtrU(v1))
24330d27 355 {
200a44fe
PL
356 for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); v2_ptrU;
357 v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
24330d27 358 {
9ab79bdf 359 v = (*_FcMatchers[i].compare) (&v1_ptrU->value,
adac22f2 360 &v2_ptrU->value);
24330d27
KP
361 if (v < 0)
362 {
363 *result = FcResultTypeMismatch;
364 return FcFalse;
365 }
24330d27
KP
366 v = v * 100 + j;
367 if (v < best)
368 {
369 if (bestValue)
adac22f2 370 *bestValue = FcValueCanonicalize(&v2_ptrU->value);
24330d27
KP
371 best = v;
372 }
adac22f2 373 if (v1_ptrU->binding == FcValueBindingStrong)
4c003605
KP
374 {
375 if (v < bestStrong)
376 bestStrong = v;
377 }
378 else
379 {
380 if (v < bestWeak)
381 bestWeak = v;
382 }
24330d27
KP
383 }
384 j++;
385 }
386 if (FcDebug () & FC_DBG_MATCHV)
387 {
388 printf (" %s: %g ", object, best);
389 FcValueListPrint (v1orig);
390 printf (", ");
391 FcValueListPrint (v2orig);
392 printf ("\n");
393 }
d0f07b8d 394 if (value)
4c003605
KP
395 {
396 int weak = _FcMatchers[i].weak;
397 int strong = _FcMatchers[i].strong;
398 if (weak == strong)
399 value[strong] += best;
400 else
401 {
402 value[weak] += bestWeak;
403 value[strong] += bestStrong;
404 }
405 }
24330d27
KP
406 return FcTrue;
407}
408
409/*
410 * Return a value indicating the distance between the two lists of
411 * values
412 */
413
414static FcBool
415FcCompare (FcPattern *pat,
416 FcPattern *fnt,
417 double *value,
418 FcResult *result)
419{
420 int i, i1, i2;
421
4c003605 422 for (i = 0; i < NUM_MATCH_VALUES; i++)
24330d27
KP
423 value[i] = 0.0;
424
bc9469ba
KP
425 i1 = 0;
426 i2 = 0;
427 while (i1 < pat->num && i2 < fnt->num)
24330d27 428 {
9ab79bdf
PL
429 FcPatternElt *elt_i1 = FcPatternEltU(pat->elts)+i1;
430 FcPatternElt *elt_i2 = FcPatternEltU(fnt->elts)+i2;
431
432 i = FcObjectPtrCompare(elt_i1->object, elt_i2->object);
bc9469ba
KP
433 if (i > 0)
434 i2++;
435 else if (i < 0)
436 i1++;
437 else
24330d27 438 {
d854eaf8 439 if (!FcCompareValueList (elt_i1->object,
9ab79bdf
PL
440 elt_i1->values, elt_i2->values,
441 0, value, result))
bc9469ba
KP
442 return FcFalse;
443 i1++;
444 i2++;
24330d27 445 }
bc9469ba
KP
446 }
447 return FcTrue;
24330d27
KP
448}
449
216fac98
KP
450FcPattern *
451FcFontRenderPrepare (FcConfig *config,
452 FcPattern *pat,
453 FcPattern *font)
454{
455 FcPattern *new;
456 int i;
457 FcPatternElt *fe, *pe;
458 FcValue v;
216fac98
KP
459 FcResult result;
460
461 new = FcPatternCreate ();
462 if (!new)
463 return 0;
464 for (i = 0; i < font->num; i++)
465 {
cd2ec1a9
PL
466 fe = FcPatternEltU(font->elts)+i;
467 pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
216fac98
KP
468 if (pe)
469 {
d854eaf8 470 if (!FcCompareValueList (pe->object, pe->values,
938bc633 471 fe->values, &v, 0, &result))
216fac98
KP
472 {
473 FcPatternDestroy (new);
474 return 0;
475 }
476 }
477 else
4262e0b3 478 v = FcValueCanonicalize(&FcValueListPtrU(fe->values)->value);
cd2ec1a9 479 FcPatternAdd (new, FcObjectPtrU(fe->object), v, FcFalse);
216fac98
KP
480 }
481 for (i = 0; i < pat->num; i++)
482 {
cd2ec1a9
PL
483 pe = FcPatternEltU(pat->elts)+i;
484 fe = FcPatternFindElt (font, FcObjectPtrU(pe->object));
216fac98 485 if (!fe)
cd2ec1a9 486 FcPatternAdd (new, FcObjectPtrU(pe->object),
4262e0b3 487 FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
216fac98 488 }
793154ed
PL
489
490 if (FcPatternFindElt (font, FC_FILE))
491 FcPatternTransferFullFname (new, font);
492
fa244f3d 493 FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
216fac98
KP
494 return new;
495}
496
24330d27 497FcPattern *
80c053b7
KP
498FcFontSetMatch (FcConfig *config,
499 FcFontSet **sets,
500 int nsets,
501 FcPattern *p,
502 FcResult *result)
24330d27 503{
4c003605 504 double score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
24330d27
KP
505 int f;
506 FcFontSet *s;
507 FcPattern *best;
24330d27 508 int i;
216fac98 509 int set;
24330d27 510
4c003605 511 for (i = 0; i < NUM_MATCH_VALUES; i++)
24330d27
KP
512 bestscore[i] = 0;
513 best = 0;
514 if (FcDebug () & FC_DBG_MATCH)
515 {
516 printf ("Match ");
517 FcPatternPrint (p);
518 }
519 if (!config)
520 {
521 config = FcConfigGetCurrent ();
522 if (!config)
ec0c740e
KP
523 {
524 *result = FcResultOutOfMemory;
24330d27 525 return 0;
ec0c740e 526 }
24330d27 527 }
80c053b7 528 for (set = 0; set < nsets; set++)
24330d27 529 {
80c053b7 530 s = sets[set];
24330d27
KP
531 if (!s)
532 continue;
533 for (f = 0; f < s->nfont; f++)
534 {
535 if (FcDebug () & FC_DBG_MATCHV)
536 {
537 printf ("Font %d ", f);
538 FcPatternPrint (s->fonts[f]);
539 }
540 if (!FcCompare (p, s->fonts[f], score, result))
541 return 0;
542 if (FcDebug () & FC_DBG_MATCHV)
543 {
544 printf ("Score");
4c003605 545 for (i = 0; i < NUM_MATCH_VALUES; i++)
24330d27
KP
546 {
547 printf (" %g", score[i]);
548 }
549 printf ("\n");
550 }
4c003605 551 for (i = 0; i < NUM_MATCH_VALUES; i++)
24330d27
KP
552 {
553 if (best && bestscore[i] < score[i])
554 break;
555 if (!best || score[i] < bestscore[i])
556 {
4c003605 557 for (i = 0; i < NUM_MATCH_VALUES; i++)
24330d27
KP
558 bestscore[i] = score[i];
559 best = s->fonts[f];
560 break;
561 }
562 }
563 }
564 }
565 if (FcDebug () & FC_DBG_MATCH)
566 {
567 printf ("Best score");
4c003605 568 for (i = 0; i < NUM_MATCH_VALUES; i++)
24330d27
KP
569 printf (" %g", bestscore[i]);
570 FcPatternPrint (best);
571 }
572 if (!best)
573 {
574 *result = FcResultNoMatch;
575 return 0;
576 }
216fac98 577 return FcFontRenderPrepare (config, p, best);
24330d27 578}
80c053b7
KP
579
580FcPattern *
581FcFontMatch (FcConfig *config,
582 FcPattern *p,
583 FcResult *result)
584{
585 FcFontSet *sets[2];
586 int nsets;
587
588 if (!config)
589 {
590 config = FcConfigGetCurrent ();
591 if (!config)
592 return 0;
593 }
594 nsets = 0;
595 if (config->fonts[FcSetSystem])
596 sets[nsets++] = config->fonts[FcSetSystem];
597 if (config->fonts[FcSetApplication])
598 sets[nsets++] = config->fonts[FcSetApplication];
599 return FcFontSetMatch (config, sets, nsets, p, result);
600}
216fac98 601
216fac98 602typedef struct _FcSortNode {
216fac98 603 FcPattern *pattern;
4c003605 604 double score[NUM_MATCH_VALUES];
216fac98
KP
605} FcSortNode;
606
0ab36ca8
KP
607static int
608FcSortCompare (const void *aa, const void *ab)
216fac98 609{
0ab36ca8
KP
610 FcSortNode *a = *(FcSortNode **) aa;
611 FcSortNode *b = *(FcSortNode **) ab;
bc9469ba
KP
612 double *as = &a->score[0];
613 double *bs = &b->score[0];
88c747e2 614 double ad = 0, bd = 0;
0ab36ca8 615 int i;
216fac98 616
4c003605 617 i = NUM_MATCH_VALUES;
bc9469ba
KP
618 while (i-- && (ad = *as++) == (bd = *bs++))
619 ;
620 return ad < bd ? -1 : ad > bd ? 1 : 0;
216fac98
KP
621}
622
623static FcBool
0ab36ca8 624FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
216fac98
KP
625{
626 FcCharSet *ncs;
0ab36ca8
KP
627 FcSortNode *node;
628
629 while (nnode--)
216fac98 630 {
0ab36ca8
KP
631 node = *n++;
632 if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) ==
633 FcResultMatch)
216fac98 634 {
1412a699
KP
635 /*
636 * If this font isn't a subset of the previous fonts,
637 * add it to the list
638 */
639 if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
216fac98 640 {
0ab36ca8
KP
641 if (*cs)
642 {
643 ncs = FcCharSetUnion (ncs, *cs);
644 if (!ncs)
645 return FcFalse;
646 FcCharSetDestroy (*cs);
647 }
648 else
649 ncs = FcCharSetCopy (ncs);
650 *cs = ncs;
6f6563ed 651 FcPatternReference (node->pattern);
82f4243f
KP
652 if (FcDebug () & FC_DBG_MATCH)
653 {
654 printf ("Add ");
655 FcPatternPrint (node->pattern);
656 }
0ab36ca8 657 if (!FcFontSetAdd (fs, node->pattern))
6f6563ed
KP
658 {
659 FcPatternDestroy (node->pattern);
216fac98 660 return FcFalse;
6f6563ed 661 }
216fac98 662 }
216fac98
KP
663 }
664 }
216fac98
KP
665 return FcTrue;
666}
667
1412a699
KP
668void
669FcFontSetSortDestroy (FcFontSet *fs)
670{
1412a699
KP
671 FcFontSetDestroy (fs);
672}
673
216fac98
KP
674FcFontSet *
675FcFontSetSort (FcConfig *config,
676 FcFontSet **sets,
677 int nsets,
678 FcPattern *p,
679 FcBool trim,
680 FcCharSet **csp,
681 FcResult *result)
682{
683 FcFontSet *ret;
684 FcFontSet *s;
685 FcSortNode *nodes;
0ab36ca8 686 FcSortNode **nodeps, **nodep;
216fac98 687 int nnodes;
216fac98
KP
688 FcSortNode *new;
689 FcCharSet *cs;
690 int set;
691 int f;
692 int i;
5cf8c536
KP
693 int nPatternLang;
694 FcBool *patternLangSat;
695 FcValue patternLang;
216fac98 696
82f4243f
KP
697 if (FcDebug () & FC_DBG_MATCH)
698 {
699 printf ("Sort ");
700 FcPatternPrint (p);
701 }
216fac98
KP
702 nnodes = 0;
703 for (set = 0; set < nsets; set++)
704 {
705 s = sets[set];
706 if (!s)
707 continue;
708 nnodes += s->nfont;
709 }
710 if (!nnodes)
711 goto bail0;
5cf8c536
KP
712
713 for (nPatternLang = 0;
714 FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
715 nPatternLang++)
716 ;
717
9dac3c59 718 /* freed below */
5cf8c536
KP
719 nodes = malloc (nnodes * sizeof (FcSortNode) +
720 nnodes * sizeof (FcSortNode *) +
721 nPatternLang * sizeof (FcBool));
216fac98
KP
722 if (!nodes)
723 goto bail0;
1412a699 724 nodeps = (FcSortNode **) (nodes + nnodes);
5cf8c536 725 patternLangSat = (FcBool *) (nodeps + nnodes);
216fac98 726
216fac98 727 new = nodes;
0ab36ca8 728 nodep = nodeps;
216fac98
KP
729 for (set = 0; set < nsets; set++)
730 {
731 s = sets[set];
732 if (!s)
733 continue;
734 for (f = 0; f < s->nfont; f++)
735 {
736 if (FcDebug () & FC_DBG_MATCHV)
737 {
738 printf ("Font %d ", f);
739 FcPatternPrint (s->fonts[f]);
740 }
741 new->pattern = s->fonts[f];
742 if (!FcCompare (p, new->pattern, new->score, result))
743 goto bail1;
744 if (FcDebug () & FC_DBG_MATCHV)
745 {
746 printf ("Score");
4c003605 747 for (i = 0; i < NUM_MATCH_VALUES; i++)
216fac98
KP
748 {
749 printf (" %g", new->score[i]);
750 }
751 printf ("\n");
752 }
0ab36ca8 753 *nodep = new;
216fac98 754 new++;
0ab36ca8 755 nodep++;
216fac98
KP
756 }
757 }
758
0ab36ca8
KP
759 nnodes = new - nodes;
760
1412a699 761 qsort (nodeps, nnodes, sizeof (FcSortNode *),
0ab36ca8 762 FcSortCompare);
5cf8c536
KP
763
764 for (i = 0; i < nPatternLang; i++)
765 patternLangSat[i] = FcFalse;
766
767 for (f = 0; f < nnodes; f++)
768 {
769 FcBool satisfies = FcFalse;
770 /*
771 * If this node matches any language, go check
772 * which ones and satisfy those entries
773 */
774 if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
775 {
776 for (i = 0; i < nPatternLang; i++)
777 {
778 FcValue nodeLang;
779
780 if (!patternLangSat[i] &&
781 FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
782 FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
783 {
9ab79bdf 784 double compare = FcCompareLang (&patternLang, &nodeLang);
5cf8c536
KP
785 if (compare >= 0 && compare < 2)
786 {
787 if (FcDebug () & FC_DBG_MATCHV)
788 {
789 FcChar8 *family;
790 FcChar8 *style;
791
792 if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
793 FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
794 printf ("Font %s:%s matches language %d\n", family, style, i);
795 }
796 patternLangSat[i] = FcTrue;
797 satisfies = FcTrue;
798 break;
799 }
800 }
801 }
802 }
803 if (!satisfies)
804 nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
805 }
806
807 /*
808 * Re-sort once the language issues have been settled
809 */
810 qsort (nodeps, nnodes, sizeof (FcSortNode *),
811 FcSortCompare);
0ab36ca8 812
216fac98
KP
813 ret = FcFontSetCreate ();
814 if (!ret)
815 goto bail1;
816
817 cs = 0;
818
0ab36ca8 819 if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
216fac98
KP
820 goto bail2;
821
d0f07b8d
KP
822 if (csp)
823 *csp = cs;
824 else
825 FcCharSetDestroy (cs);
216fac98 826
1412a699
KP
827 free (nodes);
828
216fac98
KP
829 return ret;
830
831bail2:
832 if (cs)
833 FcCharSetDestroy (cs);
834 FcFontSetDestroy (ret);
835bail1:
836 free (nodes);
837bail0:
838 return 0;
839}
20ac65ab
KP
840
841FcFontSet *
842FcFontSort (FcConfig *config,
843 FcPattern *p,
844 FcBool trim,
845 FcCharSet **csp,
846 FcResult *result)
847{
848 FcFontSet *sets[2];
849 int nsets;
850
851 if (!config)
852 {
853 config = FcConfigGetCurrent ();
854 if (!config)
855 return 0;
856 }
857 nsets = 0;
858 if (config->fonts[FcSetSystem])
859 sets[nsets++] = config->fonts[FcSetSystem];
860 if (config->fonts[FcSetApplication])
861 sets[nsets++] = config->fonts[FcSetApplication];
862 return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
863}