Coverage Report

Created: 2026-10-14 08:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/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
7.11M
{
32
7.11M
    double v1, v2, v;
33
34
7.11M
    switch ((int)value1->type) {
35
7.11M
    case FcTypeInteger:
36
7.11M
  v1 = (double)value1->u.i;
37
7.11M
  break;
38
0
    case FcTypeDouble:
39
0
  v1 = value1->u.d;
40
0
  break;
41
0
    default:
42
0
  return -1.0;
43
7.11M
    }
44
7.11M
    switch ((int)value2->type) {
45
7.11M
    case FcTypeInteger:
46
7.11M
  v2 = (double)value2->u.i;
47
7.11M
  break;
48
0
    case FcTypeDouble:
49
0
  v2 = value2->u.d;
50
0
  break;
51
0
    default:
52
0
  return -1.0;
53
7.11M
    }
54
7.11M
    v = v2 - v1;
55
7.11M
    if (v < 0)
56
2.46M
  v = -v;
57
7.11M
    *bestValue = FcValueCanonicalize (value2);
58
7.11M
    return v;
59
7.11M
}
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
7.19M
{
110
7.19M
    FcLangResult result;
111
112
7.19M
    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
7.19M
    case FcTypeString:
126
7.19M
  switch ((int)v2->type) {
127
7.19M
  case FcTypeLangSet:
128
7.19M
      result = FcLangSetHasLang (FcValueLangSet (v2), FcValueString (v1));
129
7.19M
      break;
130
9
  case FcTypeString:
131
9
      result = FcLangCompare (FcValueString (v1), FcValueString (v2));
132
9
      break;
133
0
  default:
134
0
      return -1.0;
135
7.19M
  }
136
7.19M
  break;
137
7.19M
    default:
138
0
  return -1.0;
139
7.19M
    }
140
7.19M
    *bestValue = FcValueCanonicalize (v2);
141
7.19M
    switch (result) {
142
2.47M
    case FcLangEqual:
143
2.47M
  return 0;
144
0
    case FcLangDifferentCountry:
145
0
  return 1;
146
4.72M
    case FcLangDifferentLang:
147
4.72M
    default:
148
4.72M
  return 2;
149
7.19M
    }
150
7.19M
}
151
152
static double
153
FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
154
7.08M
{
155
7.08M
    if (v2->type != FcTypeBool || v1->type != FcTypeBool)
156
0
  return -1.0;
157
158
7.08M
    bestValue->type = FcTypeBool;
159
7.08M
    if (v2->u.b != FcDontCare)
160
7.08M
  bestValue->u.b = v2->u.b;
161
0
    else
162
0
  bestValue->u.b = v1->u.b;
163
164
7.08M
    return (double)((v2->u.b ^ v1->u.b) == 1);
165
7.08M
}
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
4.72M
{
212
4.72M
    FcValue value1 = FcValueCanonicalize (v1);
213
4.72M
    FcValue value2 = FcValueCanonicalize (v2);
214
4.72M
    double  b1, e1, b2, e2, d;
215
216
4.72M
    switch ((int)value1.type) {
217
4.72M
    case FcTypeInteger:
218
4.72M
  b1 = e1 = value1.u.i;
219
4.72M
  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
4.72M
    }
230
4.72M
    switch ((int)value2.type) {
231
0
    case FcTypeInteger:
232
0
  b2 = e2 = value2.u.i;
233
0
  break;
234
4.72M
    case FcTypeDouble:
235
4.72M
  b2 = e2 = value2.u.d;
236
4.72M
  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
4.72M
    }
244
245
4.72M
    if (e1 < b2)
246
948k
  d = b2;
247
3.77M
    else if (e2 < b1)
248
1.12M
  d = e2;
249
2.65M
    else
250
2.65M
  d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5;
251
252
4.72M
    bestValue->type = FcTypeDouble;
253
4.72M
    bestValue->u.d = d;
254
255
    /* If the ranges overlap, it's a match, otherwise return closest distance. */
256
4.72M
    if (e1 < b2 || e2 < b1)
257
2.07M
  return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
258
2.65M
    else
259
2.65M
  return 0.0;
260
4.72M
}
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
28.3M
{
417
28.3M
    if (include_lang) {
418
9
  switch (object) {
419
3
  case FC_FAMILYLANG_OBJECT:
420
6
  case FC_STYLELANG_OBJECT:
421
9
  case FC_FULLNAMELANG_OBJECT:
422
9
      object = FC_LANG_OBJECT;
423
9
      break;
424
9
  }
425
9
    }
426
28.3M
    if (object > FC_MAX_BASE_OBJECT ||
427
28.3M
        !_FcMatchers[object].compare ||
428
21.2M
        _FcMatchers[object].strong == -1 ||
429
21.2M
        _FcMatchers[object].weak == -1)
430
7.08M
  return NULL;
431
432
21.2M
    return _FcMatchers + object;
433
28.3M
}
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
28.3M
{
445
28.3M
    FcValueListPtr v1, v2;
446
28.3M
    double         v, best, bestStrong, bestWeak;
447
28.3M
    int            j, k, pos = 0;
448
28.3M
    int            weak, strong;
449
450
28.3M
    if (!match) {
451
7.08M
  if (bestValue)
452
0
      *bestValue = FcValueCanonicalize (&v2orig->value);
453
7.08M
  if (n)
454
0
      *n = 0;
455
7.08M
  return FcTrue;
456
7.08M
    }
457
458
21.2M
    weak = match->weak;
459
21.2M
    strong = match->strong;
460
461
21.2M
    best = 1e99;
462
21.2M
    bestStrong = 1e99;
463
21.2M
    bestWeak = 1e99;
464
29.2M
    for (v1 = v1orig, j = 0; v1; v1 = FcValueListNext (v1), j++) {
465
31.5M
  for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext (v2), k++) {
466
23.6M
      FcValue matchValue;
467
23.6M
      v = (match->compare) (&v1->value, &v2->value, &matchValue);
468
23.6M
      if (v < 0) {
469
0
    *result = FcResultTypeMismatch;
470
0
    return FcFalse;
471
0
      }
472
23.6M
      v = v * 1000 + j * 100 + k * (v2->value.type == FcTypeString ? 1 : 0);
473
23.6M
      if (v < best) {
474
23.6M
    if (bestValue)
475
27
        *bestValue = matchValue;
476
23.6M
    best = v;
477
23.6M
    pos = k;
478
23.6M
      }
479
23.6M
      if (weak == strong) {
480
    /* found the best possible match */
481
23.6M
    if (best < 1000)
482
15.7M
        goto done;
483
23.6M
      } 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
23.6M
  }
491
23.6M
    }
