Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/fontconfig/src/fcdefault.c
Line
Count
Source
1
/*
2
 * fontconfig/src/fcdefault.c
3
 *
4
 * Copyright © 2001 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 <limits.h>
28
#include <string.h>
29
30
/* MT-safe */
31
32
static const struct {
33
    FcObject field;
34
    FcBool   value;
35
} FcBoolDefaults[] = {
36
    { FC_HINTING_OBJECT,         FcTrue  }, /* !FT_LOAD_NO_HINTING */
37
    { FC_VERTICAL_LAYOUT_OBJECT, FcFalse }, /* FC_LOAD_VERTICAL_LAYOUT */
38
    { FC_AUTOHINT_OBJECT,        FcFalse }, /* FC_LOAD_FORCE_AUTOHINT */
39
    { FC_GLOBAL_ADVANCE_OBJECT,  FcTrue  }, /* !FC_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
40
    { FC_EMBEDDED_BITMAP_OBJECT, FcTrue  }, /* !FC_LOAD_NO_BITMAP */
41
    { FC_DECORATIVE_OBJECT,      FcFalse },
42
    { FC_SYMBOL_OBJECT,          FcFalse },
43
    { FC_VARIABLE_OBJECT,        FcFalse },
44
};
45
46
594
#define NUM_FC_BOOL_DEFAULTS (int)(sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
47
48
FcStrSet *
49
FcConfigGetDefaultLangs (FcConfig *config)
50
68
{
51
68
    FcStrSet *result;
52
53
68
    if (!config) {
54
0
  config = FcConfigGetCurrent();
55
0
    }
56
68
    FcConfigReference (config);
57
68
retry:
58
68
    result = (FcStrSet *)fc_atomic_ptr_get (&config->default_langs);
59
68
    if (!result) {
60
2
  char *langs;
61
62
2
  result = FcStrSetCreate();
63
64
2
  langs = getenv ("FC_LANG");
65
2
  if (!langs || !langs[0])
66
2
      langs = getenv ("LC_ALL");
67
2
  if (!langs || !langs[0]) {
68
2
      langs = getenv ("LC_CTYPE");
69
      // On some macOS systems, LC_CTYPE is set to "UTF-8", which doesn't
70
      // give any languge information. In this case, ignore LC_CTYPE and
71
      // continue the search with LANG.
72
2
      if (langs && (FcStrCmpIgnoreCase ((const FcChar8 *)langs,
73
0
                                        (const FcChar8 *)"UTF-8") == 0)) {
74
0
    langs = NULL;
75
0
      }
76
2
  }
77
2
  if (!langs || !langs[0])
78
2
      langs = getenv ("LANG");
79
2
  if (langs && langs[0]) {
80
0
      if (!FcStrSetAddLangs (result, langs))
81
0
    FcStrSetAdd (result, (const FcChar8 *)"en");
82
0
  } else
83
2
      FcStrSetAdd (result, (const FcChar8 *)"en");
84
85
2
  FcRefSetConst (&result->ref);
86
2
  if (!fc_atomic_ptr_cmpexch (&config->default_langs, NULL, result)) {
87
0
      FcRefInit (&result->ref, 1);
88
0
      FcStrSetDestroy (result);
89
0
      goto retry;
90
0
  }
91
2
    }
92
68
    FcConfigDestroy (config);
93
94
68
    return result;
95
68
}
96
97
FcStrSet *
98
FcGetDefaultLangs (void)
99
0
{
100
0
    return FcConfigGetDefaultLangs (NULL);
101
0
}
102
103
FcChar8 *
104
FcConfigGetDefaultLang (FcConfig *config)
105
66
{
106
66
    FcChar8 *lang;
107
108
66
    if (!config) {
109
0
  config = FcConfigGetCurrent();
110
0
    }
111
66
    FcConfigReference (config);
112
66
retry:
113
66
    lang = fc_atomic_ptr_get (&config->default_lang);
114
66
    if (!lang) {
115
2
  FcStrSet *langs = FcConfigGetDefaultLangs (config);
116
2
  lang = FcStrCopy (langs->strs[0]);
117
118
2
  if (!fc_atomic_ptr_cmpexch (&config->default_lang, NULL, lang)) {
119
0
      free (lang);
120
0
      goto retry;
121
0
  }
122
2
    }
123
66
    FcConfigDestroy (config);
124
125
66
    return lang;
126
66
}
127
128
FcChar8 *
129
FcGetDefaultLang (void)
130
0
{
131
0
    return FcConfigGetDefaultLang (NULL);
132
0
}
133
134
FcChar8 *
135
FcConfigGetPrgname (FcConfig *config)
136
66
{
137
66
    FcChar8 *prgname;
138
139
66
    if (!config) {
140
0
  config = FcConfigGetCurrent();
141
0
    }
142
66
    FcConfigReference (config);
143
66
retry:
144
66
    prgname = fc_atomic_ptr_get (&config->prgname);
145
66
    if (!prgname) {
146
#ifdef _WIN32
147
  char buf[MAX_PATH + 1];
148
149
  /* TODO This is ASCII-only; fix it. */
150
  if (GetModuleFileNameA (GetModuleHandle (NULL), buf, sizeof (buf) / sizeof (buf[0])) > 0) {
151
      char        *p;
152
      unsigned int len;
153
154
      p = strrchr (buf, '\\');
155
      if (p)
156
    p++;
157
      else
158
    p = buf;
159
160
      len = strlen (p);
161
162
      if (len > 4 && 0 == strcmp (p + len - 4, ".exe")) {
163
    len -= 4;
164
    buf[len] = '\0';
165
      }
166
167
      prgname = FcStrCopy (p);
168
  }
169
#elif defined(HAVE_GETPROGNAME)
170
  const char *q = getprogname();
171
  if (q)
172
      prgname = FcStrCopy (q);
173
  else
174
      prgname = FcStrCopy ("");
175
#else
176
#  if defined(HAVE_GETEXECNAME)
177
  char *p = FcStrCopy (getexecname());
178
#  elif defined(HAVE_READLINK)
179
2
  size_t size = FC_PATH_MAX;
180
2
  char  *p = NULL;
181
182
2
  while (1) {
183
2
      char   *buf = malloc (size);
184
2
      ssize_t len;
185
186
2
      if (!buf)
187
0
    break;
188
189
2
      len = readlink ("/proc/self/exe", buf, size - 1);
190
2
      if (len < 0) {
191
0
    free (buf);
192
0
    break;
193
0
      }
194
2
      if (len < size - 1) {
195
2
    buf[len] = 0;
196
2
    p = buf;
197
2
    break;
198
2
      }
199
200
0
      free (buf);
201
0
      size *= 2;
202
0
  }
203
#  else
204
  char *p = NULL;
205
#  endif
206
2
  if (p) {
207
2
      char *r = strrchr (p, '/');
208
2
      if (r)
209
2
    r++;
210
0
      else
211
0
    r = p;
212
213
2
      prgname = FcStrCopy ((const FcChar8 *)r);
214
2
  }
215
216
2
  if (!prgname)
217
0
      prgname = FcStrCopy ((const FcChar8 *)"");
218
219
2
  if (p)
220
2
      free (p);
221
2
#endif
222
223
2
  if (!fc_atomic_ptr_cmpexch (&config->prgname, NULL, prgname)) {
224
0
      free (prgname);
225
0
      goto retry;
226
0
  }
227
2
    }
228
229
66
    if (prgname && !prgname[0]) {
230
0
  prgname = NULL;
231
0
    }
232
66
    FcConfigDestroy (config);
233
234
66
    return prgname;
235
66
}
236
237
FcChar8 *
238
FcGetPrgname (void)
239
0
{
240
0
    return FcConfigGetPrgname (NULL);
241
0
}
242
243
FcChar8 *
244
FcConfigGetDesktopName (FcConfig *config)
245
66
{
246
66
    FcChar8 *desktop_name;
247
248
66
    if (!config) {
249
0
  config = FcConfigGetCurrent();
250
0
    }
251
66
    FcConfigReference (config);
252
66
retry:
253
66
    desktop_name = fc_atomic_ptr_get (&config->desktop_name);
254
66
    if (!desktop_name) {
255
2
  char *s = getenv ("XDG_CURRENT_DESKTOP");
256
257
2
  if (!s)
258
2
      desktop_name = FcStrCopy ((const FcChar8 *)"");
259
0
  else
260
0
      desktop_name = FcStrCopy ((const FcChar8 *)s);
261
2
  if (!desktop_name) {
262
0
      fprintf (stderr, "Fontconfig error: out of memory in %s\n",
263
0
               __FUNCTION__);
264
0
      return NULL;
265
0
  }
266
267
2
  if (!fc_atomic_ptr_cmpexch (&config->desktop_name, NULL, desktop_name)) {
268
0
      free (desktop_name);
269
0
      goto retry;
270
0
  }
271
2
    }
272
66
    if (desktop_name && !desktop_name[0]) {
273
66
  desktop_name = NULL;
274
66
    }
275
66
    FcConfigDestroy (config);
276
277
66
    return desktop_name;
278
66
}
279
280
FcChar8 *
281
FcGetDesktopName (void)
282
0
{
283
0
    return FcConfigGetDesktopName (NULL);
284
0
}
285
286
void
287
FcConfigSetDefaultSubstitute (FcConfig  *config,
288
                              FcPattern *pattern)
