Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/fontconfig/src/fcmatch.c
Line
Count
Source
1
/*
2
 * fontconfig/src/fcmatch.c
3
 *
4
 * Copyright © 2000 Keith Packard
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 the author(s) not be used in
11
 * advertising or publicity pertaining to distribution of the software without
12
 * specific, written prior permission.  The authors make 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
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
 * EVENT SHALL THE AUTHOR(S) 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 "fcint.h"
26
27
#include <locale.h>
28
29
static double
30
FcCompareNumber (const FcValue *value1, const FcValue *value2, FcValue *bestValue)
31
86
{
32
86
    double v1, v2, v;
33
34
86
    switch ((int)value1->type) {
35
86
    case FcTypeInteger:
36
86
  v1 = (double)value1->u.i;
37
86
  break;
38
0
    case FcTypeDouble:
39
0
  v1 = value1->u.d;
40
0
  break;
41
0
    default:
42
0
  return -1.0;
43
86
    }
44
86
    switch ((int)value2->type) {
45
86
    case FcTypeInteger:
46
86
  v2 = (double)value2->u.i;
47
86
  break;
48
0
    case FcTypeDouble:
49
0
  v2 = value2->u.d;
50
0
  break;
51
0
    default:
52
0
  return -1.0;
53
86
    }
54
86
    v = v2 - v1;
55
86
    if (v < 0)
56
26
  v = -v;
57
86
    *bestValue = FcValueCanonicalize (value2);
58
86
    return v;
59
86
}
60
61
static double
62
FcCompareString (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
63
0
{
64
0
    *bestValue = FcValueCanonicalize (v2);
65
0
    return (double)FcStrCmpIgnoreCase (FcValueString (v1), FcValueString (v2)) != 0;
66
0
}
67
68
static double
69
FcCompareFamily (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
70
0
{
71
    /* rely on the guarantee in FcPatternObjectAddWithBinding that
72
     * families are always FcTypeString. */
73
0
    const FcChar8 *v1_string = FcValueString (v1);
74
0
    const FcChar8 *v2_string = FcValueString (v2);
75
76
0
    *bestValue = FcValueCanonicalize (v2);
77
78
0
    if (FcToLower (*v1_string) != FcToLower (*v2_string) &&
79
0
        *v1_string != ' ' && *v2_string != ' ')
80
0
  return 1.0;
81
82
0
    return (double)FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