492
21.2M
done:
493
21.2M
    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
21.2M
    if (value) {
501
21.2M
  if (weak == strong)
502
21.2M
      value[strong] += best;
503
0
  else {
504
0
      value[weak] += bestWeak;
505
0
      value[strong] += bestStrong;
506
0
  }
507
21.2M
    }
508
21.2M
    if (n)
509
9
  *n = pos;
510
511
21.2M
    return FcTrue;
512
21.2M
}
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
107k
{
532
107k
    FcHashTableDestroy (data->family_hash);
533
107k
}
534
535
static FcBool
536
FcCompareDataInit (FcPattern     *pat,
537
                   FcCompareData *data)
538
107k
{
539
107k
    FcHashTable   *table;
540
107k
    FcPatternElt  *elt;
541
107k
    FcValueListPtr l;
542
107k
    int            i;
543
107k
    const void    *key;
544
107k
    FamilyEntry   *e;
545
546
107k
    table = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
547
107k
                               (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
548
107k
                               NULL,
549
107k
                               NULL,
550
107k
                               NULL,
551
107k
                               free);
552
107k
    if (!table)
553
0
  return FcFalse;
554
555
107k
    elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
556
107k
    if (elt) {
557
214k
  for (l = FcPatternEltValues (elt), i = 0; l; l = FcValueListNext (l), i++) {
558
107k
      key = FcValueString (&l->value);
559
107k
      if (!FcHashTableFind (table, key, (void **)&e)) {
560
107k
    e = malloc (sizeof (FamilyEntry));
561
107k
    if (!e) {
562
0
        FcHashTableDestroy (table);
563
0
        return FcFalse;
564
0
    }
565
107k
    e->strong_value = 1e99;
566
107k
    e->weak_value = 1e99;
567
107k
    FcHashTableAdd (table, (void *)key, e);
568
107k
      }
569
107k
      if (l->binding == FcValueBindingWeak) {
570
0
    if (i < e->weak_value)
571
0
        e->weak_value = i;
572
107k
      } else {
573
107k
    if (i < e->strong_value)
574
107k
        e->strong_value = i;
575
107k
      }
576
107k
  }
577
107k
    }
578
579
107k
    data->family_hash = table;
580
107k
    return FcTrue;
581
107k
}
582
583
static FcBool
584
FcCompareFamilies (FcPattern     *pat,
585
                   FcValueListPtr v1orig,
586
                   FcPattern     *fnt,
587
                   FcValueListPtr v2orig,
588
                   double        *value,
589
                   FcResult      *result,
590
                   FcHashTable   *table)
591
2.36M
{
592
2.36M
    FcValueListPtr v2;
593
2.36M
    double         strong_value;
594
2.36M
    double         weak_value;
595
2.36M
    const void    *key;
596
2.36M
    FamilyEntry   *e;
597
598
2.36M
    assert (table != NULL);
599
600
2.36M
    strong_value = 1e99;
601
2.36M
    weak_value = 1e99;
602
603
5.69M
    for (v2 = v2orig; v2; v2 = FcValueListNext (v2)) {
604
3.32M
  key = FcValueString (&v2->value);
605
3.32M
  if (FcHashTableFind (table, key, (void **)&e)) {
606
938
      if (e->strong_value < strong_value)
607
938
    strong_value = e->strong_value;
608
938
      if (e->weak_value < weak_value)
609
0
    weak_value = e->weak_value;
610
938
  }
611
3.32M
    }
612
2.36M
    if (FcDebug() & FC_DBG_MATCHV) {
613
0
  printf ("%s: %g (%g) ", FcObjectName (FC_FAMILY_OBJECT), strong_value, weak_value);
614
0
  FcValueListPrint (v1orig);
615
0
  printf (", ");
616
0
  FcValueListPrint (v2orig);
617
0
  printf ("\n");
618
0
    }
619
620
2.36M
    value[PRI_FAMILY_STRONG] = strong_value;
621
2.36M
    value[PRI_FAMILY_WEAK] = weak_value;
622
623
2.36M
    return FcTrue;
624
2.36M
}
625
626
/*
627
 * Fonts loaded from caches that predate the genericfamily object
628
 * (issue #562) carry no FC_GENERIC_FAMILY element, so the merge-join
629
 * below would skip that dimension and hand them an unearned perfect
630
 * score.  Re-derive the value from the font's family (curated
631
 * classification only) and score it as if the scanner had stored it,
632
 * so an old-cache font matches like a freshly scanned one.
633
 */
