Coverage Report

Created: 2026-08-14 10:22

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
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
1.71k
{
212
1.71k
    FcValue value1 = FcValueCanonicalize (v1);
213
1.71k
    FcValue value2 = FcValueCanonicalize (v2);
214
1.71k
    double  b1, e1, b2, e2, d;
215
216
1.71k
    switch ((int)value1.type) {
217
1.71k
    case FcTypeInteger:
218
1.71k
  b1 = e1 = value1.u.i;
219
1.71k
  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
1.71k
    }
230
1.71k
    switch ((int)value2.type) {
231
0
    case FcTypeInteger:
232
0
  b2 = e2 = value2.u.i;
233
0
  break;
234
1.71k
    case FcTypeDouble:
235
1.71k
  b2 = e2 = value2.u.d;
236
1.71k
  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
1.71k
    }
244
245
1.71k
    if (e1 < b2)
246
210
  d = b2;
247
1.50k
    else if (e2 < b1)
248
186
  d = e2;
249
1.32k
    else
250
1.32k
  d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5;
251
252
1.71k
    bestValue->type = FcTypeDouble;
253
1.71k
    bestValue->u.d = d;
254
255
    /* If the ranges overlap, it's a match, otherwise return closest distance. */
256
1.71k
    if (e1 < b2 || e2 < b1)
257
396
  return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
258
1.32k
    else
259
1.32k
  return 0.0;
260
1.71k
}
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
12.4k
{
417
12.4k
    if (include_lang) {
418
198
  switch (object) {
419
66
  case FC_FAMILYLANG_OBJECT:
420
132
  case FC_STYLELANG_OBJECT:
421
198
  case FC_FULLNAMELANG_OBJECT:
422
198
      object = FC_LANG_OBJECT;
423
198
      break;
424
198
  }
425
198
    }
426
12.4k
    if (object > FC_MAX_BASE_OBJECT ||
427
12.4k
        !_FcMatchers[object].compare ||
428
9.70k
        _FcMatchers[object].strong == -1 ||
429
9.70k
        _FcMatchers[object].weak == -1)
430
2.77k
  return NULL;
431
432
9.70k
    return _FcMatchers + object;
433
12.4k
}
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
10.5k
{
445
10.5k
    FcValueListPtr v1, v2;
446
10.5k
    double         v, best, bestStrong, bestWeak;
447
10.5k
    int            j, k, pos = 0;
448
10.5k
    int            weak, strong;
449
450
10.5k
    if (!match) {
451
2.37k
  if (bestValue)
452
0
      *bestValue = FcValueCanonicalize (&v2orig->value);
453
2.37k
  if (n)
454
0
      *n = 0;
455
2.37k
  return FcTrue;
456
2.37k
    }
457
458
8.18k
    weak = match->weak;
459
8.18k
    strong = match->strong;
460
461
8.18k
    best = 1e99;
462
8.18k
    bestStrong = 1e99;
463
8.18k
    bestWeak = 1e99;
464
10.0k
    for (v1 = v1orig, j = 0; v1; v1 = FcValueListNext (v1), j++) {
465
10.0k
  for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext (v2), k++) {
466
8.18k
      FcValue matchValue;
467
8.18k
      v = (match->compare) (&v1->value, &v2->value, &matchValue);
468
8.18k
      if (v < 0) {
469
0
    *result = FcResultTypeMismatch;
470
0
    return FcFalse;
471
0
      }
472
8.18k
      v = v * 1000 + j * 100 + k * (v2->value.type == FcTypeString ? 1 : 0);
473
8.18k
      if (v < best) {
474
8.18k
    if (bestValue)
475
594
        *bestValue = matchValue;
476
8.18k
    best = v;
477
8.18k
    pos = k;
478
8.18k
      }
479
8.18k
      if (weak == strong) {
480
    /* found the best possible match */
481
8.18k
    if (best < 1000)
482
6.27k
        goto done;
483
8.18k
      } 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
8.18k
  }
491
8.18k
    }
492
8.18k
done:
493
8.18k
    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
8.18k
    if (value) {
501
7.39k
  if (weak == strong)
502
7.39k
      value[strong] += best;
503
0
  else {
504
0
      value[weak] += bestWeak;
505
0
      value[strong] += bestStrong;
506
0
  }
507
7.39k
    }
508
8.18k
    if (n)
509
198
  *n = pos;
510
511
8.18k
    return FcTrue;
512
8.18k
}
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
66
{
532
66
    FcHashTableDestroy (data->family_hash);
533
66
}
534
535
static void
536
FcCompareDataInit (FcPattern     *pat,
537
                   FcCompareData *data)