83
0
}
84
85
static double
86
FcComparePostScript (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
87
0
{
88
0
    const FcChar8 *v1_string = FcValueString (v1);
89
0
    const FcChar8 *v2_string = FcValueString (v2);
90
0
    int            n;
91
0
    size_t         len1, len2, mlen;
92
93
0
    *bestValue = FcValueCanonicalize (v2);
94
95
0
    if (FcToLower (*v1_string) != FcToLower (*v2_string) &&
96
0
        *v1_string != ' ' && *v2_string != ' ')
97
0
  return 1.0;
98
99
0
    n = FcStrMatchIgnoreCaseAndDelims (v1_string, v2_string, (const FcChar8 *)" -,");
100
0
    len1 = strlen ((const char *)v1_string);
101
0
    len2 = strlen ((const char *)v2_string);
102
0
    mlen = FC_MAX (len1, len2);
103
104
0
    return (double)(mlen - n) / (double)mlen;
105
0
}
106
107
static double
108
FcCompareLang (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
109
32
{
110
32
    FcLangResult result;
111
112
32
    switch ((int)v1->type) {
113
0
    case FcTypeLangSet:
114
0
  switch ((int)v2->type) {
115
0
  case FcTypeLangSet:
116
0
      result = FcLangSetCompare (FcValueLangSet (v1), FcValueLangSet (v2));
117
0
      break;
118
0
  case FcTypeString:
119
0
      result = FcLangSetHasLang (FcValueLangSet (v1), FcValueString (v2));
120
0
      break;
121
0
  default:
122
0
      return -1.0;
123
0
  }
124
0
  break;
125
32
    case FcTypeString:
126
32
  switch ((int)v2->type) {
127
26
  case FcTypeLangSet:
128
26
      result = FcLangSetHasLang (FcValueLangSet (v2), FcValueString (v1));
129
26
      break;
130
6
  case FcTypeString:
131
6
      result = FcLangCompare (FcValueString (v1), FcValueString (v2));
132
6
      break;
133
0
  default:
134
0
      return -1.0;
135
32
  }
136
32
  break;
137
32
    default:
138
0
  return -1.0;
139
32
    }
140
32
    *bestValue = FcValueCanonicalize (v2);
141
32
    switch (result) {
142
32
    case FcLangEqual:
143
32
  return 0;
144
0
    case FcLangDifferentCountry:
145
0
  return 1;
146
0
    case FcLangDifferentLang:
147
0
    default:
148
0
  return 2;
149
32
    }
150
32
}
151
152
static double
153
FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
154
78
{
155
78
    if (v2->type != FcTypeBool || v1->type != FcTypeBool)
156
0
  return -1.0;
157
158
78
    bestValue->type = FcTypeBool;
159
78
    if (v2->u.b != FcDontCare)
160
78
  bestValue->u.b = v2->u.b;
161
0
    else
162
0
  bestValue->u.b = v1->u.b;
163
164
78
    return (double)((v2->u.b ^ v1->u.b) == 1);
165
78
}
166
167
static double
168
FcCompareEqual (const FcValue *value1, const FcValue *value2, FcValue *bestValue)
169
0
{
170
0
    double v1, v2, v;
171
172
0
    switch ((int)value1->type) {
173
0
    case FcTypeInteger:
174
0
  v1 = (double)value1->u.i;
175
0
  break;
176
0
    case FcTypeDouble:
177
0
  v1 = value1->u.d;
178
0
  break;
179
0
    case FcTypeBool:
180
0
  return FcCompareBool (value1, value2, bestValue);
181
0
    default:
182
0
  return -1.0;
183
0
    }
184
0
    switch ((int)value2->type) {
185
0
    case FcTypeInteger:
186
0
  v2 = (double)value2->u.i;
187
0
  break;
188
0
    case FcTypeDouble:
189
0
  v2 = value2->u.d;
190
0
  break;
191
0
    case FcTypeBool:
192
0
  return FcCompareBool (value1, value2, bestValue);
193
0
    default:
194
0
  return -1.0;
195
0
    }
196
0
    v = !(v1 == v2);
197
0
    *bestValue = FcValueCanonicalize (value2);
198
199
0
    return v;
200
0
}
201
202
static double
203
FcCompareCharSet (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
204
0
{
205
0
    *bestValue = FcValueCanonicalize (v2); /* TODO Improve. */
206
0
    return (double)FcCharSetSubtractCount (FcValueCharSet (v1), FcValueCharSet (v2));
207
0
}
208
209
static double
210
FcCompareRange (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
211
52
{
212
52
    FcValue value1 = FcValueCanonicalize (v1);
213
52
    FcValue value2 = FcValueCanonicalize (v2);
214
52
    double  b1, e1, b2, e2, d;
215
216
52
    switch ((int)value1.type) {
217
52
    case FcTypeInteger:
218
52
  b1 = e1 = value1.u.i;
219
52
  break;
220
0
    case FcTypeDouble:
221
0
  b1 = e1 = value1.u.d;
222
0
  break;
223
0
    case FcTypeRange:
224
0
  b1 = value1.u.r->begin;
225
0
  e1 = value1.u.r->end;
226
0
  break;
227
0
    default:
228
0
  return -1;
229
52
    }
230
52
    switch ((int)value2.type) {
231
0
    case FcTypeInteger:
232
0
  b2 = e2 = value2.u.i;
233
0
  break;
234
52
    case FcTypeDouble:
235
52
  b2 = e2 = value2.u.d;
236
52
  break;
237
0
    case FcTypeRange:
238
0
  b2 = value2.u.r->begin;
239
0
  e2 = value2.u.r->end;
240
0
  break;
241
0
    default:
242
0
  return -1;
243
52
    }
244
245
52
    if (e1 < b2)
246
12
  d = b2;
247
40
    else if (e2 < b1)
248
0
  d = e2;
249
40
    else
250
40
  d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5;
251
252
52
    bestValue->type = FcTypeDouble;
253
52
    bestValue->u.d = d;
254
255
    /* If the ranges overlap, it's a match, otherwise return closest distance. */
256
52
    if (e1 < b2 || e2 < b1)
257
12
  return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
258
40
    else
259
40
  return 0.0;
260
52
}
261
262
static double
263
FcCompareSize (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
264
0
{
265
0
    FcValue value1 = FcValueCanonicalize (v1);
266
0
    FcValue value2 = FcValueCanonicalize (v2);
267
0
    double  b1, e1, b2, e2;
268
269
0
    switch ((int)value1.type) {
270
0
    case FcTypeInteger:
271
0
  b1 = e1 = value1.u.i;
272
0
  break;
273
0
    case FcTypeDouble:
274
0
  b1 = e1 = value1.u.d;
275
0
  break;
276
0
    case FcTypeRange:
277
0
  b1 = value1.u.r->begin;
278
0
  e1 = value1.u.r->end;
279
0
  break;
280
0
    default:
281
0
  return -1;
282
0
    }
283
0
    switch ((int)value2.type) {
284
0
    case FcTypeInteger:
285
0
  b2 = e2 = value2.u.i;
286
0
  break;
287
0
    case FcTypeDouble:
288
0
  b2 = e2 = value2.u.d;
289
0
  break;
290
0
    case FcTypeRange:
291
0
  b2 = value2.u.r->begin;
292
0
  e2 = value2.u.r->end;
293
0
  break;
294
0
    default:
295
0
  return -1;
296
0
    }
297
298
0
    bestValue->type = FcTypeDouble;
299
0
    bestValue->u.d = (b1 + e1) * .5;
300
301
    /* If the ranges overlap, it's a match, otherwise return closest distance. */
302
0
    if (e1 < b2 || e2 < b1)
303
0
  return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
304
0
    if (b2 != e2 && b1 == e2) /* Semi-closed interval. */
305
0
  return 1e-15;
306
0
    else
307
0
  return 0.0;
308
0
}
309
310
static double
311
FcCompareFilename (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
312
0
{
313
0
    const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2);
314
0
    *bestValue = FcValueCanonicalize (v2);
315
0
    if (FcStrCmp (s1, s2) == 0)
316
0
  return 0.0;
317
0
    else if (FcStrCmpIgnoreCase (s1, s2) == 0)
318
0
  return 1.0;
319
0
    else if (FcStrGlobMatch (s1, s2))
320
0
  return 2.0;
321
0
    else
322
0
  return 3.0;
323
0
}
324
325
/* Define priorities to -1 for objects that don't have a compare function. */
326
327
#define PRI_NULL(n)        \
328
    PRI_##n##_STRONG = -1, \
329
    PRI_##n##_WEAK = -1,
330
#define PRI1(n)
331
#define PRI_FcCompareFamily(n)     PRI1 (n)
332
#define PRI_FcCompareString(n)     PRI1 (n)
333
#define PRI_FcCompareNumber(n)     PRI1 (n)
334
#define PRI_FcCompareEqual(n)      PRI1 (n)
335
#define PRI_FcCompareBool(n)       PRI1 (n)
336
#define PRI_FcCompareFilename(n)   PRI1 (n)
337
#define PRI_FcCompareCharSet(n)    PRI1 (n)
338
#define PRI_FcCompareLang(n)       PRI1 (n)
339
#define PRI_FcComparePostScript(n) PRI1 (n)
340
#define PRI_FcCompareRange(n)      PRI1 (n)
341
#define PRI_FcCompareSize(n)       PRI1 (n)
342
343
#define FC_OBJECT(NAME, Type, Cmp) PRI_##Cmp (NAME)
344
345
typedef enum _FcMatcherPriorityDummy {
346
#include "fcobjs.h"
347
} FcMatcherPriorityDummy;
348
349
#undef FC_OBJECT
350
351
/* Canonical match priority order. */
352
353
#undef PRI1
354
#define PRI1(n)                     \
355
    PRI_##n,                        \
356
  PRI_##n##_STRONG = PRI_##n, \
357
  PRI_##n##_WEAK = PRI_##n
358
359
typedef enum _FcMatcherPriority {
360
    PRI1 (FILE),
361
    PRI1 (FONT_WRAPPER),
362
    PRI1 (FONTFORMAT),
363
    PRI1 (VARIABLE),
364
    PRI1 (NAMED_INSTANCE),
365
    PRI1 (SCALABLE),
366
    PRI1 (COLOR),
367
    PRI1 (FOUNDRY),
368
    PRI1 (CHARSET),
369
    PRI_FAMILY_STRONG,
370
    PRI1 (GENERIC_FAMILY),
371
    PRI_POSTSCRIPT_NAME_STRONG,
372
    PRI1 (LANG),
373
    PRI_FAMILY_WEAK,
374
    PRI_POSTSCRIPT_NAME_WEAK,
375
    PRI1 (SYMBOL),
376
    PRI1 (SPACING),
377
    PRI1 (SIZE),
378
    PRI1 (PIXEL_SIZE),
379
    PRI1 (STYLE),
380
    PRI1 (SLANT),
381
    PRI1 (WEIGHT),
382
    PRI1 (WIDTH),
383
    PRI1 (FONT_HAS_HINT),
384
    PRI1 (DECORATIVE),
385
    PRI1 (ANTIALIAS),
386
    PRI1 (RASTERIZER),
387
    PRI1 (OUTLINE),
388
    PRI1 (ORDER),
389
    PRI1 (FONTVERSION),
390
    PRI_END
391
} FcMatcherPriority;
392
393
#undef PRI1
394
395
typedef struct _FcMatcher {
396
    FcObject object;
397
    double (*compare) (const FcValue *v1, const FcValue *v2, FcValue *bestValue);
398
    int strong, weak;
399
} FcMatcher;
400
401
/*
402
 * Order is significant, it defines the precedence of
403
 * each value, earlier values are more significant than
404
 * later values
405
 */
406
#define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME##_OBJECT, Cmp, PRI_##NAME##_STRONG, PRI_##NAME##_WEAK },
407
static const FcMatcher _FcMatchers[] = {
408
    { FC_INVALID_OBJECT, NULL, -1, -1 },
409
#include "fcobjs.h"
410
};
411
#undef FC_OBJECT
412
413
static const FcMatcher *
414
FcObjectToMatcher (FcObject object,
415
                   FcBool   include_lang)
416
378
{
417
378
    if (include_lang) {
418
6
  switch (object) {
419
2
  case FC_FAMILYLANG_OBJECT:
420
4
  case FC_STYLELANG_OBJECT:
421
6
  case FC_FULLNAMELANG_OBJECT:
422
6
      object = FC_LANG_OBJECT;
423
6
      break;
424
6
  }
425
6
    }
426
378
    if (object > FC_MAX_BASE_OBJECT ||
427
378
        !_FcMatchers[object].compare ||
428
294
        _FcMatchers[object].strong == -1 ||
429
294
        _FcMatchers[object].weak == -1)
430
84
  return NULL;
431
432
294
    return _FcMatchers + object;
433
378
}
434
435
static FcBool
436
FcCompareValueList (FcObject         object,
437
                    const FcMatcher *match,
438
                    FcValueListPtr   v1orig, /* pattern */
439
                    FcValueListPtr   v2orig, /* target */
440
                    FcValue         *bestValue,
441
                    double          *value,
442
                    int             *n,
443
                    FcResult        *result)
444
320
{
445
320
    FcValueListPtr v1, v2;
446
320
    double         v, best, bestStrong, bestWeak;
447
320
    int            j, k, pos = 0;
448
320
    int            weak, strong;
449
450
320
    if (!match) {
451
72
  if (bestValue)
452
0
      *bestValue = FcValueCanonicalize (&v2orig->value);
453
72
  if (n)
454
0
      *n = 0;
455
72
  return FcTrue;
456
72
    }
457
458
248
    weak = match->weak;
459
248
    strong = match->strong;
460
461
248
    best = 1e99;
462
248
    bestStrong = 1e99;
463
248
    bestWeak = 1e99;
464
306
    for (v1 = v1orig, j = 0; v1; v1 = FcValueListNext (v1), j++) {
465
306
  for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext (v2), k++) {
466
248
      FcValue matchValue;
467
248
      v = (match->compare) (&v1->value, &v2->value, &matchValue);
468
248
      if (v < 0) {
469
0
    *result = FcResultTypeMismatch;
470
0
    return FcFalse;
471
0
      }
472
248
      v = v * 1000 + j * 100 + k * (v2->value.type == FcTypeString ? 1 : 0);
473
248
      if (v < best) {
474
248
    if (bestValue)
475
18
        *bestValue = matchValue;
476
248
    best = v;
477
248
    pos = k;
478
248
      }
479
248
      if (weak == strong) {
480
    /* found the best possible match */
481
248
    if (best < 1000)
482
190
        goto done;
483
248
      } else if (v1->binding == FcValueBindingStrong) {
484
0
    if (v < bestStrong)
485
0
        bestStrong = v;
486
0
      } else {
487
0
    if (v < bestWeak)
488
0
        bestWeak = v;
489
0
      }
490
248
  }
491
248
    }
492
248
done:
493
248
    if (FcDebug() & FC_DBG_MATCHV) {
494
0
  printf (" %s: %g ", FcObjectName (object), best);
495
0
  FcValueListPrint (v1orig);
496
0
  printf (", ");
497
0
  FcValueListPrint (v2orig);
498
0
  printf ("\n");
499
0
    }
500
248
    if (value) {
501
224
  if (weak == strong)
502
224
      value[strong] += best;
503
0
  else {
504
0
      value[weak] += bestWeak;
505
0
      value[strong] += bestStrong;
506
0
  }
507
224
    }
508
248
    if (n)
509
6
  *n = pos;
510
511
248
    return FcTrue;
512
248
}
513
514
/* The bulk of the time in FcFontMatch and FcFontSort goes to
515
 * walking long lists of family names. We speed this up with a
516
 * hash table.
517
 */
518
typedef struct
519
{
520
    double strong_value;
521
    double weak_value;
522
} FamilyEntry;
523
524
typedef struct
525
{
526
    FcHashTable *family_hash;
527
} FcCompareData;
528
529
static void
530
FcCompareDataClear (FcCompareData *data)
531
2
{
532
2
    FcHashTableDestroy (data->family_hash);
533
2
}
534
535
static void
536
FcCompareDataInit (FcPattern     *pat,
537
                   FcCompareData *data)
538
2
{
539
2
    FcHashTable   *table;
540
2
    FcPatternElt  *elt;
541
2
    FcValueListPtr l;
542
2
    int            i;
543
2
    const void    *key;
544
2
    FamilyEntry   *e;
545
546
2
    table = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
547
2
                               (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
548
2
                               NULL,
549
2
                               NULL,
550
2
                               NULL,
551
2
                               free);
552
553
2
    elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
554
2
    if (elt) {
555
4
  for (l = FcPatternEltValues (elt), i = 0; l; l = FcValueListNext (l), i++) {
556
2
      key = FcValueString (&l->value);
557
2
      if (!FcHashTableFind (table, key, (void **)&e)) {
558
2
    e = malloc (sizeof (FamilyEntry));
559
2
    e->strong_value = 1e99;
560
2
    e->weak_value = 1e99;
561
2
    FcHashTableAdd (table, (void *)key, e);
562
2
      }
563
2
      if (l->binding == FcValueBindingWeak) {
564
0
    if (i < e->weak_value)
565
0
        e->weak_value = i;
566
2
      } else {
567
2
    if (i < e->strong_value)
568
2
        e->strong_value = i;
569
2
      }
570
2
  }
571
2
    }
572
573
2
    data->family_hash = table;
574
2
}
575
576
static FcBool
577
FcCompareFamilies (FcPattern     *pat,
578
                   FcValueListPtr v1orig,
579
                   FcPattern     *fnt,
580
                   FcValueListPtr v2orig,
581
                   double        *value,
582
                   FcResult      *result,
583
                   FcHashTable   *table)
584
24
{
585
24
    FcValueListPtr v2;
586
24
    double         strong_value;
587
24
    double         weak_value;
588
24
    const void    *key;
589
24
    FamilyEntry   *e;
590
591
24
    assert (table != NULL);
592
593
24
    strong_value = 1e99;
594
24
    weak_value = 1e99;
595
596
48
    for (v2 = v2orig; v2; v2 = FcValueListNext (v2)) {
597
24
  key = FcValueString (&v2->value);
598
24
  if (FcHashTableFind (table, key, (void **)&e)) {
599
8
      if (e->strong_value < strong_value)
600
8
    strong_value = e->strong_value;
601
8
      if (e->weak_value < weak_value)
602
0
    weak_value = e->weak_value;
603
8
  }
604
24
    }
605
24
    if (FcDebug() & FC_DBG_MATCHV) {
606
0
  printf ("%s: %g (%g) ", FcObjectName (FC_FAMILY_OBJECT), strong_value, weak_value);
607
0
  FcValueListPrint (v1orig);
608
0
  printf (", ");
609
0
  FcValueListPrint (v2orig);
610
0
  printf ("\n");
611
0
    }
612
613
24
    value[PRI_FAMILY_STRONG] = strong_value;
614
24
    value[PRI_FAMILY_WEAK] = weak_value;
615
616
24
    return FcTrue;
617
24
}
618
619
/*
620
 * Return a value indicating the distance between the two lists of
621
 * values
622
 */
623
624
static FcBool
625
FcCompare (FcPattern     *pat,
626
           FcPattern     *fnt,
627
           double        *value,
628
           FcResult      *result,
629
           FcCompareData *data)
630
24
{
631
24
    int i, i1, i2;
632
633
744
    for (i = 0; i < PRI_END; i++)
634
720
  value[i] = 0.0;
635
636
24
    i1 = 0;
637
24
    i2 = 0;
638
960
    while (i1 < pat->num && i2 < fnt->num) {
639
936
  FcPatternElt *elt_i1 = &FcPatternElts (pat)[i1];
640
936
  FcPatternElt *elt_i2 = &FcPatternElts (fnt)[i2];
641
642
936
  i = FcObjectCompare (elt_i1->object, elt_i2->object);
643
936
  if (i > 0)
644
312
      i2++;
645
624
  else if (i < 0)
646
304
      i1++;
647
320
  else if (elt_i1->object == FC_FAMILY_OBJECT && data->family_hash) {
648
24
      if (!FcCompareFamilies (pat, FcPatternEltValues (elt_i1),
649
24
                              fnt, FcPatternEltValues (elt_i2),
650
24
                              value, result,
651
24
                              data->family_hash))
652
0
    return FcFalse;
653
24
      i1++;
654
24
      i2++;
655
296
  } else {
656
296
      const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse);
657
296
      if (!FcCompareValueList (elt_i1->object, match,
658
296
                               FcPatternEltValues (elt_i1),
659
296
                               FcPatternEltValues (elt_i2),
660
296
                               NULL, value, NULL, result))
661
0
    return FcFalse;
662
296
      i1++;
663
296
      i2++;
664
296
  }
665
936
    }
666
24
    return FcTrue;
667
24
}
668
669
FcPattern *
670
FcFontRenderPrepare (FcConfig  *config,
671
                     FcPattern *pat,
672
                     FcPattern *font)
673
2
{
674
2
    FcPattern    *newp;
675
2
    int           i;
676
2
    FcPatternElt *fe, *pe;
677
2
    FcValue       v;
678
2
    FcResult      result;
679
2
    FcBool        variable = FcFalse;
680
2
    FcStrBuf      variations;
681
682
2
    assert (pat != NULL);
683
2
    assert (font != NULL);
684
685
2
    FcPatternObjectGetBool (font, FC_VARIABLE_OBJECT, 0, &variable);
686
2
    assert (variable != FcDontCare);
687
2
    if (variable)
688
0
  FcStrBufInit (&variations, NULL, 0);
689
690
2
    newp = FcPatternCreate();
691
2
    if (!newp)
692
0
  return NULL;
693
60
    for (i = 0; i < font->num; i++) {
694
58
  fe = &FcPatternElts (font)[i];
695
58
  if (fe->object == FC_FAMILYLANG_OBJECT ||
696
56
      fe->object == FC_STYLELANG_OBJECT ||
697
54
      fe->object == FC_FULLNAMELANG_OBJECT) {
698
      /* ignore those objects. we need to deal with them
699
       * another way */
700
6
      continue;
701
6
  }
702
52
  if (fe->object == FC_FAMILY_OBJECT ||
703
50
      fe->object == FC_STYLE_OBJECT ||
704
48
      fe->object == FC_FULLNAME_OBJECT) {
705
6
      FcPatternElt *fel, *pel;
706
707
6
      FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT);
708
6
      FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT);
709
6
      FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT);
710
711
6
      fel = FcPatternObjectFindElt (font, fe->object + 1);
712
6
      pel = FcPatternObjectFindElt (pat, fe->object + 1);
713
714
6
      if (fel && pel) {
715
    /* The font has name languages, and pattern asks for specific language(s).
716
     * Match on language and and prefer that result.
717
     * Note:  Currently the code only give priority to first matching language.
718
     */
719
6
    int              n = 1, j;
720
6
    FcValueListPtr   l1, l2, ln = NULL, ll = NULL;
721
6
    const FcMatcher *match = FcObjectToMatcher (pel->object, FcTrue);
722
723
6
    if (!FcCompareValueList (pel->object, match,
724
6
                             FcPatternEltValues (pel),
725
6
                             FcPatternEltValues (fel), NULL, NULL, &n, &result)) {
726
0
        FcPatternDestroy (newp);
727
0
        return NULL;
728
0
    }
729
730
6
    for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel);
731
12
         l1 != NULL || l2 != NULL;
732
6
         j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL) {
733
6
        FcValueListPtr (*func) (FcValueListPtr, FcValue, FcValueBinding);
734
6
        FcValueBinding binding = FcValueBindingEnd;
735
736
6
        if (j == n) {
737
6
      binding = FcValueBindingStrong;
738
6
      func = FcValueListPrepend;
739
6
        } else
740
0
      func = FcValueListAppend;
741
6
        if (l1) {
742
6
      ln = func (ln,
743
6
                 FcValueCanonicalize (&l1->value),
744
6
                 l1->binding);
745
6
        }
746
6
        if (l2) {
747
6
      if (binding == FcValueBindingEnd)
748
0
          binding = l2->binding;
749
6
      ll = func (ll,
750
6
                 FcValueCanonicalize (&l2->value),
751
6
                 binding);
752
6
        }
753
6
    }
754
6
    FcPatternObjectListAdd (newp, fe->object, ln, FcFalse);
755
6
    FcPatternObjectListAdd (newp, fel->object, ll, FcFalse);
756
757
6
    continue;
758
6
      } else if (fel) {
759
    /* Pattern doesn't ask for specific language.  Copy all for name and
760
     * lang. */
761
0
    FcValueListPtr l1, l2;
762
763
0
    l1 = FcValueListDuplicate (FcPatternEltValues (fe));
764
0
    l2 = FcValueListDuplicate (FcPatternEltValues (fel));
765
0
    FcPatternObjectListAdd (newp, fe->object, l1, FcFalse);
766
0
    FcPatternObjectListAdd (newp, fel->object, l2, FcFalse);
767
768
0
    continue;
769
0
      }
770
6
  }
