Coverage Report

Created: 2025-07-07 10:01

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