Coverage Report

Created: 2026-03-31 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/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
1.33M
#define NUM_FC_BOOL_DEFAULTS (int)(sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
47
48
FcStrSet *
49
FcConfigGetDefaultLangs (FcConfig *config)
50
148k
{
51
148k
    FcStrSet *result;
52
53
148k
    if (!config) {
54
0
  config = FcConfigGetCurrent();
55
0
    }
56
148k
    FcConfigReference (config);
57
148k
retry:
58
148k
    result = (FcStrSet *)fc_atomic_ptr_get (&config->default_langs);
59
148k
    if (!result) {
60
11
  char *langs;
61
62
11
  result = FcStrSetCreate();
63
64
11
  langs = getenv ("FC_LANG");
65
11
  if (!langs || !langs[0])
66
11
      langs = getenv ("LC_ALL");
67
11
  if (!langs || !langs[0]) {
68
11
      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
11
      if (langs && (FcStrCmpIgnoreCase ((const FcChar8 *)langs,
73
0
                                        (const FcChar8 *)"UTF-8") == 0)) {
74
0
    langs = NULL;
75
0
      }
76
11
  }
77
11
  if (!langs || !langs[0])
78
11
      langs = getenv ("LANG");
79
11
  if (langs && langs[0]) {
80
0
      if (!FcStrSetAddLangs (result, langs))
81
0
    FcStrSetAdd (result, (const FcChar8 *)"en");
82
0
  } else
83
11
      FcStrSetAdd (result, (const FcChar8 *)"en");
84
85
11
  FcRefSetConst (&result->ref);
86
11
  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
11
    }
92
148k
    FcConfigDestroy (config);
93
94
148k
    return result;
95
148k
}
96
97
FcStrSet *
98
FcGetDefaultLangs (void)
99
0
{
100
0
    return FcConfigGetDefaultLangs (NULL);
101
0
}
102
103
FcChar8 *
104
FcConfigGetDefaultLang (FcConfig *config)
105
148k
{
106
148k
    FcChar8 *lang;
107
108
148k
    if (!config) {
109
0
  config = FcConfigGetCurrent();
110
0
    }
111
148k
    FcConfigReference (config);
112
148k
retry:
113
148k
    lang = fc_atomic_ptr_get (&config->default_lang);
114
148k
    if (!lang) {
115
11
  FcStrSet *langs = FcConfigGetDefaultLangs (config);
116
11
  lang = FcStrCopy (langs->strs[0]);
117
118
11
  if (!fc_atomic_ptr_cmpexch (&config->default_lang, NULL, lang)) {
119
0
      free (lang);
120
0
      goto retry;
121
0
  }
122
11
    }
123
148k
    FcConfigDestroy (config);
124
125
148k
    return lang;
126
148k
}
127
128
FcChar8 *
129
FcGetDefaultLang (void)
130
0
{
131
0
    return FcConfigGetDefaultLang (NULL);
132
0
}
133
134
FcChar8 *
135
FcConfigGetPrgname (FcConfig *config)
136
148k
{
137
148k
    FcChar8 *prgname;
138
139
148k
    if (!config) {
140
0
  config = FcConfigGetCurrent();
141
0
    }
142
148k
    FcConfigReference (config);
143
148k
retry:
144
148k
    prgname = fc_atomic_ptr_get (&config->prgname);
145
148k
    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
11
  size_t size = FC_PATH_MAX;
180
11
  char  *p = NULL;
181
182
11
  while (1) {
183
11
      char   *buf = malloc (size);
184
11
      ssize_t len;
185
186
11
      if (!buf)
187
0
    break;
188
189
11
      len = readlink ("/proc/self/exe", buf, size - 1);
190
11
      if (len < 0) {
191
0
    free (buf);
192
0
    break;
193
0
      }
194
11
      if (len < size - 1) {
195
11
    buf[len] = 0;
196
11
    p = buf;
197
11
    break;
198
11
      }
199
200
0
      free (buf);
201
0
      size *= 2;
202
0
  }
203
#  else
204
  char *p = NULL;
205
#  endif
206
11
  if (p) {
207
11
      char *r = strrchr (p, '/');
208
11
      if (r)
209
11
    r++;
210
0
      else
211
0
    r = p;
212
213
11
      prgname = FcStrCopy ((const FcChar8 *)r);
214
11
  }
215
216
11
  if (!prgname)
217
0
      prgname = FcStrCopy ((const FcChar8 *)"");
218
219
11
  if (p)
220
11
      free (p);
221
11
#endif
222
223
11
  if (!fc_atomic_ptr_cmpexch (&config->prgname, NULL, prgname)) {
224
0
      free (prgname);
225
0
      goto retry;
226
0
  }
227
11
    }
228
229
148k
    if (prgname && !prgname[0]) {
230
0
  prgname = NULL;
231
0
    }
232
148k
    FcConfigDestroy (config);
233
234
148k
    return prgname;