771
772
46
  pe = FcPatternObjectFindElt (pat, fe->object);
773
46
  if (pe) {
774
18
      const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse);
775
18
      if (!FcCompareValueList (pe->object, match,
776
18
                               FcPatternEltValues (pe),
777
18
                               FcPatternEltValues (fe), &v, NULL, NULL, &result)) {
778
0
    FcPatternDestroy (newp);
779
0
    return NULL;
780
0
      }
781
18
      FcPatternObjectAdd (newp, fe->object, v, FcFalse);
782
783
      /* Set font-variations settings for standard axes in variable fonts. */
784
18
      if (variable &&
785
0
          FcPatternEltValues (fe)->value.type == FcTypeRange &&
786
0
          (fe->object == FC_WEIGHT_OBJECT ||
787
0
           fe->object == FC_WIDTH_OBJECT ||
788
0
           fe->object == FC_SIZE_OBJECT)) {
789
0
    double      num;
790
0
    const char *tag = "    ";
791
792
0
    assert (v.type == FcTypeDouble);
793
0
    num = v.u.d;
794
0
    if (variations.len)
795
0
        FcStrBufChar (&variations, ',');
796
0
    switch (fe->object) {
797
0
    case FC_WEIGHT_OBJECT:
798
0
        tag = "wght";
799
0
        num = FcWeightToOpenType (num);
800
0
        break;
801
802
0
    case FC_WIDTH_OBJECT:
803
0
        tag = "wdth";
804
0
        break;
805
806
0
    case FC_SIZE_OBJECT:
807
0
        tag = "opsz";
808
0
        break;
809
0
    }
810
0
    FcStrBufFormat (&variations, "%4s=%g", tag, num);
811
0
      }