634
static FcBool
635
FcCompareGenericFamilyBackfill (FcValueListPtr query, /* pattern genericfamily */
636
                                FcPattern     *fnt,
637
                                double        *value,
638
                                FcResult      *result)
639
0
{
640
0
    const FcMatcher      *match = FcObjectToMatcher (FC_GENERIC_FAMILY_OBJECT, FcFalse);
641
0
    FcPatternElt         *fam = FcPatternObjectFindElt (fnt, FC_FAMILY_OBJECT);
642
0
    FcGenericFamilyValues g;
643
0
    FcValueList           vl[FC_GENERIC_FAMILY_MAX_VALUES];
644
0
    int                   k;
645
646
0
    g = FcGenericFamilyGetValues (fam ? FcPatternEltValues (fam) : NULL);
647
0
    for (k = 0; k < g.n; k++) {
648
0
  vl[k].value.type = FcTypeInteger;
649
0
  vl[k].value.u.i = g.values[k];
650
0
  vl[k].binding = FcValueBindingStrong;
651
0
  vl[k].next = (k + 1 < g.n) ? &vl[k + 1] : NULL;
652
0
    }
653
0
    return FcCompareValueList (FC_GENERIC_FAMILY_OBJECT, match,
654
0
                               query, vl, NULL, value, NULL, result);
655
0
}
656
657
/*
658
 * Return a value indicating the distance between the two lists of
659
 * values
660
 */
661
662
static FcBool
663
FcCompare (FcPattern     *pat,
664
           FcPattern     *fnt,
665
           double        *value,
666
           FcResult      *result,
667
           FcCompareData *data)
668
2.36M
{
669
2.36M
    int i, i1, i2;
670
671
73.2M
    for (i = 0; i < PRI_END; i++)
672
70.8M
  value[i] = 0.0;
673
674
2.36M
    i1 = 0;
675
2.36M
    i2 = 0;
676
92.7M
    while (i1 < pat->num && i2 < fnt->num) {
677
90.3M
  FcPatternElt *elt_i1 = &FcPatternElts (pat)[i1];
678
90.3M
  FcPatternElt *elt_i2 = &FcPatternElts (fnt)[i2];
679
680
90.3M
  i = FcObjectCompare (elt_i1->object, elt_i2->object);
681
90.3M
  if (i > 0)
682
31.1M
      i2++;
683
59.2M
  else if (i < 0)
684
28.4M
      i1++;
685
30.7M
  else if (elt_i1->object == FC_FAMILY_OBJECT && data->family_hash) {
686
2.36M
      if (!FcCompareFamilies (pat, FcPatternEltValues (elt_i1),
687
2.36M
                              fnt, FcPatternEltValues (elt_i2),
688
2.36M
                              value, result,
689
2.36M
                              data->family_hash))
690
0
    return FcFalse;
691
2.36M
      i1++;
692
2.36M
      i2++;
693
28.3M
  } else {
694
28.3M
      const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse);
695
28.3M
      if (!FcCompareValueList (elt_i1->object, match,
696
28.3M
                               FcPatternEltValues (elt_i1),
697
28.3M
                               FcPatternEltValues (elt_i2),
698
28.3M
                               NULL, value, NULL, result))
699
0
    return FcFalse;
700
28.3M
      i1++;
701
28.3M
      i2++;
702
28.3M
  }
703
90.3M
    }
704
705
    /*
706
     * genericfamily is derivable from the family name, so reconstruct it
707
     * for fonts loaded from caches that predate the object rather than
708
     * leaving it unscored (issue #562).  This is done outside the
709
     * merge-join because the loop can exit before reaching a trailing
710
     * query object that the font lacks.
711
     * NOTE: when missing-object vs not-matched scoring is unified, this
712
     * reconstruction must run before the missing-object policy so
713
     * derivable objects are treated as present, not absent.
714
     */
715
2.36M
    {
716
2.36M
  FcPatternElt *q_gf = FcPatternObjectFindElt (pat, FC_GENERIC_FAMILY_OBJECT);
717
718
2.36M
  if (q_gf && !FcPatternObjectFindElt (fnt, FC_GENERIC_FAMILY_OBJECT) &&
719
0
      !FcCompareGenericFamilyBackfill (FcPatternEltValues (q_gf),
720
0
                                       fnt, value, result))
721
0
      return FcFalse;
722
2.36M
    }
723
724
2.36M
    return FcTrue;
725
2.36M
}
726
727
FcPattern *
728
FcFontRenderPrepare (FcConfig  *config,
729
                     FcPattern *pat,
730
                     FcPattern *font)