235
148k
}
236
237
FcChar8 *
238
FcGetPrgname (void)
239
0
{
240
0
    return FcConfigGetPrgname (NULL);
241
0
}
242
243
FcChar8 *
244
FcConfigGetDesktopName (FcConfig *config)
245
148k
{
246
148k
    FcChar8 *desktop_name;
247
248
148k
    if (!config) {
249
0
  config = FcConfigGetCurrent();
250
0
    }
251
148k
    FcConfigReference (config);
252
148k
retry:
253
148k
    desktop_name = fc_atomic_ptr_get (&config->desktop_name);
254
148k
    if (!desktop_name) {
255
11
  char *s = getenv ("XDG_CURRENT_DESKTOP");
256
257
11
  if (!s)
258
11
      desktop_name = FcStrCopy ((const FcChar8 *)"");
259
0
  else
260
0
      desktop_name = FcStrCopy ((const FcChar8 *)s);
261
11
  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
11
  if (!fc_atomic_ptr_cmpexch (&config->desktop_name, NULL, desktop_name)) {
268
0
      free (desktop_name);
269
0
      goto retry;
270
0
  }
271
11
    }
272
148k
    if (desktop_name && !desktop_name[0]) {
273
148k
  desktop_name = NULL;
274
148k
    }
275
148k
    FcConfigDestroy (config);
276
277
148k
    return desktop_name;
278
148k
}
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
148k
{
290
148k
    FcPatternIter iter;
291
148k
    FcValue       v, namelang, v2;
292
148k
    int           i;
293
148k
    double        dpi, size, scale, pixelsize;
294
295
148k
    config = FcConfigReference (config);
296
297
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_WEIGHT_OBJECT))
298
133k
  FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_NORMAL);
299
300
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_SLANT_OBJECT))
301
144k
  FcPatternObjectAddInteger (pattern, FC_SLANT_OBJECT, FC_SLANT_ROMAN);
302
303
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_WIDTH_OBJECT))
304
145k
  FcPatternObjectAddInteger (pattern, FC_WIDTH_OBJECT, FC_WIDTH_NORMAL);
305
306
1.33M
    for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
307
1.19M
  if (!FcPatternFindObjectIter (pattern, &iter, FcBoolDefaults[i].field))
308
1.19M
      FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
309
310
148k
    if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch) {
311
148k
  FcRange *r;
312
148k
  double   b, e;
313
148k
  if (FcPatternObjectGetRange (pattern, FC_SIZE_OBJECT, 0, &r) == FcResultMatch && FcRangeGetDouble (r, &b, &e))
314
0
      size = (b + e) * .5;
315
148k
  else
316
148k
      size = 12.0L;
317
148k
    }
318
148k
    if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
319
148k
  scale = 1.0;
320
148k
    if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
321
148k
  dpi = 75.0;
322
323
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_PIXEL_SIZE_OBJECT)) {
324
148k
  (void)FcPatternObjectDel (pattern, FC_SCALE_OBJECT);
325
148k
  FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale);
326
148k
  pixelsize = size * scale;
327
148k
  (void)FcPatternObjectDel (pattern, FC_DPI_OBJECT);
328
148k
  FcPatternObjectAddDouble (pattern, FC_DPI_OBJECT, dpi);
329
148k
  pixelsize *= dpi / 72.0;
330
148k
  FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, pixelsize);
331
148k
    } else {
332
0
  FcPatternIterGetValue (pattern, &iter, 0, &v, NULL);
333
0
  if (v.type == FcTypeInteger)
334
0
      size = (double)v.u.i;
335
0
  else
336
0
      size = v.u.d;
337
0
  size = size / dpi * 72.0 / scale;
338
0
    }
339
148k
    (void)FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
340
148k
    FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
341
342
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FONTVERSION_OBJECT))
343
148k
  FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff);
344
345
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_HINT_STYLE_OBJECT))
346
148k
  FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL);
347
348
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_NAMELANG_OBJECT))
349
148k
  FcPatternObjectAddString (pattern, FC_NAMELANG_OBJECT, FcConfigGetDefaultLang (config));
350
351
    /* shouldn't be failed. */
352
148k
    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
148k
    v2.type = FcTypeString;
365
148k
    v2.u.s = (FcChar8 *)"en-us";
366
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FAMILYLANG_OBJECT)) {
367
148k
  FcPatternObjectAdd (pattern, FC_FAMILYLANG_OBJECT, namelang, FcTrue);
368
148k
  FcPatternObjectAddWithBinding (pattern, FC_FAMILYLANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
369
148k
    }
370
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_STYLELANG_OBJECT)) {
371
148k
  FcPatternObjectAdd (pattern, FC_STYLELANG_OBJECT, namelang, FcTrue);
372
148k
  FcPatternObjectAddWithBinding (pattern, FC_STYLELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
373
148k
    }
374
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_FULLNAMELANG_OBJECT)) {
375
148k
  FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue);
376
148k
  FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
377
148k
    }
378
379
148k
    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
148k
    if (FcPatternObjectGet (pattern, FC_DESKTOP_NAME_OBJECT, 0, &v) == FcResultNoMatch) {
386
148k
  FcChar8 *desktop = FcConfigGetDesktopName (config);
387
148k
  if (desktop)
388
0
      FcPatternObjectAddString (pattern, FC_DESKTOP_NAME_OBJECT, desktop);
389
148k
    }
390
391
148k
    if (!FcPatternFindObjectIter (pattern, &iter, FC_ORDER_OBJECT))
392
148k
  FcPatternObjectAddInteger (pattern, FC_ORDER_OBJECT, 0);
393
394
148k
    FcConfigDestroy (config);
395
148k
}
396
397
void
398
FcDefaultSubstitute (FcPattern *pattern)
399
148k
{
400
148k
    FcConfigSetDefaultSubstitute (NULL, pattern);
401
148k
}
402
#define __fcdefault__
403
#include "fcaliastail.h"
404
#undef __fcdefault__