538
66
{
539
66
    FcHashTable   *table;
540
66
    FcPatternElt  *elt;
541
66
    FcValueListPtr l;
542
66
    int            i;
543
66
    const void    *key;
544
66
    FamilyEntry   *e;
545
546
66
    table = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
547
66
                               (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
548
66
                               NULL,
549
66
                               NULL,
550
66
                               NULL,
551
66
                               free);
552
553
66
    elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
554
66
    if (elt) {
555
132
  for (l = FcPatternEltValues (elt), i = 0; l; l = FcValueListNext (l), i++) {
556
66
      key = FcValueString (&l->value);
557
66
      if (!FcHashTableFind (table, key, (void **)&e)) {
558
66
    e = malloc (sizeof (FamilyEntry));
559
66
    e->strong_value = 1e99;
560
66
    e->weak_value = 1e99;
561
66
    FcHashTableAdd (table, (void *)key, e);
562
66
      }
563
66
      if (l->binding == FcValueBindingWeak) {
564
0
    if (i < e->weak_value)
565
0
        e->weak_value = i;
566
66
      } else {
567
66
    if (i < e->strong_value)
568
66
        e->strong_value = i;
569
66
      }
570
66
  }
571
66
    }
572
573
66
    data->family_hash = table;
574
66
}
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
792
{
585
792
    FcValueListPtr v2;
586
792
    double         strong_value;
587
792
    double         weak_value;
588
792
    const void    *key;
589
792
    FamilyEntry   *e;
590
591
792
    assert (table != NULL);
592
593
792
    strong_value = 1e99;
594
792
    weak_value = 1e99;
595
596
1.58k
    for (v2 = v2orig; v2; v2 = FcValueListNext (v2)) {
597
792
  key = FcValueString (&v2->value);
598
792
  if (FcHashTableFind (table, key, (void **)&e)) {
599
264
      if (e->strong_value < strong_value)
600
264
    strong_value = e->strong_value;
601
264
      if (e->weak_value < weak_value)
602
0
    weak_value = e->weak_value;
603
264
  }
604
792
    }
605
792
    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
792
    value[PRI_FAMILY_STRONG] = strong_value;
614
792
    value[PRI_FAMILY_WEAK] = weak_value;
615
616
792
    return FcTrue;
617
792
}
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
792
{
631
792
    int i, i1, i2;
632
633
24.5k
    for (i = 0; i < PRI_END; i++)
634
23.7k
  value[i] = 0.0;
635
636
792
    i1 = 0;
637
792
    i2 = 0;
638
31.6k
    while (i1 < pat->num && i2 < fnt->num) {
639
30.8k
  FcPatternElt *elt_i1 = &FcPatternElts (pat)[i1];
640
30.8k
  FcPatternElt *elt_i2 = &FcPatternElts (fnt)[i2];
641
642
30.8k
  i = FcObjectCompare (elt_i1->object, elt_i2->object);
643
30.8k
  if (i > 0)
644
10.2k
      i2++;
645
20.5k
  else if (i < 0)
646
10.0k
      i1++;
647
10.5k
  else if (elt_i1->object == FC_FAMILY_OBJECT && data->family_hash) {
648
792
      if (!FcCompareFamilies (pat, FcPatternEltValues (elt_i1),
649
792
                              fnt, FcPatternEltValues (elt_i2),
650
792
                              value, result,
651
792
                              data->family_hash))
652
0
    return FcFalse;
653
792
      i1++;
654
792
      i2++;
655
9.76k
  } else {
656
9.76k
      const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse);
657
9.76k
      if (!FcCompareValueList (elt_i1->object, match,
658
9.76k
                               FcPatternEltValues (elt_i1),
659
9.76k
                               FcPatternEltValues (elt_i2),
660
9.76k
                               NULL, value, NULL, result))
661
0
    return FcFalse;
662
9.76k
      i1++;
663
9.76k
      i2++;
664
9.76k
  }
665
30.8k
    }
666
792
    return FcTrue;
667
792
}
668
669
FcPattern *
670
FcFontRenderPrepare (FcConfig  *config,
671
                     FcPattern *pat,
672
                     FcPattern *font)