289
66
{
290
66
    FcPatternIter iter;
291
66
    FcValue       v, namelang, v2;
292
66
    int           i;
293
66
    double        dpi, size, scale, pixelsize;
294
295
66
    config = FcConfigReference (config);
296
297
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_WEIGHT_OBJECT))
298
0
  FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_NORMAL);
299
300
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_SLANT_OBJECT))
301
0
  FcPatternObjectAddInteger (pattern, FC_SLANT_OBJECT, FC_SLANT_ROMAN);
302
303
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_WIDTH_OBJECT))
304
0
  FcPatternObjectAddInteger (pattern, FC_WIDTH_OBJECT, FC_WIDTH_NORMAL);
305
306
594
    for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
307
528
  if (!FcPatternFindObjectIter (pattern, &iter, FcBoolDefaults[i].field))
308
528
      FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
309
310
66
    if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch) {
311
66
  FcRange *r;
312
66
  double   b, e;
313
66
  if (FcPatternObjectGetRange (pattern, FC_SIZE_OBJECT, 0, &r) == FcResultMatch && FcRangeGetDouble (r, &b, &e))
314
0
      size = (b + e) * .5;
315
66
  else
316
66
      size = 12.0L;
317
66
    }
318
66
    if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
319
66
  scale = 1.0;
