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