673
66
{
674
66
    FcPattern    *newp;
675
66
    int           i;
676
66
    FcPatternElt *fe, *pe;
677
66
    FcValue       v;
678
66
    FcResult      result;
679
66
    FcBool        variable = FcFalse;
680
66
    FcStrBuf      variations;
681
682
66
    assert (pat != NULL);
683
66
    assert (font != NULL);
684
685
66
    FcPatternObjectGetBool (font, FC_VARIABLE_OBJECT, 0, &variable);
686
66
    assert (variable != FcDontCare);
687
66
    if (variable)
688
0
  FcStrBufInit (&variations, NULL, 0);
689
690
66
    newp = FcPatternCreate();
691
66
    if (!newp)
692
0
  return NULL;
693
1.98k
    for (i = 0; i < font->num; i++) {
694
1.91k
  fe = &FcPatternElts (font)[i];
695
1.91k
  if (fe->object == FC_FAMILYLANG_OBJECT ||
696
1.84k
      fe->object == FC_STYLELANG_OBJECT ||
697
1.78k
      fe->object == FC_FULLNAMELANG_OBJECT) {
698
      /* ignore those objects. we need to deal with them
699
       * another way */
700
198
      continue;
701
198
  }
702
1.71k
  if (fe->object == FC_FAMILY_OBJECT ||
703
1.65k
      fe->object == FC_STYLE_OBJECT ||
704
1.58k
      fe->object == FC_FULLNAME_OBJECT) {
705
198
      FcPatternElt *fel, *pel;
706
707
198
      FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT);
708
198
      FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT);
709
198
      FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT);
710
711
198
      fel = FcPatternObjectFindElt (font, fe->object + 1);
712
198
      pel = FcPatternObjectFindElt (pat, fe->object + 1);
713
714
198
      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
198
    int              n = 1, j;
720
198
    FcValueListPtr   l1, l2, ln = NULL, ll = NULL;
721
198
    const FcMatcher *match = FcObjectToMatcher (pel->object, FcTrue);
722
723
198
    if (!FcCompareValueList (pel->object, match,
724
198
                             FcPatternEltValues (pel),
725
198
                             FcPatternEltValues (fel), NULL, NULL, &n, &result)) {
726
0
        FcPatternDestroy (newp);
727
0
        return NULL;
728
0
    }
729
730
198
    for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel);
731
396
         l1 != NULL || l2 != NULL;
732
198
         j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL) {
733
198
        FcValueListPtr (*func) (FcValueListPtr, FcValue, FcValueBinding);
734
198
        FcValueBinding binding = FcValueBindingEnd;
735
736
198
        if (j == n) {
737
198
      binding = FcValueBindingStrong;
738
198
      func = FcValueListPrepend;
739
198
        } else
740
0
      func = FcValueListAppend;
741
198
        if (l1) {
742
198
      ln = func (ln,
743
198
                 FcValueCanonicalize (&l1->value),
744
198
                 l1->binding);
745
198
        }
746
198
        if (l2) {
747
198
      if (binding == FcValueBindingEnd)
748
0
          binding = l2->binding;
749
198
      ll = func (ll,
750
198
                 FcValueCanonicalize (&l2->value),
751
198
                 binding);
752
198
        }
753
198
    }
754
198
    FcPatternObjectListAdd (newp, fe->object, ln, FcFalse);
755
198
    FcPatternObjectListAdd (newp, fel->object, ll, FcFalse);
756
757
198
    continue;
758
198
      } 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
198
  }
771
772
1.51k
  pe = FcPatternObjectFindElt (pat, fe->object);
773
1.51k
  if (pe) {
774
594
      const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse);
775
594
      if (!FcCompareValueList (pe->object, match,
776
594
                               FcPatternEltValues (pe),
777
594
                               FcPatternEltValues (fe), &v, NULL, NULL, &result)) {
778
0
    FcPatternDestroy (newp);
779
0
    return NULL;
780
0
      }
781
594
      FcPatternObjectAdd (newp, fe->object, v, FcFalse);
782
783
      /* Set font-variations settings for standard axes in variable fonts. */
784
594
      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
924
  } else {
813
924
      FcPatternObjectListAdd (newp, fe->object,
814
924
                              FcValueListDuplicate (FcPatternEltValues (fe)),
815
924
                              FcTrue);
816
924
  }
817
1.51k
    }
818
1.78k
    for (i = 0; i < pat->num; i++) {
819
1.71k
  pe = &FcPatternElts (pat)[i];
820
1.71k
  fe = FcPatternObjectFindElt (font, pe->object);
821
1.71k
  if (!fe &&
822
858
      pe->object != FC_FAMILYLANG_OBJECT &&
823
858
      pe->object != FC_STYLELANG_OBJECT &&
824
858
      pe->object != FC_FULLNAMELANG_OBJECT) {
825
858
      FcPatternObjectListAdd (newp, pe->object,
826
858
                              FcValueListDuplicate (FcPatternEltValues (pe)),
827
858
                              FcFalse);
828
858
  }
829
1.71k
    }
830
831
66
    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
66
    FcConfigSubstituteWithPat (config, newp, pat, FcMatchFont);
844
66
    return newp;
845
66
}
846
847
static FcPattern *
848
FcFontSetMatchInternal (FcFontSet **sets,
849
                        int         nsets,
850
                        FcPattern  *p,
851
                        FcResult   *result)
