Coverage Report

Created: 2026-06-30 11:14

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