812
28
  } else {
813
28
      FcPatternObjectListAdd (newp, fe->object,
814
28
                              FcValueListDuplicate (FcPatternEltValues (fe)),
815
28
                              FcTrue);
816
28
  }
817
46
    }
818
54
    for (i = 0; i < pat->num; i++) {
819
52
  pe = &FcPatternElts (pat)[i];
820
52
  fe = FcPatternObjectFindElt (font, pe->object);
821
52
  if (!fe &&
822
26
      pe->object != FC_FAMILYLANG_OBJECT &&
823
26
      pe->object != FC_STYLELANG_OBJECT &&
824
26
      pe->object != FC_FULLNAMELANG_OBJECT) {
825
26
      FcPatternObjectListAdd (newp, pe->object,
826
26
                              FcValueListDuplicate (FcPatternEltValues (pe)),
827
26
                              FcFalse);
828
26
  }
829
52
    }
830
831
2
    if (variable && variations.len) {
832
0
  FcChar8 *vars = NULL;
833
0
  if (FcPatternObjectGetString (newp, FC_FONT_VARIATIONS_OBJECT, 0, &vars) == FcResultMatch) {
834
0
      FcStrBufChar (&variations, ',');
835
0
      FcStrBufString (&variations, vars);
836
0
      FcPatternObjectDel (newp, FC_FONT_VARIATIONS_OBJECT);
837
0
  }
838
839
0
  FcPatternObjectAddString (newp, FC_FONT_VARIATIONS_OBJECT, FcStrBufDoneStatic (&variations));
840
0
  FcStrBufDestroy (&variations);
841
0
    }