731
3
{
732
3
    FcPattern    *newp;
733
3
    int           i;
734
3
    FcPatternElt *fe, *pe;
735
3
    FcValue       v;
736
3
    FcResult      result;
737
3
    FcBool        variable = FcFalse;
738
3
    FcStrBuf      variations;
739
740
3
    assert (pat != NULL);
741
3
    assert (font != NULL);
742
743
3
    FcPatternObjectGetBool (font, FC_VARIABLE_OBJECT, 0, &variable);
744
3
    assert (variable != FcDontCare);
745
3
    if (variable)
746
0
  FcStrBufInit (&variations, NULL, 0);
747
748
3
    newp = FcPatternCreate();
749
3
    if (!newp)
750
0
  return NULL;
751
90
    for (i = 0; i < font->num; i++) {
752
87
  fe = &FcPatternElts (font)[i];
753
87
  if (fe->object == FC_FAMILYLANG_OBJECT ||
754
84
      fe->object == FC_STYLELANG_OBJECT ||
755
81
      fe->object == FC_FULLNAMELANG_OBJECT) {
756
      /* ignore those objects. we need to deal with them
757
       * another way */
758
9
      continue;
759
9
  }
760
78
  if (fe->object == FC_FAMILY_OBJECT ||
761
75
      fe->object == FC_STYLE_OBJECT ||
762
72
      fe->object == FC_FULLNAME_OBJECT) {
763
9
      FcPatternElt *fel, *pel;
764
765
9
      FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT);
766
9
      FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT);
767
9
      FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT);
768
769
9
      fel = FcPatternObjectFindElt (font, fe->object + 1);
770
9
      pel = FcPatternObjectFindElt (pat, fe->object + 1);
771
772
9
      if (fel && pel) {
773
    /* The font has name languages, and pattern asks for specific language(s).
774
     * Match on language and and prefer that result.
775
     * Note:  Currently the code only give priority to first matching language.
776
     */
777
9
    int              n = 1, j;
778
9
    FcValueListPtr   l1, l2, ln = NULL, ll = NULL;
779
9
    const FcMatcher *match = FcObjectToMatcher (pel->object, FcTrue);
780
781
9
    if (!FcCompareValueList (pel->object, match,
782
9
                             FcPatternEltValues (pel),
783
9
                             FcPatternEltValues (fel), NULL, NULL, &n, &result)) {
784
0
        FcPatternDestroy (newp);
785
0
        return NULL;
786
0
    }
787
788
9
    for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel);
789
18
         l1 != NULL || l2 != NULL;
790
9
         j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL) {
791
9
        FcValueListPtr (*func) (FcValueListPtr, FcValue, FcValueBinding);
792
9
        FcValueBinding binding = FcValueBindingEnd;
793
794
9
        if (j == n) {
795
9
      binding = FcValueBindingStrong;
796
9
      func = FcValueListPrepend;
797
9
        } else
798
0
      func = FcValueListAppend;
799
9
        if (l1) {
800
9
      ln = func (ln,
801
9
                 FcValueCanonicalize (&l1->value),
802
9
                 l1->binding);
803
9
        }
804
9
        if (l2) {
805
9
      if (binding == FcValueBindingEnd)
806
0
          binding = l2->binding;
807
9
      ll = func (ll,
808
9
                 FcValueCanonicalize (&l2->value),
809
9
                 binding);
810
9
        }
811
9
    }
812
9
    FcPatternObjectListAdd (newp, fe->object, ln, FcFalse);
813
9
    FcPatternObjectListAdd (newp, fel->object, ll, FcFalse);
814
815
9
    continue;
816
9
      } else if (fel) {
817
    /* Pattern doesn't ask for specific language.  Copy all for name and
818
     * lang. */
819
0
    FcValueListPtr l1, l2;
820
821
0
    l1 = FcValueListDuplicate (FcPatternEltValues (fe));
822
0
    l2 = FcValueListDuplicate (FcPatternEltValues (fel));
823
0
    FcPatternObjectListAdd (newp, fe->object, l1, FcFalse);
824
0
    FcPatternObjectListAdd (newp, fel->object, l2, FcFalse);
825
826
0
    continue;
827
0
      }
828
9
  }
829
830
69
  pe = FcPatternObjectFindElt (pat, fe->object);
831
69
  if (pe) {
832
27
      const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse);
833
27
      if (!FcCompareValueList (pe->object, match,
834
27
                               FcPatternEltValues (pe),
835
27
                               FcPatternEltValues (fe), &v, NULL, NULL, &result)) {
836
0
    FcPatternDestroy (newp);
837
0
    return NULL;
838
0
      }
839
27
      FcPatternObjectAdd (newp, fe->object, v, FcFalse);
840
841
      /* Set font-variations settings for standard axes in variable fonts. */
842
27
      if (variable &&
843
0
          FcPatternEltValues (fe)->value.type == FcTypeRange &&
844
0
          (fe->object == FC_WEIGHT_OBJECT ||
845
0
           fe->object == FC_WIDTH_OBJECT ||
846
0
           fe->object == FC_SIZE_OBJECT)) {
847
0
    double      num;
848
0
    const char *tag = "    ";
849
850
0
    assert (v.type == FcTypeDouble);
851
0
    num = v.u.d;
852
0
    if (variations.len)
853
0
        FcStrBufChar (&variations, ',');
854
0
    switch (fe->object) {
855
0
    case FC_WEIGHT_OBJECT:
856
0
        tag = "wght";
857
0
        num = FcWeightToOpenType (num);
858
0
        break;
859
860
0
    case FC_WIDTH_OBJECT:
861
0
        tag = "wdth";
862
0
        break;
863
864
0
    case FC_SIZE_OBJECT:
865
0
        tag = "opsz";
866
0
        break;
867
0
    }
868
0
    FcStrBufFormat (&variations, "%4s=%g", tag, num);
869
0
      }
870
42
  } else {
871
42
      FcPatternObjectListAdd (newp, fe->object,
872
42
                              FcValueListDuplicate (FcPatternEltValues (fe)),
873
42
                              FcTrue);
874
42
  }
875
69
    }
