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