842
843
2
    FcConfigSubstituteWithPat (config, newp, pat, FcMatchFont);
844
2
    return newp;
845
2
}
846
847
static FcPattern *
848
FcFontSetMatchInternal (FcFontSet **sets,
849
                        int         nsets,
850
                        FcPattern  *p,
851
                        FcResult   *result)
852
2
{
853
2
    double              score[PRI_END], bestscore[PRI_END];
854
2
    int                 f;
855
2
    FcFontSet          *s;
856
2
    FcPattern          *best, *pat = NULL;
857
2
    int                 i;
858
2
    int                 set;
859
2
    FcCompareData       data;
860
2
    const FcPatternElt *elt;
861
862
62
    for (i = 0; i < PRI_END; i++)
863
60
  bestscore[i] = 0;
864
2
    best = 0;
865
2
    if (FcDebug() & FC_DBG_MATCH) {
866
0
  printf ("Match ");
867
0
  FcPatternPrint (p);
868
0
    }
869
870
2
    FcCompareDataInit (p, &data);
871
872
4
    for (set = 0; set < nsets; set++) {
873
2
  s = sets[set];
874
2
  if (!s)
875
0
      continue;
876
26
  for (f = 0; f < s->nfont; f++) {
877
24
      if (FcDebug() & FC_DBG_MATCHV) {
878
0
    printf ("Font %d ", f);
879
0
    FcPatternPrint (s->fonts[f]);
880
0
      }
881
24
      if (!FcCompare (p, s->fonts[f], score, result, &data)) {
882
0
    FcCompareDataClear (&data);
883
0
    return 0;
884
0
      }
885
24
      if (FcDebug() & FC_DBG_MATCHV) {
886
0
    printf ("Score");
887
0
    for (i = 0; i < PRI_END; i++) {
888
0
        printf (" %g", score[i]);
889
0
    }
890
0
    printf ("\n");
891
0
      }
892
358
      for (i = 0; i < PRI_END; i++) {
893
358
    if (best && bestscore[i] < score[i])
894
16
        break;
895
342
    if (!best || score[i] < bestscore[i]) {
896
248
        for (i = 0; i < PRI_END; i++)
897
240
      bestscore[i] = score[i];
898
8
        best = s->fonts[f];
899
8
        break;
900
8
    }
901
342
      }
902
24
  }
903
2
    }
904
905
2
    FcCompareDataClear (&data);
906
907
    /* Update the binding according to the score to indicate how exactly values matches on. */
908
2
    if (best) {
909
2
  pat = FcPatternCreate();
910
2
  elt = FcPatternElts (best);
911
60
  for (i = 0; i < FcPatternObjectCount (best); i++) {
912
58
      const FcMatcher *match = FcObjectToMatcher (elt[i].object, FcFalse);
913
58
      FcValueListPtr   l = FcPatternEltValues (&elt[i]);
914
915
58
      if (!match)
916
12
    FcPatternObjectListAdd (pat, elt[i].object,
917
12
                            FcValueListDuplicate (l), FcTrue);
918
46
      else {
919
46
    FcValueBinding binding = FcValueBindingWeak;
920
46
    FcValueListPtr newp = NULL, ll, t = NULL;
921
46
    FcValue        v;
922
923
    /* If the value was matched exactly, update the binding to Strong. */
924
46
    if (bestscore[match->strong] < 1000)
925
44
        binding = FcValueBindingStrong;
926
927
92
    for (ll = l; ll != NULL; ll = FcValueListNext (ll)) {
928
46
        if (!newp) {
929
46
      t = newp = FcValueListCreate();
930
46
        } else {
931
0
      t->next = FcValueListCreate();
932
0
      t = FcValueListNext (t);
933
0
        }
934
46
        v = FcValueCanonicalize (&ll->value);
935
46
        t->value = FcValueSave (v);
936
46
        t->binding = binding;
937
46
        t->next = NULL;
938
46
    }
939
46
    FcPatternObjectListAdd (pat, elt[i].object, newp, FcTrue);
940
46
      }
941
58
  }
942
2
    }
943
2
    if (FcDebug() & FC_DBG_MATCH) {
944
0
  printf ("Best score");
945
0
  for (i = 0; i < PRI_END; i++)
946
0
      printf (" %g", bestscore[i]);
947
0
  printf ("\n");
948
0
  FcPatternPrint (pat);
949
0
    }
950
2
    if (FcDebug() & FC_DBG_MATCH2) {
951
0
  char        *env = getenv ("FC_DBG_MATCH_FILTER");
952
0
  FcObjectSet *os = NULL;
953
954
0
  if (env) {
955
0
      char  *ss, *s;
956
0
      char  *p;
957
0
      FcBool f = FcTrue;
958
959
0
      ss = s = (char *)FcStrCopy ((const FcChar8 *)env);
960
0
      os = FcObjectSetCreate();
961
0
      while (f) {
962
0
    size_t len;
963
0
    char  *x;
964
965
0
    if (!(p = strchr (s, ','))) {
966
0
        f = FcFalse;
967
0
        len = strlen (s);
968
0
    } else {
969
0
        len = (p - s);
970
0
    }
971
0
    x = malloc (sizeof (char) * (len + 1));
972
0
    if (x) {
973
0
        strcpy (x, s);
974
0
        if (FcObjectFromName (x) > 0)
975
0
      FcObjectSetAdd (os, x);
976
0
        s = p + 1;
977
0
        free (x);
978
0
    }
979
0
      }
980
0
      free (ss);
981
0
  }
982
0
  FcPatternPrint2 (p, pat, os);
983
0
  if (os)
984
0
      FcObjectSetDestroy (os);
985
0
    }
986
    /* assuming that 'result' is initialized with FcResultNoMatch
987
     * outside this function */
988
2
    if (pat)
989
2
  *result = FcResultMatch;
990
991
2
    return pat;
992
2
}
993
994
FcPattern *
995
FcFontSetMatch (FcConfig   *config,
996
                FcFontSet **sets,
997
                int         nsets,
998
                FcPattern  *p,
999
                FcResult   *result)