320
66
    if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
321
66
  dpi = 75.0;
322
323
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_PIXEL_SIZE_OBJECT)) {
324
0
  (void)FcPatternObjectDel (pattern, FC_SCALE_OBJECT);
325
0
  FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale);
326
0
  pixelsize = size * scale;
327
0
  (void)FcPatternObjectDel (pattern, FC_DPI_OBJECT);
328
0
  FcPatternObjectAddDouble (pattern, FC_DPI_OBJECT, dpi);
329
0
  pixelsize *= dpi / 72.0;
330
0
  FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, pixelsize);
331
66
    } else {
332
66
  FcPatternIterGetValue (pattern, &iter, 0, &v, NULL);
333
66
  if (v.type == FcTypeInteger)
334
0
      size = (double)v.u.i;
335
66
  else
336
66
      size = v.u.d;
337
66
  size = size / dpi * 72.0 / scale;
338
66
    }
339
66
    (void)FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
340
66
    FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
341
342
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FONTVERSION_OBJECT))
343
66
  FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff);
344
345
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_HINT_STYLE_OBJECT))
346
66
  FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL);
347
348
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_NAMELANG_OBJECT))
349
66
  FcPatternObjectAddString (pattern, FC_NAMELANG_OBJECT, FcConfigGetDefaultLang (config));
350
351
    /* shouldn't be failed. */
352
66
    FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &namelang);
353
    /* Add a fallback to ensure the english name when the requested language
354
     * isn't available. this would helps for the fonts that have non-English
355
     * name at the beginning.
356
     */
357
    /* Set "en-us" instead of "en" to avoid giving higher score to "en".
358
     * This is a hack for the case that the orth is not like ll-cc, because,
359
     * if no namelang isn't explicitly set, it will has something like ll-cc
360
     * according to current locale. which may causes FcLangDifferentTerritory
361
     * at FcLangCompare(). thus, the English name is selected so that
362
     * exact matched "en" has higher score than ll-cc.
363
     */
364
66
    v2.type = FcTypeString;
365
66
    v2.u.s = (FcChar8 *)"en-us";
366
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FAMILYLANG_OBJECT)) {
367
66
  FcPatternObjectAdd (pattern, FC_FAMILYLANG_OBJECT, namelang, FcTrue);
368
66
  FcPatternObjectAddWithBinding (pattern, FC_FAMILYLANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
369
66
    }
370
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_STYLELANG_OBJECT)) {
371
66
  FcPatternObjectAdd (pattern, FC_STYLELANG_OBJECT, namelang, FcTrue);
372
66
  FcPatternObjectAddWithBinding (pattern, FC_STYLELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
373
66
    }
374
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FULLNAMELANG_OBJECT)) {
375
66
  FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue);
376
66
  FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
377
66
    }
378
379
66
    if (FcPatternObjectGet (pattern, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) {
380
0
  FcChar8 *prgname = FcConfigGetPrgname (config);
381
0
  if (prgname)
382
0
      FcPatternObjectAddString (pattern, FC_PRGNAME_OBJECT, prgname);
383
0
    }
384
385
66
    if (FcPatternObjectGet (pattern, FC_DESKTOP_NAME_OBJECT, 0, &v) == FcResultNoMatch) {
386
66
  FcChar8 *desktop = FcConfigGetDesktopName (config);
387
66
  if (desktop)
388
0
      FcPatternObjectAddString (pattern, FC_DESKTOP_NAME_OBJECT, desktop);
389
66
    }
390
391
66
    if (!FcPatternFindObjectIter (pattern, &iter, FC_ORDER_OBJECT))
392
66
  FcPatternObjectAddInteger (pattern, FC_ORDER_OBJECT, 0);
393
394
66
    FcConfigDestroy (config);
395
66
}
396
397
void
398
FcDefaultSubstitute (FcPattern *pattern)
399
66
{
400
66
    FcConfigSetDefaultSubstitute (NULL, pattern);
401
66
}
402
#define __fcdefault__
403
#include "fcaliastail.h"
404
#undef __fcdefault__