876
78
    for (i = 0; i < pat->num; i++) {
877
75
  pe = &FcPatternElts (pat)[i];
878
75
  fe = FcPatternObjectFindElt (font, pe->object);
879
75
  if (!fe &&
880
36
      pe->object != FC_FAMILYLANG_OBJECT &&
881
36
      pe->object != FC_STYLELANG_OBJECT &&
882
36
      pe->object != FC_FULLNAMELANG_OBJECT) {
883
36
      FcPatternObjectListAdd (newp, pe->object,
884
36
                              FcValueListDuplicate (FcPatternEltValues (pe)),
885
36
                              FcFalse);
886
36
  }
887
75
    }
888
889
3
    if (variable && variations.len) {
890
0
  FcChar8 *vars = NULL;
891
0
  if (FcPatternObjectGetString (newp, FC_FONT_VARIATIONS_OBJECT, 0, &vars) == FcResultMatch) {
892
0
      FcStrBufChar (&variations, ',');
893
0
      FcStrBufString (&variations, vars);
894
0
      FcPatternObjectDel (newp, FC_FONT_VARIATIONS_OBJECT);
895
0
  }
896
897
0
  FcPatternObjectAddString (newp, FC_FONT_VARIATIONS_OBJECT, FcStrBufDoneStatic (&variations));
898
0
  FcStrBufDestroy (&variations);
899
0
    }
900
901
3
    FcConfigSubstituteWithPat (config, newp, pat, FcMatchFont);
902
3
    return newp;
903
3
}
904
905
static FcPattern *
906
FcFontSetMatchInternal (FcFontSet **sets,
907
                        int         nsets,
908
                        FcPattern  *p,
909
                        FcResult   *result)
910
3
{
911
3
    double              score[PRI_END], bestscore[PRI_END];
912
3
    int                 f;
913
3
    FcFontSet          *s;
914
3
    FcPattern          *best, *pat = NULL;
915
3
    int                 i;
916
3
    int                 set;
917
3
    FcCompareData       data;
918
3
    const FcPatternElt *elt;
919
920
93
    for (i = 0; i < PRI_END; i++)
921
90
  bestscore[i] = 0;
922
3
    best = 0;
923
3
    if (FcDebug() & FC_DBG_MATCH) {
924
0
  printf ("Match ");
925
0
  FcPatternPrint (p);
926
0
    }
927
928
3
    if (!FcCompareDataInit (p, &data))
929
0
  return 0;
930
931
6
    for (set = 0; set < nsets; set++) {
932
3
  s = sets[set];
933
3
  if (!s)
934
0
      continue;
935
69
  for (f = 0; f < s->nfont; f++) {
936
66
      if (FcDebug() & FC_DBG_MATCHV) {
937
0
    printf ("Font %d ", f);
938
0
    FcPatternPrint (s->fonts[f]);
939
0
      }
940
66
      if (!FcCompare (p, s->fonts[f], score, result, &data)) {
941
0
    FcCompareDataClear (&data);
942
0
    return 0;
943
0
      }
944
66
      if (FcDebug() & FC_DBG_MATCHV) {
945
0
    printf ("Score");
946
0
    for (i = 0; i < PRI_END; i++) {
947
0
        printf (" %g", score[i]);
948
0
    }
949
0
    printf ("\n");
950
0
      }
951
1.44k
      for (i = 0; i < PRI_END; i++) {
952
1.43k
    if (best && bestscore[i] < score[i])
953
54
        break;
954
1.38k
    if (!best || score[i] < bestscore[i]) {
955
93
        for (i = 0; i < PRI_END; i++)
956
90
      bestscore[i] = score[i];
957
3
        best = s->fonts[f];
958
3
        break;
959
3
    }
960
1.38k
      }
961
66
  }
962
3
    }
963
964
3
    FcCompareDataClear (&data);
965
966
    /* Update the binding according to the score to indicate how exactly values matches on. */
967
3
    if (best) {
968
3
  pat = FcPatternCreate();
969
3
  elt = FcPatternElts (best);
970
90
  for (i = 0; i < FcPatternObjectCount (best); i++) {
971
87
      const FcMatcher *match = FcObjectToMatcher (elt[i].object, FcFalse);
972
87
      FcValueListPtr   l = FcPatternEltValues (&elt[i]);
973
974
87
      if (!match)
975
18
    FcPatternObjectListAdd (pat, elt[i].object,
976
18
                            FcValueListDuplicate (l), FcTrue);
977
69
      else {
978
69
    FcValueBinding binding = FcValueBindingWeak;
979
69
    FcValueListPtr newp = NULL, ll, t = NULL;
980
69
    FcValue        v;
981
982
    /* If the value was matched exactly, update the binding to Strong. */
983
69
    if (bestscore[match->strong] < 1000)
984
60
        binding = FcValueBindingStrong;
985
986
138
    for (ll = l; ll != NULL; ll = FcValueListNext (ll)) {
987
69
        if (!newp) {
988
69
      t = newp = FcValueListCreate();
989
69
        } else {
990
0
      t->next = FcValueListCreate();
991
0
      t = FcValueListNext (t);
992
0
        }
993
69
        v = FcValueCanonicalize (&ll->value);
994
69
        t->value = FcValueSave (v);
995
69
        t->binding = binding;
996
69
        t->next = NULL;
997
69
    }
998
69
    FcPatternObjectListAdd (pat, elt[i].object, newp, FcTrue);
999
69
      }
1000
87
  }
1001
3
    }
1002
3
    if (FcDebug() & FC_DBG_MATCH) {
1003
0
  printf ("Best score");
1004
0
  for (i = 0; i < PRI_END; i++)
1005
0
      printf (" %g", bestscore[i]);
1006
0
  printf ("\n");
1007
0
  FcPatternPrint (pat);
1008
0
    }
1009
3
    if (FcDebug() & FC_DBG_MATCH2) {
1010
0
  char        *env = getenv ("FC_DBG_MATCH_FILTER");
1011
0
  FcObjectSet *os = NULL;
1012
1013
0
  if (env) {
1014
0
      char  *ss, *s;
1015
0
      char  *p;
1016
0
      FcBool f = FcTrue;
1017
1018
0
      ss = s = (char *)FcStrCopy ((const FcChar8 *)env);
1019
0
      os = FcObjectSetCreate();
1020
0
      while (f) {
1021
0
    size_t len;
1022
0
    char  *x;
1023
1024
0
    if (!(p = strchr (s, ','))) {
1025
0
        f = FcFalse;
1026
0
        len = strlen (s);
1027
0
    } else {
1028
0
        len = (p - s);
1029
0
    }
1030
0
    x = malloc (sizeof (char) * (len + 1));
1031
0
    if (x) {
1032
0
        strcpy (x, s);
1033
0
        if (FcObjectFromName (x) > 0)
1034
0
      FcObjectSetAdd (os, x);
1035
0
        s = p + 1;
1036
0
        free (x);
1037
0
    }
1038
0
      }
1039
0
      free (ss);
1040
0
  }
1041
0
  FcPatternPrint2 (p, pat, os);
1042
0
  if (os)
1043
0
      FcObjectSetDestroy (os);
1044
0
    }
1045
    /* assuming that 'result' is initialized with FcResultNoMatch
1046
     * outside this function */
1047
3
    if (pat)
1048
3
  *result = FcResultMatch;
1049
1050
3
    return pat;
1051
3
}
1052
1053
FcPattern *
1054
FcFontSetMatch (FcConfig   *config,
1055
                FcFontSet **sets,
1056
                int         nsets,
1057
                FcPattern  *p,
1058
                FcResult   *result)
