Coverage Report

Created: 2025-07-23 08:13

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