1000
2
{
1001
2
    FcPattern *best, *ret = NULL;
1002
1003
2
    assert (sets != NULL);
1004
2
    assert (p != NULL);
1005
2
    assert (result != NULL);
1006
1007
2
    *result = FcResultNoMatch;
1008
1009
2
    config = FcConfigReference (config);
1010
2
    if (!config)
1011
0
  return NULL;
1012
2
    best = FcFontSetMatchInternal (sets, nsets, p, result);
1013
2
    if (best) {
1014
2
  ret = FcFontRenderPrepare (config, p, best);
1015
2
  FcPatternDestroy (best);
1016
2
    }
1017
1018
2
    FcConfigDestroy (config);
1019
1020
2
    return ret;
1021
2
}
1022
1023
FcPattern *
1024
FcFontMatch (FcConfig  *config,
1025
             FcPattern *p,
1026
             FcResult  *result)
1027
0
{
1028
0
    FcFontSet *sets[2];
1029
0
    int        nsets;
1030
0
    FcPattern *best, *ret = NULL;
1031
1032
0
    assert (p != NULL);
1033
0
    assert (result != NULL);
1034
1035
0
    *result = FcResultNoMatch;
1036
1037
0
    config = FcConfigReference (config);
1038
0
    if (!config)
1039
0
  return NULL;
1040
0
    nsets = 0;
1041
0
    if (config->fonts[FcSetSystem])
1042
0
  sets[nsets++] = config->fonts[FcSetSystem];
1043
0
    if (config->fonts[FcSetApplication])
1044
0
  sets[nsets++] = config->fonts[FcSetApplication];
1045
1046
0
    best = FcFontSetMatchInternal (sets, nsets, p, result);
1047
0
    if (best) {
1048
0
  ret = FcFontRenderPrepare (config, p, best);
1049
0
  FcPatternDestroy (best);
1050
0
    }
1051
1052
0
    FcConfigDestroy (config);
1053
1054
0
    return ret;
1055
0
}
1056
1057
typedef struct _FcSortNode {
1058
    FcPattern *pattern;
1059
    double     score[PRI_END];
1060
} FcSortNode;
1061
1062
static int
1063
FcSortCompare (const void *aa, const void *ab)
1064
0
{
1065
0
    FcSortNode *a = *(FcSortNode **)aa;
1066
0
    FcSortNode *b = *(FcSortNode **)ab;
1067
0
    double     *as = &a->score[0];
1068
0
    double     *bs = &b->score[0];
1069
0
    double      ad = 0, bd = 0;
1070
0
    int         i;
1071
1072
0
    i = PRI_END;
1073
0
    while (i-- && (ad = *as++) == (bd = *bs++))
1074
0
  ;
1075
0
    return ad < bd ? -1 : ad > bd ? 1
1076
0
                                  : 0;
1077
0
}
1078
1079
static FcBool
1080
FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
1081
0
{
1082
0
    FcBool     ret = FcFalse;
1083
0
    FcCharSet *cs;
1084
0
    int        i;
1085
1086
0
    cs = 0;
1087
0
    if (trim || csp) {
1088
0
  cs = FcCharSetCreate();
1089
0
  if (cs == NULL)
1090
0
      goto bail;
1091
0
    }
1092
1093
0
    for (i = 0; i < nnode; i++) {
1094
0
  FcSortNode *node = *n++;
1095
0
  FcBool      adds_chars = FcFalse;
1096
1097
  /*
1098
   * Only fetch node charset if we'd need it
1099
   */
1100
0
  if (cs) {
1101
0
      FcCharSet *ncs;
1102
1103
0
      if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
1104
0
          FcResultMatch)
1105
0
    continue;
1106
1107
0
      if (!FcCharSetMerge (cs, ncs, &adds_chars))
1108
0
    goto bail;
1109
0
  }
1110
1111
  /*
1112
   * If this font isn't a subset of the previous fonts,
1113
   * add it to the list
1114
   */
1115
0
  if (!i || !trim || adds_chars) {
1116
0
      FcPatternReference (node->pattern);
1117
0
      if (FcDebug() & FC_DBG_MATCHV) {
1118
0
    printf ("Add ");
1119
0
    FcPatternPrint (node->pattern);
1120
0
      }
1121
0
      if (!FcFontSetAdd (fs, node->pattern)) {
1122
0
    FcPatternDestroy (node->pattern);
1123
0
    goto bail;
1124
0
      }
1125
0
  }
1126
0
    }