852
66
{
853
66
    double              score[PRI_END], bestscore[PRI_END];
854
66
    int                 f;
855
66
    FcFontSet          *s;
856
66
    FcPattern          *best, *pat = NULL;
857
66
    int                 i;
858
66
    int                 set;
859
66
    FcCompareData       data;
860
66
    const FcPatternElt *elt;
861
862
2.04k
    for (i = 0; i < PRI_END; i++)
863
1.98k
  bestscore[i] = 0;
864
66
    best = 0;
865
66
    if (FcDebug() & FC_DBG_MATCH) {
866
0
  printf ("Match ");
867
0
  FcPatternPrint (p);
868
0
    }
869
870
66
    FcCompareDataInit (p, &data);
871
872
132
    for (set = 0; set < nsets; set++) {
873
66
  s = sets[set];
874
66
  if (!s)
875
0
      continue;
876
858
  for (f = 0; f < s->nfont; f++) {
877
792
      if (FcDebug() & FC_DBG_MATCHV) {
878
0
    printf ("Font %d ", f);
879
0
    FcPatternPrint (s->fonts[f]);
880
0
      }
881
792
      if (!FcCompare (p, s->fonts[f], score, result, &data)) {
882
0
    FcCompareDataClear (&data);
883
0
    return 0;
884
0
      }
885
792
      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
11.8k
      for (i = 0; i < PRI_END; i++) {
893
11.8k
    if (best && bestscore[i] < score[i])
894
522
        break;
895
11.2k
    if (!best || score[i] < bestscore[i]) {
896
8.37k
        for (i = 0; i < PRI_END; i++)
897
8.10k
      bestscore[i] = score[i];
898
270
        best = s->fonts[f];
899
270
        break;
900
270
    }
901
11.2k
      }
902
792
  }
903
66
    }
904
905
66
    FcCompareDataClear (&data);
906
907
    /* Update the binding according to the score to indicate how exactly values matches on. */
908
66
    if (best) {
909
66
  pat = FcPatternCreate();
910
66
  elt = FcPatternElts (best);
911
1.98k
  for (i = 0; i < FcPatternObjectCount (best); i++) {
912
1.91k
      const FcMatcher *match = FcObjectToMatcher (elt[i].object, FcFalse);
913
1.91k
      FcValueListPtr   l = FcPatternEltValues (&elt[i]);
914
915
1.91k
      if (!match)
916
396
    FcPatternObjectListAdd (pat, elt[i].object,
917
396
                            FcValueListDuplicate (l), FcTrue);
918
1.51k
      else {
919
1.51k
    FcValueBinding binding = FcValueBindingWeak;
920
1.51k
    FcValueListPtr newp = NULL, ll, t = NULL;
921
1.51k
    FcValue        v;
922
923
    /* If the value was matched exactly, update the binding to Strong. */
924
1.51k
    if (bestscore[match->strong] < 1000)
925
1.45k
        binding = FcValueBindingStrong;
926
927
3.03k
    for (ll = l; ll != NULL; ll = FcValueListNext (ll)) {
928
1.51k
        if (!newp) {
929
1.51k
      t = newp = FcValueListCreate();
930
1.51k
        } else {
931
0
      t->next = FcValueListCreate();
932
0
      t = FcValueListNext (t);
933
0
        }
934
1.51k
        v = FcValueCanonicalize (&ll->value);
935
1.51k
        t->value = FcValueSave (v);
936
1.51k
        t->binding = binding;
937
1.51k
        t->next = NULL;
938
1.51k
    }
939
1.51k
    FcPatternObjectListAdd (pat, elt[i].object, newp, FcTrue);
940
1.51k
      }
941
1.91k
  }
942
66
    }
943
66
    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
66
    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
66
    if (pat)
989
66
  *result = FcResultMatch;
990
991
66
    return pat;
992
66
}
993
994
FcPattern *
995
FcFontSetMatch (FcConfig   *config,
996
                FcFontSet **sets,
997
                int         nsets,
998
                FcPattern  *p,
999
                FcResult   *result)
1000
66
{
1001
66
    FcPattern *best, *ret = NULL;
1002
1003
66
    assert (sets != NULL);
1004
66
    assert (p != NULL);
1005
66
    assert (result != NULL);
1006
1007
66
    *result = FcResultNoMatch;
1008
1009
66
    config = FcConfigReference (config);
1010
66
    if (!config)
1011
0
  return NULL;
1012
66
    best = FcFontSetMatchInternal (sets, nsets, p, result);
1013
66
    if (best) {
1014
66
  ret = FcFontRenderPrepare (config, p, best);
1015
66
  FcPatternDestroy (best);
1016
66
    }
1017
1018
66
    FcConfigDestroy (config);
1019
1020
66
    return ret;
1021
66
}
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__