Coverage Report

Created: 2026-07-10 11:04

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
603
#define NUM_FC_BOOL_DEFAULTS (int)(sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
47
48
FcStrSet *
49
FcConfigGetDefaultLangs (FcConfig *config)
50
69
{
51
69
    FcStrSet *result;
52
53
69
    if (!config) {
54
0
  config = FcConfigGetCurrent();
55
0
    }
56
69
    FcConfigReference (config);
57
69
retry:
58
69
    result = (FcStrSet *)fc_atomic_ptr_get (&config->default_langs);
59
69
    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
69
    FcConfigDestroy (config);
93
94
69
    return result;
95
69
}
96
97
FcStrSet *
98
FcGetDefaultLangs (void)
99
0
{
100
0
    return FcConfigGetDefaultLangs (NULL);
101
0
}
102
103
FcChar8 *
104
FcConfigGetDefaultLang (FcConfig *config)
105
67
{
106
67
    FcChar8 *lang;
107
108
67
    if (!config) {
109
0
  config = FcConfigGetCurrent();
110
0
    }
111
67
    FcConfigReference (config);
112
67
retry:
113
67
    lang = fc_atomic_ptr_get (&config->default_lang);
114
67
    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
67
    FcConfigDestroy (config);
124
125
67
    return lang;
126
67
}
127
128
FcChar8 *
129
FcGetDefaultLang (void)
130
0
{
131
0
    return FcConfigGetDefaultLang (NULL);
132
0
}
133
134
FcChar8 *
135
FcConfigGetPrgname (FcConfig *config)
136
67
{
137
67
    FcChar8 *prgname;
138
139
67
    if (!config) {
140
0
  config = FcConfigGetCurrent();
141
0
    }
142
67
    FcConfigReference (config);
143
67
retry:
144
67
    prgname = fc_atomic_ptr_get (&config->prgname);
145
67
    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
67
    if (prgname && !prgname[0]) {
230
0
  prgname = NULL;
231
0
    }
232
67
    FcConfigDestroy (config);
233
234
67
    return prgname;
235
67
}
236
237
FcChar8 *
238
FcGetPrgname (void)
239
0
{
240
0
    return FcConfigGetPrgname (NULL);
241
0
}
242
243
FcChar8 *
244
FcConfigGetDesktopName (FcConfig *config)
245
67
{
246
67
    FcChar8 *desktop_name;
247
248
67
    if (!config) {
249
0
  config = FcConfigGetCurrent();
250
0
    }
251
67
    FcConfigReference (config);
252
67
retry:
253
67
    desktop_name = fc_atomic_ptr_get (&config->desktop_name);
254
67
    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
67
    if (desktop_name && !desktop_name[0]) {
273
67
  desktop_name = NULL;
274
67
    }
275
67
    FcConfigDestroy (config);
276
277
67
    return desktop_name;
278
67
}
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
67
{
290
67
    FcPatternIter iter;
291
67
    FcValue       v, namelang, v2;
292
67
    int           i;
293
67
    double        dpi, size, scale, pixelsize;
294
295
67
    config = FcConfigReference (config);
296
297
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_WEIGHT_OBJECT))
298
0
  FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_NORMAL);
299
300
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_SLANT_OBJECT))
301
0
  FcPatternObjectAddInteger (pattern, FC_SLANT_OBJECT, FC_SLANT_ROMAN);
302
303
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_WIDTH_OBJECT))
304
0
  FcPatternObjectAddInteger (pattern, FC_WIDTH_OBJECT, FC_WIDTH_NORMAL);
305
306
603
    for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
307
536
  if (!FcPatternFindObjectIter (pattern, &iter, FcBoolDefaults[i].field))
308
536
      FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
309
310
67
    if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch) {
311
67
  FcRange *r;
312
67
  double   b, e;
313
67
  if (FcPatternObjectGetRange (pattern, FC_SIZE_OBJECT, 0, &r) == FcResultMatch && FcRangeGetDouble (r, &b, &e))
314
0
      size = (b + e) * .5;
315
67
  else
316
67
      size = 12.0L;
317
67
    }
318
67
    if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
319
67
  scale = 1.0;
320
67
    if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
321
67
  dpi = 75.0;
322
323
67
    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
67
    } else {
332
67
  FcPatternIterGetValue (pattern, &iter, 0, &v, NULL);
333
67
  if (v.type == FcTypeInteger)
334
0
      size = (double)v.u.i;
335
67
  else
336
67
      size = v.u.d;
337
67
  size = size / dpi * 72.0 / scale;
338
67
    }
339
67
    (void)FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
340
67
    FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
341
342
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FONTVERSION_OBJECT))
343
67
  FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff);
344
345
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_HINT_STYLE_OBJECT))
346
67
  FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL);
347
348
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_NAMELANG_OBJECT))
349
67
  FcPatternObjectAddString (pattern, FC_NAMELANG_OBJECT, FcConfigGetDefaultLang (config));
350
351
    /* shouldn't be failed. */
352
67
    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
67
    v2.type = FcTypeString;
365
67
    v2.u.s = (FcChar8 *)"en-us";
366
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FAMILYLANG_OBJECT)) {
367
67
  FcPatternObjectAdd (pattern, FC_FAMILYLANG_OBJECT, namelang, FcTrue);
368
67
  FcPatternObjectAddWithBinding (pattern, FC_FAMILYLANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
369
67
    }
370
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_STYLELANG_OBJECT)) {
371
67
  FcPatternObjectAdd (pattern, FC_STYLELANG_OBJECT, namelang, FcTrue);
372
67
  FcPatternObjectAddWithBinding (pattern, FC_STYLELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
373
67
    }
374
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FULLNAMELANG_OBJECT)) {
375
67
  FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue);
376
67
  FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
377
67
    }
378
379
67
    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
67
    if (FcPatternObjectGet (pattern, FC_DESKTOP_NAME_OBJECT, 0, &v) == FcResultNoMatch) {
386
67
  FcChar8 *desktop = FcConfigGetDesktopName (config);
387
67
  if (desktop)
388
0
      FcPatternObjectAddString (pattern, FC_DESKTOP_NAME_OBJECT, desktop);
389
67
    }
390
391
67
    if (!FcPatternFindObjectIter (pattern, &iter, FC_ORDER_OBJECT))
392
67
  FcPatternObjectAddInteger (pattern, FC_ORDER_OBJECT, 0);
393
394
67
    FcConfigDestroy (config);
395
67
}
396
397
void
398
FcDefaultSubstitute (FcPattern *pattern)
399
67
{
400
67
    FcConfigSetDefaultSubstitute (NULL, pattern);
401
67
}
402
#define __fcdefault__
403
#include "fcaliastail.h"
404
#undef __fcdefault__