1059
0
{
1060
0
    FcPattern *best, *ret = NULL;
1061
1062
0
    assert (sets != NULL);
1063
0
    assert (p != NULL);
1064
0
    assert (result != NULL);
1065
1066
0
    *result = FcResultNoMatch;
1067
1068
0
    config = FcConfigReference (config);
1069
0
    if (!config)
1070
0
  return NULL;
1071
0
    best = FcFontSetMatchInternal (sets, nsets, p, result);
1072
0
    if (best) {
1073
0
  ret = FcFontRenderPrepare (config, p, best);
1074
0
  FcPatternDestroy (best);
1075
0
    }
1076
1077
0
    FcConfigDestroy (config);
1078
1079
0
    return ret;
1080
0
}
1081
1082
FcPattern *
1083
FcFontMatch (FcConfig  *config,
1084
             FcPattern *p,
1085
             FcResult  *result)
1086
3
{
1087
3
    FcFontSet *sets[2];
1088
3
    int        nsets;
1089
3
    FcPattern *best, *ret = NULL;
1090
1091
3
    assert (p != NULL);
1092
3
    assert (result != NULL);
1093
1094
3
    *result = FcResultNoMatch;
1095
1096
3
    config = FcConfigReference (config);
1097
3
    if (!config)
1098
0
  return NULL;
1099
3
    FcRwLockReadLock (&config->fonts_lock);
1100
3
    nsets = 0;
1101
3
    if (config->fonts[FcSetSystem])
1102
3
  sets[nsets++] = config->fonts[FcSetSystem];
1103
3
    if (config->fonts[FcSetApplication])
1104
0
  sets[nsets++] = config->fonts[FcSetApplication];
1105
1106
3
    best = FcFontSetMatchInternal (sets, nsets, p, result);
1107
3
    FcRwLockUnlockRead (&config->fonts_lock);
1108
3
    if (best) {
1109
3
  ret = FcFontRenderPrepare (config, p, best);
1110
3
  FcPatternDestroy (best);
1111
3
    }
1112
1113
3
    FcConfigDestroy (config);
1114
1115
3
    return ret;
1116
3
}
1117
1118
typedef struct _FcSortNode {
1119
    FcPattern *pattern;
1120
    double     score[PRI_END];
1121
} FcSortNode;
1122
1123
static int
1124
FcSortCompare (const void *aa, const void *ab)
1125
12.7M
{
1126
12.7M
    FcSortNode *a = *(FcSortNode **)aa;
1127
12.7M
    FcSortNode *b = *(FcSortNode **)ab;
1128
12.7M
    double     *as = &a->score[0];
1129
12.7M
    double     *bs = &b->score[0];
1130
12.7M
    double      ad = 0, bd = 0;
1131
12.7M
    int         i;
1132
1133
12.7M
    i = PRI_END;
1134
293M
    while (i-- && (ad = *as++) == (bd = *bs++))
1135
280M
  ;
1136
12.7M
    return ad < bd ? -1 : ad > bd ? 1
1137
6.36M
                                  : 0;
1138
12.7M
}
1139
1140
static FcBool
1141
FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
1142
107k
{
1143
107k
    FcBool     ret = FcFalse;
1144
107k
    FcCharSet *cs;
1145
107k
    int        i;
1146
1147
107k
    cs = 0;
1148
107k
    if (trim || csp) {
1149
0
  cs = FcCharSetCreate();
1150
0
  if (cs == NULL)
1151
0
      goto bail;
1152
0
    }
1153
1154
2.47M
    for (i = 0; i < nnode; i++) {
1155
2.36M
  FcSortNode *node = *n++;
1156
2.36M
  FcBool      adds_chars = FcFalse;
1157
1158
  /*
1159
   * Only fetch node charset if we'd need it
1160
   */
1161
2.36M
  if (cs) {
1162
0
      FcCharSet *ncs;
1163
1164
0
      if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
1165
0
          FcResultMatch)
1166
0
    continue;
1167
1168
0
      if (!FcCharSetMerge (cs, ncs, &adds_chars))
1169
0
    goto bail;
1170
0
  }
1171
1172
  /*
1173
   * If this font isn't a subset of the previous fonts,
1174
   * add it to the list
1175
   */
1176
2.36M
  if (!i || !trim || adds_chars) {
1177
2.36M
      FcPatternReference (node->pattern);
1178
2.36M
      if (FcDebug() & FC_DBG_MATCHV) {
1179
0
    printf ("Add ");
1180
0
    FcPatternPrint (node->pattern);
1181
0
      }
1182
2.36M
      if (!FcFontSetAdd (fs, node->pattern)) {
1183
0
    FcPatternDestroy (node->pattern);
1184
0
    goto bail;
1185
0
      }
1186
2.36M
  }
1187
2.36M
    }