1127
0
    if (csp) {
1128
0
  *csp = cs;
1129
0
  cs = 0;
1130
0
    }
1131
1132
0
    ret = FcTrue;
1133
1134
0
bail:
1135
0
    if (cs)
1136
0
  FcCharSetDestroy (cs);
1137
1138
0
    return ret;
1139
0
}
1140
1141
void
1142
FcFontSetSortDestroy (FcFontSet *fs)
1143
0
{
1144
0
    FcFontSetDestroy (fs);
1145
0
}
1146
1147
FcFontSet *
1148
FcFontSetSort (FcConfig   *config,
1149
               FcFontSet **sets,
1150
               int         nsets,
1151
               FcPattern  *p,
1152
               FcBool      trim,
1153
               FcCharSet **csp,
1154
               FcResult   *result)
1155
0
{
1156
0
    FcFontSet    *ret;
1157
0
    FcFontSet    *s;
1158
0
    FcSortNode   *nodes;
1159
0
    FcSortNode  **nodeps, **nodep;
1160
0
    int           nnodes;
1161
0
    FcSortNode   *newp;
1162
0
    int           set;
1163
0
    int           f;
1164
0
    int           i;
1165
0
    int           nPatternLang;
1166
0
    FcBool       *patternLangSat;
1167
0
    FcValue       patternLang;
1168
0
    FcCompareData data;
1169
1170
0
    assert (sets != NULL);
1171
0
    assert (p != NULL);
1172
0
    assert (result != NULL);
1173
1174
    /* There are some implementation that relying on the result of
1175
     * "result" to check if the return value of FcFontSetSort
1176
     * is valid or not.
1177
     * So we should initialize it to the conservative way since
1178
     * this function doesn't return NULL anymore.
1179
     */
1180
0
    if (result)
1181
0
  *result = FcResultNoMatch;
1182
1183
0
    if (FcDebug() & FC_DBG_MATCH) {
1184
0
  printf ("Sort ");
1185
0
  FcPatternPrint (p);
1186
0
    }
1187
0
    nnodes = 0;
1188
0
    for (set = 0; set < nsets; set++) {
1189
0
  s = sets[set];
1190
0
  if (!s)
1191
0
      continue;
1192
0
  nnodes += s->nfont;
1193
0
    }
1194
0
    if (!nnodes)
1195
0
  return FcFontSetCreate();
1196
1197
0
    if (!config)
1198
0
  config = FcConfigGetCurrent();
1199
0
    FcConfigReference (config);
1200
1201
0
    for (nPatternLang = 0;
1202
0
         FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
1203
0
         nPatternLang++)
1204
0
  ;
1205
1206
    /* freed below */
1207
0
    nodes = malloc (nnodes * sizeof (FcSortNode) +
1208
0
                    nnodes * sizeof (FcSortNode *) +
1209
0
                    nPatternLang * sizeof (FcBool));
1210
0
    if (!nodes)
1211
0
  goto bail0;
1212
0
    nodeps = (FcSortNode **)(nodes + nnodes);
1213
0
    patternLangSat = (FcBool *)(nodeps + nnodes);
1214
1215
0
    FcCompareDataInit (p, &data);
1216
1217
0
    newp = nodes;
1218
0
    nodep = nodeps;
1219
0
    for (set = 0; set < nsets; set++) {
1220
0
  s = sets[set];
1221
0
  if (!s)
1222
0
      continue;
1223
0
  for (f = 0; f < s->nfont; f++) {
1224
0
      if (FcDebug() & FC_DBG_MATCHV) {
1225
0
    printf ("Font %d ", f);
1226
0
    FcPatternPrint (s->fonts[f]);
1227
0
      }
1228
0
      newp->pattern = s->fonts[f];
1229
0
      if (!FcCompare (p, newp->pattern, newp->score, result, &data))
1230
0
    goto bail1;
1231
      /* TODO: Should we check a FcPattern in FcFontSet?
1232
       * This way may not work if someone has own list of application fonts
1233
       * That said, just to reduce the cost for lookup so far.
1234
       */
1235
0
      if (config->prefer_app_fonts && s != config->fonts[FcSetApplication]) {
1236
0
    newp->score[PRI_ORDER] += 1000;
1237
0
      }
1238
0
      if (FcDebug() & FC_DBG_MATCHV) {
1239
0
    printf ("Score");
1240
0
    for (i = 0; i < PRI_END; i++) {
1241
0
        printf (" %g", newp->score[i]);
1242
0
    }
1243
0
    printf ("\n");
1244
0
      }
1245
0
      *nodep = newp;
1246
0
      newp++;
1247
0
      nodep++;
1248
0
  }
1249
0
    }
1250
1251
0
    FcCompareDataClear (&data);
1252
1253
0
    nnodes = newp - nodes;
1254
1255
0
    qsort (nodeps, nnodes, sizeof (FcSortNode *),
1256
0
           FcSortCompare);
1257
1258
0
    for (i = 0; i < nPatternLang; i++)
1259
0
  patternLangSat[i] = FcFalse;
1260
1261
0
    for (f = 0; f < nnodes; f++) {
1262
0
  FcBool satisfies = FcFalse;
1263
  /*
1264
   * If this node matches any language, go check
1265
   * which ones and satisfy those entries
1266
   */
1267
0
  if (nodeps[f]->score[PRI_LANG] < 2000) {
1268
0
      for (i = 0; i < nPatternLang; i++) {
1269
0
    FcValue nodeLang;
1270
1271
0
    if (!patternLangSat[i] &&
1272
0
        FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
1273
0
        FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch) {
1274
0
        FcValue matchValue;
1275
0
        double  compare = FcCompareLang (&patternLang, &nodeLang, &matchValue);
1276
0
        if (compare >= 0 && compare < 2) {
1277
0
      if (FcDebug() & FC_DBG_MATCHV) {
1278
0
          FcChar8 *family;
1279
0
          FcChar8 *style;
1280
1281
0
          if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
1282
0
              FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
1283
0
        printf ("Font %s:%s matches language %d\n", family, style, i);
1284
0
      }
1285
0
      patternLangSat[i] = FcTrue;
1286
0
      satisfies = FcTrue;
1287
0
      break;
1288
0
        }
1289
0
    }
1290
0
      }
1291
0
  }
1292
0
  if (!satisfies) {
1293
0
      nodeps[f]->score[PRI_LANG] = 10000.0;
1294
0
  }
1295
0
    }
1296
1297
    /*
1298
     * Re-sort once the language issues have been settled
1299
     */
1300
0
    qsort (nodeps, nnodes, sizeof (FcSortNode *),
1301
0
           FcSortCompare);
1302
1303
0
    ret = FcFontSetCreate();
1304
0
    if (!ret)
1305
0
  goto bail1;
1306
1307
0
    if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
1308
0
  goto bail2;
1309
1310
0
    free (nodes);
1311
1312
0
    if (ret->nfont > 0) {
1313
0
  *result = FcResultMatch;
1314
0
  if (FcDebug() & FC_DBG_MATCH) {
1315
0
      printf ("First font ");
1316
0
      FcPatternPrint (ret->fonts[0]);
1317
0
  }
1318
0
    }
1319
0
    if (config)
1320
0
  FcConfigDestroy (config);
1321
1322
0
    return ret;
1323
1324
0
bail2:
1325
0
    FcFontSetDestroy (ret);
1326
0
bail1:
1327
0
    free (nodes);
1328
0
bail0:
1329
0
    if (config)
1330
0
  FcConfigDestroy (config);
1331
0
    return 0;
1332
0
}
1333
1334
FcFontSet *
1335
FcFontSort (FcConfig   *config,
1336
            FcPattern  *p,
1337
            FcBool      trim,
1338
            FcCharSet **csp,
1339
            FcResult   *result)
1340
0
{
1341
0
    FcFontSet *sets[2], *ret;
1342
0
    int        nsets;
1343
1344
0
    assert (p != NULL);
1345
0
    assert (result != NULL);
1346
1347
0
    *result = FcResultNoMatch;
1348
1349
0
    config = FcConfigReference (config);
1350
0
    if (!config)
1351
0
  return NULL;
1352
0
    nsets = 0;
1353
0
    if (config->fonts[FcSetSystem])
1354
0
  sets[nsets++] = config->fonts[FcSetSystem];
1355
0
    if (config->fonts[FcSetApplication])
1356
0
  sets[nsets++] = config->fonts[FcSetApplication];
1357
0
    ret = FcFontSetSort (config, sets, nsets, p, trim, csp, result);
1358
0
    FcConfigDestroy (config);
1359
1360
0
    return ret;
1361
0
}
1362
#define __fcmatch__
1363
#include "fcaliastail.h"
1364
#undef __fcmatch__