1188
107k
    if (csp) {
1189
0
  *csp = cs;
1190
0
  cs = 0;
1191
0
    }
1192
1193
107k
    ret = FcTrue;
1194
1195
107k
bail:
1196
107k
    if (cs)
1197
0
  FcCharSetDestroy (cs);
1198
1199
107k
    return ret;
1200
107k
}
1201
1202
void
1203
FcFontSetSortDestroy (FcFontSet *fs)
1204
0
{
1205
0
    FcFontSetDestroy (fs);
1206
0
}
1207
1208
FcFontSet *
1209
FcFontSetSort (FcConfig   *config,
1210
               FcFontSet **sets,
1211
               int         nsets,
1212
               FcPattern  *p,
1213
               FcBool      trim,
1214
               FcCharSet **csp,
1215
               FcResult   *result)
1216
107k
{
1217
107k
    FcFontSet    *ret;
1218
107k
    FcFontSet    *s;
1219
107k
    FcSortNode   *nodes;
1220
107k
    FcSortNode  **nodeps, **nodep;
1221
107k
    int           nnodes;
1222
107k
    FcSortNode   *newp;
1223
107k
    int           set;
1224
107k
    int           f;
1225
107k
    int           i;
1226
107k
    int           nPatternLang;
1227
107k
    FcBool       *patternLangSat;
1228
107k
    FcValue       patternLang;
1229
107k
    FcCompareData data;
1230
1231
107k
    assert (sets != NULL);
1232
107k
    assert (p != NULL);
1233
107k
    assert (result != NULL);
1234
1235
    /* There are some implementation that relying on the result of
1236
     * "result" to check if the return value of FcFontSetSort
1237
     * is valid or not.
1238
     * So we should initialize it to the conservative way since
1239
     * this function doesn't return NULL anymore.
1240
     */
1241
107k
    if (result)
1242
107k
  *result = FcResultNoMatch;
1243
1244
107k
    if (FcDebug() & FC_DBG_MATCH) {
1245
0
  printf ("Sort ");
1246
0
  FcPatternPrint (p);
1247
0
    }
1248
107k
    nnodes = 0;
1249
214k
    for (set = 0; set < nsets; set++) {
1250
107k
  s = sets[set];
1251
107k
  if (!s)
1252
0
      continue;
1253
107k
  nnodes += s->nfont;
1254
107k
    }
1255
107k
    if (!nnodes)
1256
0
  return FcFontSetCreate();
1257
1258
107k
    if (!config)
1259
0
  config = FcConfigGetCurrent();
1260
107k
    FcConfigReference (config);
1261
1262
107k
    for (nPatternLang = 0;
1263
322k
         FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
1264
214k
         nPatternLang++)
1265
214k
  ;
1266
1267
    /* freed below */
1268
107k
    nodes = malloc (nnodes * sizeof (FcSortNode) +
1269
107k
                    nnodes * sizeof (FcSortNode *) +
1270
107k
                    nPatternLang * sizeof (FcBool));
1271
107k
    if (!nodes)
1272
0
  goto bail0;
1273
107k
    nodeps = (FcSortNode **)(nodes + nnodes);
1274
107k
    patternLangSat = (FcBool *)(nodeps + nnodes);
1275
1276
107k
    if (!FcCompareDataInit (p, &data))
1277
0
  goto bail1;
1278
1279
107k
    newp = nodes;
1280
107k
    nodep = nodeps;
1281
214k
    for (set = 0; set < nsets; set++) {
1282
107k
  s = sets[set];
1283
107k
  if (!s)
1284
0
      continue;
1285
2.47M
  for (f = 0; f < s->nfont; f++) {
1286
2.36M
      if (FcDebug() & FC_DBG_MATCHV) {
1287
0
    printf ("Font %d ", f);
1288
0
    FcPatternPrint (s->fonts[f]);
1289
0
      }
1290
2.36M
      newp->pattern = s->fonts[f];
1291
2.36M
      if (!FcCompare (p, newp->pattern, newp->score, result, &data))
1292
0
    goto bail1;
1293
      /* TODO: Should we check a FcPattern in FcFontSet?
1294
       * This way may not work if someone has own list of application fonts
1295
       * That said, just to reduce the cost for lookup so far.
1296
       */
1297
2.36M
      if (config->prefer_app_fonts && s != config->fonts[FcSetApplication]) {
1298
0
    newp->score[PRI_ORDER] += 1000;
1299
0
      }
1300
2.36M
      if (FcDebug() & FC_DBG_MATCHV) {
1301
0
    printf ("Score");
1302
0
    for (i = 0; i < PRI_END; i++) {
1303
0
        printf (" %g", newp->score[i]);
1304
0
    }
1305
0
    printf ("\n");
1306
0
      }
1307
2.36M
      *nodep = newp;
1308
2.36M
      newp++;
1309
2.36M
      nodep++;
1310
2.36M
  }
1311
107k
    }
1312
1313
107k
    FcCompareDataClear (&data);
1314
1315
107k
    nnodes = newp - nodes;
1316
1317
107k
    qsort (nodeps, nnodes, sizeof (FcSortNode *),
1318
107k
           FcSortCompare);
1319
1320
322k
    for (i = 0; i < nPatternLang; i++)
1321
214k
  patternLangSat[i] = FcFalse;
1322
1323
2.47M
    for (f = 0; f < nnodes; f++) {
1324
2.36M
  FcBool satisfies = FcFalse;
1325
  /*
1326
   * If this node matches any language, go check
1327
   * which ones and satisfy those entries
1328
   */
1329
2.36M
  if (nodeps[f]->score[PRI_LANG] < 2000) {
1330
6.98M
      for (i = 0; i < nPatternLang; i++) {
1331
4.72M
    FcValue nodeLang;
1332
1333
4.72M
    if (!patternLangSat[i] &&
1334
2.47M
        FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
1335
2.47M
        FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch) {
1336
2.47M
        FcValue matchValue;
1337
2.47M
        double  compare = FcCompareLang (&patternLang, &nodeLang, &matchValue);
1338
2.47M
        if (compare >= 0 && compare < 2) {
1339
107k
      if (FcDebug() & FC_DBG_MATCHV) {
1340
0
          FcChar8 *family;
1341
0
          FcChar8 *style;
1342
1343
0
          if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
1344
0
              FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
1345
0
        printf ("Font %s:%s matches language %d\n", family, style, i);
1346
0
      }
1347
107k
      patternLangSat[i] = FcTrue;
1348
107k
      satisfies = FcTrue;
1349
107k
      break;
1350
107k
        }
1351
2.47M
    }
1352
4.72M
      }
1353
2.36M
  }
1354
2.36M
  if (!satisfies) {
1355
2.25M
      nodeps[f]->score[PRI_LANG] = 10000.0;
1356
2.25M
  }
1357
2.36M
    }
1358
1359
    /*
1360
     * Re-sort once the language issues have been settled
1361
     */
1362
107k
    qsort (nodeps, nnodes, sizeof (FcSortNode *),
1363
107k
           FcSortCompare);
1364
1365
107k
    ret = FcFontSetCreate();
1366
107k
    if (!ret)
1367
0
  goto bail1;
1368
1369
107k
    if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
1370
0
  goto bail2;
1371
1372
107k
    free (nodes);
1373
1374
107k
    if (ret->nfont > 0) {
1375
107k
  *result = FcResultMatch;
1376
107k
  if (FcDebug() & FC_DBG_MATCH) {
1377
0
      printf ("First font ");
1378
0
      FcPatternPrint (ret->fonts[0]);
1379
0
  }
1380
107k
    }
1381
107k
    if (config)
1382
107k
  FcConfigDestroy (config);
1383
1384
107k
    return ret;
1385
1386
0
bail2:
1387
0
    FcFontSetDestroy (ret);
1388
0
bail1:
1389
0
    free (nodes);
1390
0
bail0:
1391
0
    if (config)
1392
0
  FcConfigDestroy (config);
1393
0
    return 0;
1394
0
}
1395
1396
FcFontSet *
1397
FcFontSort (FcConfig   *config,
1398
            FcPattern  *p,
1399
            FcBool      trim,
1400
            FcCharSet **csp,
1401
            FcResult   *result)
1402
107k
{
1403
107k
    FcFontSet *sets[2], *ret;
1404
107k
    int        nsets;
1405
1406
107k
    assert (p != NULL);
1407
107k
    assert (result != NULL);
1408
1409
107k
    *result = FcResultNoMatch;
1410
1411
107k
    config = FcConfigReference (config);
1412
107k
    if (!config)
1413
0
  return NULL;
1414
107k
    FcRwLockReadLock (&config->fonts_lock);
1415
107k
    nsets = 0;
1416
107k
    if (config->fonts[FcSetSystem])
1417
107k
  sets[nsets++] = config->fonts[FcSetSystem];
1418
107k
    if (config->fonts[FcSetApplication])
1419
0
  sets[nsets++] = config->fonts[FcSetApplication];
1420
107k
    ret = FcFontSetSort (config, sets, nsets, p, trim, csp, result);
1421
107k
    FcRwLockUnlockRead (&config->fonts_lock);
1422
107k
    FcConfigDestroy (config);
1423
1424
107k
    return ret;
1425
107k
}
1426
#define __fcmatch__
1427
#include "fcaliastail.h"
1428
#undef __fcmatch__