2 * fontconfig/src/fccfg.c
4 * Copyright © 2000 Keith Packard
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.
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.
25 /* Objects MT-safe for readonly access. */
31 #include <sys/types.h>
33 #if defined (_WIN32) && !defined (R_OK)
37 #if defined(_WIN32) && !defined(S_ISFIFO)
41 static FcConfig *_fcConfig; /* MT-safe */
42 static FcMutex *_lock;
49 lock = fc_atomic_ptr_get (&_lock);
52 lock = (FcMutex *) malloc (sizeof (FcMutex));
54 if (!fc_atomic_ptr_cmpexch (&_lock, NULL, lock))
61 /* Initialize random state */
72 lock = fc_atomic_ptr_get (&_lock);
80 lock = fc_atomic_ptr_get (&_lock);
81 if (lock && fc_atomic_ptr_cmpexch (&_lock, lock, NULL))
93 config = fc_atomic_ptr_get (&_fcConfig);
96 config = FcInitLoadConfigAndFonts ();
98 if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
100 FcConfigDestroy (config);
108 FcDestroyAsRule (void *data)
110 FcRuleDestroy (data);
114 FcDestroyAsRuleSet (void *data)
116 FcRuleSetDestroy (data);
122 return FcConfigEnsure () ? FcTrue : FcFalse;
128 FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
129 if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
130 FcConfigDestroy (cfg);
135 FcConfigCreate (void)
140 FcBool err = FcFalse;
142 config = malloc (sizeof (FcConfig));
146 config->configDirs = FcStrSetCreate ();
147 if (!config->configDirs)
150 config->configMapDirs = FcStrSetCreate();
151 if (!config->configMapDirs)
154 config->configFiles = FcStrSetCreate ();
155 if (!config->configFiles)
158 config->fontDirs = FcStrSetCreate ();
159 if (!config->fontDirs)
162 config->acceptGlobs = FcStrSetCreate ();
163 if (!config->acceptGlobs)
166 config->rejectGlobs = FcStrSetCreate ();
167 if (!config->rejectGlobs)
170 config->acceptPatterns = FcFontSetCreate ();
171 if (!config->acceptPatterns)
174 config->rejectPatterns = FcFontSetCreate ();
175 if (!config->rejectPatterns)
178 config->cacheDirs = FcStrSetCreate ();
179 if (!config->cacheDirs)
182 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
184 config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet);
185 if (!config->subst[k])
191 config->maxObjects = 0;
192 for (set = FcSetSystem; set <= FcSetApplication; set++)
193 config->fonts[set] = 0;
195 config->rescanTime = time(0);
196 config->rescanInterval = 30;
198 config->expr_pool = NULL;
200 config->sysRoot = FcStrRealPath ((const FcChar8 *) getenv("FONTCONFIG_SYSROOT"));
202 config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet);
203 if (!config->rulesetList)
205 config->availConfigFiles = FcStrSetCreate ();
206 if (!config->availConfigFiles)
209 FcRefInit (&config->ref, 1);
214 FcPtrListDestroy (config->rulesetList);
216 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
217 if (config->subst[k])
218 FcPtrListDestroy (config->subst[k]);
219 FcStrSetDestroy (config->cacheDirs);
221 FcFontSetDestroy (config->rejectPatterns);
223 FcFontSetDestroy (config->acceptPatterns);
225 FcStrSetDestroy (config->rejectGlobs);
227 FcStrSetDestroy (config->acceptGlobs);
229 FcStrSetDestroy (config->fontDirs);
231 FcStrSetDestroy (config->configFiles);
233 FcStrSetDestroy (config->configMapDirs);
235 FcStrSetDestroy (config->configDirs);
243 FcConfigNewestFile (FcStrSet *files)
245 FcStrList *list = FcStrListCreate (files);
246 FcFileTime newest = { 0, FcFalse };
252 while ((file = FcStrListNext (list)))
253 if (FcStat (file, &statb) == 0)
254 if (!newest.set || statb.st_mtime - newest.time > 0)
257 newest.time = statb.st_mtime;
259 FcStrListDone (list);
265 FcConfigUptoDate (FcConfig *config)
267 FcFileTime config_time, config_dir_time, font_time;
268 time_t now = time(0);
271 config = FcConfigReference (config);
275 config_time = FcConfigNewestFile (config->configFiles);
276 config_dir_time = FcConfigNewestFile (config->configDirs);
277 font_time = FcConfigNewestFile (config->fontDirs);
278 if ((config_time.set && config_time.time - config->rescanTime > 0) ||
279 (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
280 (font_time.set && (font_time.time - config->rescanTime) > 0))
282 /* We need to check for potential clock problems here (OLPC ticket #6046) */
283 if ((config_time.set && (config_time.time - now) > 0) ||
284 (config_dir_time.set && (config_dir_time.time - now) > 0) ||
285 (font_time.set && (font_time.time - now) > 0))
288 "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
289 config->rescanTime = now;
298 config->rescanTime = now;
300 FcConfigDestroy (config);
306 FcConfigAllocExpr (FcConfig *config)
308 if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
310 FcExprPage *new_page;
312 new_page = malloc (sizeof (FcExprPage));
316 new_page->next_page = config->expr_pool;
317 new_page->next = new_page->exprs;
318 config->expr_pool = new_page;
321 return config->expr_pool->next++;
325 FcConfigReference (FcConfig *config)
329 /* lock during obtaining the value from _fcConfig and count up refcount there,
330 * there are the race between them.
334 config = fc_atomic_ptr_get (&_fcConfig);
339 config = FcInitLoadConfigAndFonts ();
343 if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
345 FcConfigDestroy (config);
349 FcRefInc (&config->ref);
353 FcRefInc (&config->ref);
359 FcConfigDestroy (FcConfig *config)
367 if (FcRefDec (&config->ref) != 1)
370 (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
372 FcStrSetDestroy (config->configDirs);
373 FcStrSetDestroy (config->configMapDirs);
374 FcStrSetDestroy (config->fontDirs);
375 FcStrSetDestroy (config->cacheDirs);
376 FcStrSetDestroy (config->configFiles);
377 FcStrSetDestroy (config->acceptGlobs);
378 FcStrSetDestroy (config->rejectGlobs);
379 FcFontSetDestroy (config->acceptPatterns);
380 FcFontSetDestroy (config->rejectPatterns);
382 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
383 FcPtrListDestroy (config->subst[k]);
384 FcPtrListDestroy (config->rulesetList);
385 FcStrSetDestroy (config->availConfigFiles);
386 for (set = FcSetSystem; set <= FcSetApplication; set++)
387 if (config->fonts[set])
388 FcFontSetDestroy (config->fonts[set]);
390 page = config->expr_pool;
393 FcExprPage *next = page->next_page;
398 FcStrFree (config->sysRoot);
405 * Add cache to configuration, adding fonts and directories
409 FcConfigAddCache (FcConfig *config, FcCache *cache,
410 FcSetName set, FcStrSet *dirSet, FcChar8 *forDir)
415 FcBool relocated = FcFalse;
417 if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0)
423 fs = FcCacheSet (cache);
428 for (i = 0; i < fs->nfont; i++)
430 FcPattern *font = FcFontSetFont (fs, i);
432 FcChar8 *relocated_font_file = NULL;
434 if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
435 0, &font_file) == FcResultMatch)
439 FcChar8 *slash = FcStrLastSlash (font_file);
440 relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL);
441 font_file = relocated_font_file;
445 * Check to see if font is banned by filename
447 if (!FcConfigAcceptFilename (config, font_file))
449 free (relocated_font_file);
455 * Check to see if font is banned by pattern
457 if (!FcConfigAcceptFont (config, font))
459 free (relocated_font_file);
463 if (relocated_font_file)
465 font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
466 free (relocated_font_file);
469 if (FcFontSetAdd (config->fonts[set], font))
472 FcDirCacheReference (cache, nref);
478 dirs = FcCacheDirs (cache);
481 for (i = 0; i < cache->dirs_count; i++)
483 const FcChar8 *dir = FcCacheSubdir (cache, i);
488 FcChar8 *base = FcStrBasename (dir);
489 dir = s = FcStrBuildFilename (forDir, base, NULL);
492 if (FcConfigAcceptFilename (config, dir))
493 FcStrSetAddFilename (dirSet, dir);
502 FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
508 dirlist = FcStrListCreate (dirSet);
512 while ((dir = FcStrListNext (dirlist)))
514 if (FcDebug () & FC_DBG_FONTSET)
515 printf ("adding fonts from %s\n", dir);
516 cache = FcDirCacheRead (dir, FcFalse, config);
519 FcConfigAddCache (config, cache, set, dirSet, dir);
520 FcDirCacheUnload (cache);
522 FcStrListDone (dirlist);
527 * Scan the current list of directories in the configuration
528 * and build the set of available fonts.
532 FcConfigBuildFonts (FcConfig *config)
537 config = FcConfigReference (config);
541 fonts = FcFontSetCreate ();
548 FcConfigSetFonts (config, fonts, FcSetSystem);
550 if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
555 if (FcDebug () & FC_DBG_FONTSET)
556 FcFontSetPrint (fonts);
558 FcConfigDestroy (config);
564 FcConfigSetCurrent (FcConfig *config)
570 if (!config->fonts[FcSetSystem])
571 if (!FcConfigBuildFonts (config))
573 FcRefInc (&config->ref);
578 cfg = fc_atomic_ptr_get (&_fcConfig);
584 FcConfigDestroy (config);
588 if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
592 FcConfigDestroy (cfg);
598 FcConfigGetCurrent (void)
600 return FcConfigEnsure ();
604 FcConfigAddConfigDir (FcConfig *config,
607 return FcStrSetAddFilename (config->configDirs, d);
611 FcConfigGetConfigDirs (FcConfig *config)
615 config = FcConfigReference (config);
618 ret = FcStrListCreate (config->configDirs);
619 FcConfigDestroy (config);
625 FcConfigAddFontDir (FcConfig *config,
630 if (FcDebug() & FC_DBG_CACHE)
634 printf ("%s -> %s%s%s%s\n", d, m, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : "");
638 printf ("%s%s%s%s\n", d, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : "");
641 return FcStrSetAddFilenamePairWithSalt (config->fontDirs, d, m, salt);
645 FcConfigResetFontDirs (FcConfig *config)
647 if (FcDebug() & FC_DBG_CACHE)
649 printf ("Reset font directories!\n");
651 return FcStrSetDeleteAll (config->fontDirs);
655 FcConfigGetFontDirs (FcConfig *config)
659 config = FcConfigReference (config);
662 ret = FcStrListCreate (config->fontDirs);
663 FcConfigDestroy (config);
669 FcConfigPathStartsWith(const FcChar8 *path,
670 const FcChar8 *start)
672 int len = strlen((char *) start);
674 if (strncmp((char *) path, (char *) start, len) != 0)
679 case FC_DIR_SEPARATOR:
687 FcConfigMapFontPath(FcConfig *config,
692 const FcChar8 *map, *rpath;
695 list = FcConfigGetFontDirs(config);
698 while ((dir = FcStrListNext(list)))
699 if (FcConfigPathStartsWith(path, dir))
704 map = FcStrTripleSecond(dir);
707 rpath = path + strlen ((char *) dir);
708 while (*rpath == '/')
710 retval = FcStrBuildFilename(map, rpath, NULL);
713 size_t len = strlen ((const char *) retval);
714 while (len > 0 && retval[len-1] == '/')
716 /* trim the last slash */
723 FcConfigMapSalt (FcConfig *config,
729 list = FcConfigGetFontDirs (config);
732 while ((dir = FcStrListNext (list)))
733 if (FcConfigPathStartsWith (path, dir))
735 FcStrListDone (list);
739 return FcStrTripleThird (dir);
743 FcConfigAddCacheDir (FcConfig *config,
746 return FcStrSetAddFilename (config->cacheDirs, d);
750 FcConfigGetCacheDirs (FcConfig *config)
754 config = FcConfigReference (config);
757 ret = FcStrListCreate (config->cacheDirs);
758 FcConfigDestroy (config);
764 FcConfigAddConfigFile (FcConfig *config,
768 FcChar8 *file = FcConfigGetFilename (config, f);
773 ret = FcStrSetAdd (config->configFiles, file);
779 FcConfigGetConfigFiles (FcConfig *config)
783 config = FcConfigReference (config);
786 ret = FcStrListCreate (config->configFiles);
787 FcConfigDestroy (config);
793 FcConfigGetCache (FcConfig *config FC_UNUSED)
799 FcConfigGetFonts (FcConfig *config,
804 config = FcConfigGetCurrent ();
808 return config->fonts[set];
812 FcConfigSetFonts (FcConfig *config,
816 if (config->fonts[set])
817 FcFontSetDestroy (config->fonts[set]);
818 config->fonts[set] = fonts;
823 FcBlanksCreate (void)
830 FcBlanksDestroy (FcBlanks *b FC_UNUSED)
836 FcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
843 FcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
850 FcConfigGetBlanks (FcConfig *config FC_UNUSED)
857 FcConfigAddBlank (FcConfig *config FC_UNUSED,
858 FcChar32 blank FC_UNUSED)
866 FcConfigGetRescanInterval (FcConfig *config)
870 config = FcConfigReference (config);
873 ret = config->rescanInterval;
874 FcConfigDestroy (config);
880 FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
882 config = FcConfigReference (config);
885 config->rescanInterval = rescanInterval;
886 FcConfigDestroy (config);
892 * A couple of typos escaped into the library
895 FcConfigGetRescanInverval (FcConfig *config)
897 return FcConfigGetRescanInterval (config);
901 FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
903 return FcConfigSetRescanInterval (config, rescanInterval);
907 FcConfigAddRule (FcConfig *config,
916 FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
921 v.type = FcTypeDouble;
922 v.u.d = (double) v.u.i;
925 if (u.type == FcTypeRange && buf)
927 v.u.r = FcRangePromote (v.u.d, buf);
928 v.type = FcTypeRange;
932 if (u.type == FcTypeMatrix)
934 v.u.m = &FcIdentityMatrix;
935 v.type = FcTypeMatrix;
937 else if (u.type == FcTypeLangSet && buf)
939 v.u.l = FcLangSetPromote (NULL, buf);
940 v.type = FcTypeLangSet;
942 else if (u.type == FcTypeCharSet && buf)
944 v.u.c = FcCharSetPromote (buf);
945 v.type = FcTypeCharSet;
949 if (u.type == FcTypeLangSet && buf)
951 v.u.l = FcLangSetPromote (v.u.s, buf);
952 v.type = FcTypeLangSet;
962 FcConfigCompareValue (const FcValue *left_o,
964 const FcValue *right_o)
968 FcBool ret = FcFalse;
969 FcOp op = FC_OP_GET_OP (op_);
970 int flags = FC_OP_GET_FLAGS (op_);
971 FcValuePromotionBuffer buf1, buf2;
973 if (left_o->type != right_o->type)
975 left = FcValueCanonicalize(left_o);
976 right = FcValueCanonicalize(right_o);
977 left = FcConfigPromote (left, right, &buf1);
978 right = FcConfigPromote (right, left, &buf2);
981 if (left_o->type != right_o->type)
983 if (op == FcOpNotEqual || op == FcOpNotContains)
988 switch (left_o->type) {
990 break; /* No way to guess how to compare for this object */
991 case FcTypeInteger: {
993 int r = right_o->u.i;
1001 case FcOpNotContains:
1021 case FcTypeDouble: {
1022 double l = left_o->u.d;
1023 double r = right_o->u.d;
1031 case FcOpNotContains:
1052 FcBool l = left_o->u.b;
1053 FcBool r = right_o->u.b;
1060 ret = l == r || l >= FcDontCare;
1065 case FcOpNotContains:
1066 ret = !(l == r || l >= FcDontCare);
1069 ret = l != r && r >= FcDontCare;
1072 ret = l == r || r >= FcDontCare;
1075 ret = l != r && l >= FcDontCare;
1078 ret = l == r || l >= FcDontCare;
1085 case FcTypeString: {
1086 const FcChar8 *l = FcValueString (left_o);
1087 const FcChar8 *r = FcValueString (right_o);
1091 if (flags & FcOpFlagIgnoreBlanks)
1092 ret = FcStrCmpIgnoreBlanksAndCase (l, r) == 0;
1094 ret = FcStrCmpIgnoreCase (l, r) == 0;
1097 ret = FcStrStrIgnoreCase (l, r) != 0;
1100 if (flags & FcOpFlagIgnoreBlanks)
1101 ret = FcStrCmpIgnoreBlanksAndCase (l, r) != 0;
1103 ret = FcStrCmpIgnoreCase (l, r) != 0;
1105 case FcOpNotContains:
1106 ret = FcStrStrIgnoreCase (l, r) == 0;
1113 case FcTypeMatrix: {
1118 ret = FcMatrixEqual (left_o->u.m, right_o->u.m);
1121 case FcOpNotContains:
1122 ret = !FcMatrixEqual (left_o->u.m, right_o->u.m);
1129 case FcTypeCharSet: {
1130 const FcCharSet *l = FcValueCharSet (left_o);
1131 const FcCharSet *r = FcValueCharSet (right_o);
1135 /* left contains right if right is a subset of left */
1136 ret = FcCharSetIsSubset (r, l);
1138 case FcOpNotContains:
1139 /* left contains right if right is a subset of left */
1140 ret = !FcCharSetIsSubset (r, l);
1143 ret = FcCharSetEqual (l, r);
1146 ret = !FcCharSetEqual (l, r);
1153 case FcTypeLangSet: {
1154 const FcLangSet *l = FcValueLangSet (left_o);
1155 const FcLangSet *r = FcValueLangSet (right_o);
1159 ret = FcLangSetContains (l, r);
1161 case FcOpNotContains:
1162 ret = !FcLangSetContains (l, r);
1165 ret = FcLangSetEqual (l, r);
1168 ret = !FcLangSetEqual (l, r);
1191 ret = left_o->u.f == right_o->u.f;
1194 case FcOpNotContains:
1195 ret = left_o->u.f != right_o->u.f;
1202 const FcRange *l = FcValueRange (left_o);
1203 const FcRange *r = FcValueRange (right_o);
1204 ret = FcRangeCompare (op, l, r);
1212 #define _FcDoubleFloor(d) ((int) (d))
1213 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
1214 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
1215 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
1216 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
1217 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
1220 FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
1222 FcValue v, vl, vr, vle, vre;
1225 FcOp op = FC_OP_GET_OP (e->op);
1226 FcValuePromotionBuffer buf1, buf2;
1230 v.type = FcTypeInteger;
1234 v.type = FcTypeDouble;
1238 v.type = FcTypeString;
1240 v = FcValueSave (v);
1245 FcValue xx, xy, yx, yy;
1246 v.type = FcTypeMatrix;
1247 xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
1248 xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
1249 yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
1250 yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
1251 if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
1252 yx.type == FcTypeDouble && yy.type == FcTypeDouble)
1261 v.type = FcTypeVoid;
1262 v = FcValueSave (v);
1266 v.type = FcTypeCharSet;
1268 v = FcValueSave (v);
1271 v.type = FcTypeLangSet;
1273 v = FcValueSave (v);
1276 v.type = FcTypeRange;
1278 v = FcValueSave (v);
1281 v.type = FcTypeBool;
1285 if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
1287 if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
1288 v.type = FcTypeVoid;
1290 else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
1293 "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
1294 v.type = FcTypeVoid;
1298 if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
1299 v.type = FcTypeVoid;
1301 v = FcValueSave (v);
1304 if (FcNameConstant (e->u.constant, &v.u.i))
1305 v.type = FcTypeInteger;
1307 v.type = FcTypeVoid;
1310 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1311 if (vl.type == FcTypeBool)
1314 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
1316 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
1319 v.type = FcTypeVoid;
1320 FcValueDestroy (vl);
1329 case FcOpNotContains:
1331 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1332 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1333 v.type = FcTypeBool;
1334 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
1335 FcValueDestroy (vl);
1336 FcValueDestroy (vr);
1344 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1345 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1346 vle = FcConfigPromote (vl, vr, &buf1);
1347 vre = FcConfigPromote (vr, vle, &buf2);
1348 if (vle.type == vre.type)
1350 switch ((int) vle.type) {
1354 v.type = FcTypeDouble;
1355 v.u.d = vle.u.d + vre.u.d;
1358 v.type = FcTypeDouble;
1359 v.u.d = vle.u.d - vre.u.d;
1362 v.type = FcTypeDouble;
1363 v.u.d = vle.u.d * vre.u.d;
1366 v.type = FcTypeDouble;
1367 v.u.d = vle.u.d / vre.u.d;
1370 v.type = FcTypeVoid;
1373 if (v.type == FcTypeDouble &&
1374 v.u.d == (double) (int) v.u.d)
1376 v.type = FcTypeInteger;
1377 v.u.i = (int) v.u.d;
1383 v.type = FcTypeBool;
1384 v.u.b = vle.u.b || vre.u.b;
1387 v.type = FcTypeBool;
1388 v.u.b = vle.u.b && vre.u.b;
1391 v.type = FcTypeVoid;
1398 v.type = FcTypeString;
1399 str = FcStrPlus (vle.u.s, vre.u.s);
1400 v.u.s = FcStrdup (str);
1404 v.type = FcTypeVoid;
1407 v.type = FcTypeVoid;
1414 v.type = FcTypeMatrix;
1415 m = malloc (sizeof (FcMatrix));
1418 FcMatrixMultiply (m, vle.u.m, vre.u.m);
1423 v.type = FcTypeVoid;
1427 v.type = FcTypeVoid;
1434 v.type = FcTypeCharSet;
1435 v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
1437 v.type = FcTypeVoid;
1440 v.type = FcTypeCharSet;
1441 v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
1443 v.type = FcTypeVoid;
1446 v.type = FcTypeVoid;
1453 v.type = FcTypeLangSet;
1454 v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
1456 v.type = FcTypeVoid;
1459 v.type = FcTypeLangSet;
1460 v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
1462 v.type = FcTypeVoid;
1465 v.type = FcTypeVoid;
1470 v.type = FcTypeVoid;
1475 v.type = FcTypeVoid;
1476 FcValueDestroy (vl);
1477 FcValueDestroy (vr);
1480 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1481 switch ((int) vl.type) {
1483 v.type = FcTypeBool;
1487 v.type = FcTypeVoid;
1490 FcValueDestroy (vl);
1493 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1494 switch ((int) vl.type) {
1499 v.type = FcTypeInteger;
1500 v.u.i = FcDoubleFloor (vl.u.d);
1503 v.type = FcTypeVoid;
1506 FcValueDestroy (vl);
1509 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1510 switch ((int) vl.type) {
1515 v.type = FcTypeInteger;
1516 v.u.i = FcDoubleCeil (vl.u.d);
1519 v.type = FcTypeVoid;
1522 FcValueDestroy (vl);
1525 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1526 switch ((int) vl.type) {
1531 v.type = FcTypeInteger;
1532 v.u.i = FcDoubleRound (vl.u.d);
1535 v.type = FcTypeVoid;
1538 FcValueDestroy (vl);
1541 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1542 switch ((int) vl.type) {
1547 v.type = FcTypeInteger;
1548 v.u.i = FcDoubleTrunc (vl.u.d);
1551 v.type = FcTypeVoid;
1554 FcValueDestroy (vl);
1557 v.type = FcTypeVoid;
1563 /* The bulk of the time in FcConfigSubstitute is spent walking
1564 * lists of family names. We speed this up with a hash table.
1565 * Since we need to take the ignore-blanks option into account,
1566 * we use two separate hash tables.
1576 FcHashTable *family_blank_hash;
1577 FcHashTable *family_hash;
1581 FamilyTableLookup (FamilyTable *table,
1585 FamilyTableEntry *fe;
1586 int flags = FC_OP_GET_FLAGS (_op);
1589 if (flags & FcOpFlagIgnoreBlanks)
1590 hash = table->family_blank_hash;
1592 hash = table->family_hash;
1594 return FcHashTableFind (hash, (const void *)s, (void **)&fe);
1598 FamilyTableAdd (FamilyTable *table,
1599 FcValueListPtr values)
1602 for (ll = values; ll; ll = FcValueListNext (ll))
1604 const FcChar8 *s = FcValueString (&ll->value);
1605 FamilyTableEntry *fe;
1607 if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe))
1609 fe = malloc (sizeof (FamilyTableEntry));
1611 FcHashTableAdd (table->family_hash, (void *)s, fe);
1615 if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe))
1617 fe = malloc (sizeof (FamilyTableEntry));
1619 FcHashTableAdd (table->family_blank_hash, (void *)s, fe);
1626 FamilyTableDel (FamilyTable *table,
1629 FamilyTableEntry *fe;
1631 if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe))
1635 FcHashTableRemove (table->family_hash, (void *)s);
1638 if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe))
1642 FcHashTableRemove (table->family_blank_hash, (void *)s);
1647 copy_string (const void *src, void **dest)
1649 *dest = strdup ((char *)src);
1654 FamilyTableInit (FamilyTable *table,
1659 table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
1660 (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
1661 (FcCopyFunc)copy_string,
1665 table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase,
1666 (FcCompareFunc)FcStrCmpIgnoreCase,
1667 (FcCopyFunc)copy_string,
1671 e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT);
1673 FamilyTableAdd (table, FcPatternEltValues (e));
1677 FamilyTableClear (FamilyTable *table)
1679 if (table->family_blank_hash)
1680 FcHashTableDestroy (table->family_blank_hash);
1681 if (table->family_hash)
1682 FcHashTableDestroy (table->family_hash);
1685 static FcValueList *
1686 FcConfigMatchValueList (FcPattern *p,
1690 FcValueList *values,
1693 FcValueList *ret = 0;
1694 FcExpr *e = t->expr;
1701 /* Compute the value of the match expression */
1702 if (FC_OP_GET_OP (e->op) == FcOpComma)
1704 value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1705 e = e->u.tree.right;
1709 value = FcConfigEvaluate (p, p_pat, kind, e);
1713 if (t->object == FC_FAMILY_OBJECT && table)
1715 op = FC_OP_GET_OP (t->op);
1716 if (op == FcOpEqual || op == FcOpListing)
1718 if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
1724 if (op == FcOpNotEqual && t->qual == FcQualAll)
1727 if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
1734 for (v = values; v; v = FcValueListNext(v))
1736 /* Compare the pattern value to the match expression value */
1737 if (FcConfigCompareValue (&v->value, t->op, &value))
1741 if (t->qual != FcQualAll)
1746 if (t->qual == FcQualAll)
1754 FcValueDestroy (value);
1759 static FcValueList *
1760 FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
1766 l = (FcValueList *) malloc (sizeof (FcValueList));
1769 if (FC_OP_GET_OP (e->op) == FcOpComma)
1771 l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1772 l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
1776 l->value = FcConfigEvaluate (p, p_pat, kind, e);
1779 l->binding = binding;
1780 if (l->value.type == FcTypeVoid)
1782 FcValueList *next = FcValueListNext(l);
1792 FcConfigAdd (FcValueListPtr *head,
1793 FcValueList *position,
1799 FcValueListPtr *prev, l, last, v;
1800 FcValueBinding sameBinding;
1803 * Make sure the stored type is valid for built-in objects
1805 for (l = new; l != NULL; l = FcValueListNext (l))
1807 if (!FcObjectValidType (object, l->value.type))
1810 "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1811 FcValuePrintFile (stderr, l->value);
1812 fprintf (stderr, "\n");
1814 if (FcDebug () & FC_DBG_EDIT)
1816 printf ("Not adding\n");
1823 if (object == FC_FAMILY_OBJECT && table)
1825 FamilyTableAdd (table, new);
1829 sameBinding = position->binding;
1831 sameBinding = FcValueBindingWeak;
1832 for (v = new; v != NULL; v = FcValueListNext(v))
1833 if (v->binding == FcValueBindingSame)
1834 v->binding = sameBinding;
1838 prev = &position->next;
1840 for (prev = head; *prev != NULL;
1841 prev = &(*prev)->next)
1848 for (prev = head; *prev != NULL;
1849 prev = &(*prev)->next)
1851 if (*prev == position)
1858 if (FcDebug () & FC_DBG_EDIT)
1861 printf ("position not on list\n");
1865 if (FcDebug () & FC_DBG_EDIT)
1867 printf ("%s list before ", append ? "Append" : "Prepend");
1868 FcValueListPrintWithPosition (*head, *prev);
1875 while (last->next != NULL)
1882 if (FcDebug () & FC_DBG_EDIT)
1884 printf ("%s list after ", append ? "Append" : "Prepend");
1885 FcValueListPrint (*head);
1893 FcConfigDel (FcValueListPtr *head,
1894 FcValueList *position,
1898 FcValueListPtr *prev;
1900 if (object == FC_FAMILY_OBJECT && table)
1902 FamilyTableDel (table, FcValueString (&position->value));
1905 for (prev = head; *prev != NULL; prev = &(*prev)->next)
1907 if (*prev == position)
1909 *prev = position->next;
1910 position->next = NULL;
1911 FcValueListDestroy (position);
1918 FcConfigPatternAdd (FcPattern *p,
1926 FcPatternElt *e = FcPatternObjectInsertElt (p, object);
1930 FcConfigAdd (&e->values, 0, append, list, object, table);
1935 * Delete all values associated with a field
1938 FcConfigPatternDel (FcPattern *p,
1942 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1945 while (e->values != NULL)
1946 FcConfigDel (&e->values, e->values, object, table);
1950 FcConfigPatternCanon (FcPattern *p,
1953 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1956 if (e->values == NULL)
1957 FcPatternObjectDel (p, object);
1961 FcConfigSubstituteWithPat (FcConfig *config,
1968 FcPtrListIter iter, iter2;
1971 FcValueList *l, **value = NULL, *vl;
1974 FcObject object = FC_INVALID_OBJECT;
1975 FcPatternElt **elt = NULL, *e;
1977 FcBool retval = FcTrue;
1978 FcTest **tst = NULL;
1980 FamilyTable *table = &data;
1982 if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
1985 config = FcConfigReference (config);
1989 s = config->subst[kind];
1990 if (kind == FcMatchPattern)
1992 strs = FcGetDefaultLangs ();
1995 FcStrList *l = FcStrListCreate (strs);
1998 FcLangSet *lsund = FcLangSetCreate ();
2000 FcLangSetAdd (lsund, (const FcChar8 *)"und");
2001 FcStrSetDestroy (strs);
2002 while (l && (lang = FcStrListNext (l)))
2004 FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
2010 for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
2012 FcValue vv = FcValueCanonicalize (&ll->value);
2014 if (vv.type == FcTypeLangSet)
2016 FcLangSet *ls = FcLangSetCreate ();
2019 FcLangSetAdd (ls, lang);
2020 b = FcLangSetContains (vv.u.l, ls);
2021 FcLangSetDestroy (ls);
2024 if (FcLangSetContains (vv.u.l, lsund))
2029 if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
2031 if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
2036 v.type = FcTypeString;
2039 FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
2043 FcLangSetDestroy (lsund);
2045 if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
2047 FcChar8 *prgname = FcGetPrgname ();
2049 FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
2053 nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
2054 value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs);
2060 elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs);
2066 tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs);
2073 if (FcDebug () & FC_DBG_EDIT)
2075 printf ("FcConfigSubstitute ");
2079 FamilyTableInit (&data, p);
2081 FcPtrListIterInit (s, &iter);
2082 for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
2084 rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter);
2085 if (FcDebug () & FC_DBG_EDIT)
2087 printf ("\nRule Set: %s\n", rs->name);
2089 FcPtrListIterInit (rs->subst[kind], &iter2);
2090 for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2))
2092 r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2);
2093 for (i = 0; i < nobjs; i++)
2099 for (; r; r = r->next)
2103 /* shouldn't be reached */
2106 object = FC_OBJ_ID (r->u.test->object);
2108 * Check the tests to see if
2109 * they all match the pattern
2111 if (FcDebug () & FC_DBG_EDIT)
2113 printf ("FcConfigSubstitute test ");
2114 FcTestPrint (r->u.test);
2116 if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
2127 e = FcPatternObjectFindElt (m, r->u.test->object);
2130 /* different 'kind' won't be the target of edit */
2131 if (!elt[object] && kind == r->u.test->kind)
2134 tst[object] = r->u.test;
2137 * If there's no such field in the font,
2138 * then FcQualAll matches while FcQualAny does not
2142 if (r->u.test->qual == FcQualAll)
2144 value[object] = NULL;
2149 if (FcDebug () & FC_DBG_EDIT)
2150 printf ("No match\n");
2155 * Check to see if there is a match, mark the location
2156 * to apply match-relative edits
2158 vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table);
2159 /* different 'kind' won't be the target of edit */
2160 if (!value[object] && kind == r->u.test->kind)
2163 (r->u.test->qual == FcQualFirst && vl != e->values) ||
2164 (r->u.test->qual == FcQualNotFirst && vl == e->values))
2166 if (FcDebug () & FC_DBG_EDIT)
2167 printf ("No match\n");
2172 object = FC_OBJ_ID (r->u.edit->object);
2173 if (FcDebug () & FC_DBG_EDIT)
2175 printf ("Substitute ");
2176 FcEditPrint (r->u.edit);
2180 * Evaluate the list of expressions
2182 l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding);
2183 if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
2184 elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
2186 switch (FC_OP_GET_OP (r->u.edit->op)) {
2189 * If there was a test, then replace the matched
2190 * value with the new list of values
2194 FcValueList *thisValue = value[object];
2195 FcValueList *nextValue = l;
2198 * Append the new list of values after the current value
2200 FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table);
2202 * Delete the marked value
2205 FcConfigDel (&elt[object]->values, thisValue, object, table);
2207 * Adjust a pointer into the value list to ensure
2208 * future edits occur at the same place
2210 value[object] = nextValue;
2213 /* fall through ... */
2214 case FcOpAssignReplace:
2216 * Delete all of the values and insert
2219 FcConfigPatternDel (p, r->u.edit->object, table);
2220 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
2222 * Adjust a pointer into the value list as they no
2223 * longer point to anything valid
2225 value[object] = NULL;
2230 FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table);
2233 /* fall through ... */
2234 case FcOpPrependFirst:
2235 FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table);
2240 FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table);
2243 /* fall through ... */
2244 case FcOpAppendLast:
2245 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
2250 FcConfigDel (&elt[object]->values, value[object], object, table);
2251 FcValueListDestroy (l);
2254 /* fall through ... */
2256 FcConfigPatternDel (p, r->u.edit->object, table);
2257 FcValueListDestroy (l);
2260 FcValueListDestroy (l);
2264 * Now go through the pattern and eliminate
2265 * any properties without data
2267 FcConfigPatternCanon (p, r->u.edit->object);
2269 if (FcDebug () & FC_DBG_EDIT)
2271 printf ("FcConfigSubstitute edit");
2280 if (FcDebug () & FC_DBG_EDIT)
2282 printf ("FcConfigSubstitute done");
2286 FamilyTableClear (&data);
2293 FcConfigDestroy (config);
2299 FcConfigSubstitute (FcConfig *config,
2303 return FcConfigSubstituteWithPat (config, p, 0, kind);
2306 #if defined (_WIN32)
2308 static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
2309 FcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
2311 # if (defined (PIC) || defined (DLL_EXPORT))
2314 DllMain (HINSTANCE hinstDLL,
2316 LPVOID lpvReserved);
2319 DllMain (HINSTANCE hinstDLL,
2325 switch (fdwReason) {
2326 case DLL_PROCESS_ATTACH:
2327 if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
2328 sizeof (fontconfig_path)))
2331 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
2332 * assume it's a Unix-style installation tree, and use
2333 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
2334 * folder where the DLL is as FONTCONFIG_PATH.
2336 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
2340 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
2341 if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
2342 FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
2344 strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
2345 strcat ((char *) fontconfig_path, "\\etc\\fonts");
2348 fontconfig_path[0] = '\0';
2358 #undef FONTCONFIG_PATH
2359 #define FONTCONFIG_PATH fontconfig_path
2361 #endif /* !_WIN32 */
2363 #ifndef FONTCONFIG_FILE
2364 #define FONTCONFIG_FILE "fonts.conf"
2368 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
2374 dir = (FcChar8 *) "";
2376 osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
2378 * workaround valgrind warning because glibc takes advantage of how it knows memory is
2379 * allocated to implement strlen by reading in groups of 4
2381 size = (osize + 3) & ~3;
2383 path = malloc (size);
2387 strcpy ((char *) path, (const char *) dir);
2388 /* make sure there's a single separator */
2390 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
2391 path[strlen((char *) path)-1] != '\\')) &&
2394 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
2395 strcat ((char *) path, "\\");
2397 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
2398 strcat ((char *) path, "/");
2402 strcat ((char *) path, (char *) file);
2404 if (access ((char *) path, R_OK) == 0)
2413 FcConfigGetPath (void)
2416 FcChar8 *env, *e, *colon;
2421 npath = 2; /* default dir + null */
2422 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
2428 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
2431 path = calloc (npath, sizeof (FcChar8 *));
2441 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
2443 colon = e + strlen ((char *) e);
2444 path[i] = malloc (colon - e + 1);
2447 strncpy ((char *) path[i], (const char *) e, colon - e);
2448 path[i][colon - e] = '\0';
2458 if (fontconfig_path[0] == '\0')
2461 if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
2463 p = strrchr ((const char *) fontconfig_path, '\\');
2465 strcat ((char *) fontconfig_path, "\\fonts");
2468 dir = (FcChar8 *) FONTCONFIG_PATH;
2469 path[i] = malloc (strlen ((char *) dir) + 1);
2472 strcpy ((char *) path[i], (const char *) dir);
2476 for (i = 0; path[i]; i++)
2484 FcConfigFreePath (FcChar8 **path)
2488 for (p = path; *p; p++)
2493 static FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
2498 if (_FcConfigHomeEnabled)
2500 char *home = getenv ("HOME");
2504 home = getenv ("USERPROFILE");
2507 return (FcChar8 *) home;
2513 FcConfigXdgCacheHome (void)
2515 const char *env = getenv ("XDG_CACHE_HOME");
2516 FcChar8 *ret = NULL;
2518 if (!_FcConfigHomeEnabled)
2521 ret = FcStrCopy ((const FcChar8 *)env);
2524 const FcChar8 *home = FcConfigHome ();
2525 size_t len = home ? strlen ((const char *)home) : 0;
2527 ret = malloc (len + 7 + 1);
2531 memcpy (ret, home, len);
2532 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
2541 FcConfigXdgConfigHome (void)
2543 const char *env = getenv ("XDG_CONFIG_HOME");
2544 FcChar8 *ret = NULL;
2546 if (!_FcConfigHomeEnabled)
2549 ret = FcStrCopy ((const FcChar8 *)env);
2552 const FcChar8 *home = FcConfigHome ();
2553 size_t len = home ? strlen ((const char *)home) : 0;
2555 ret = malloc (len + 8 + 1);
2559 memcpy (ret, home, len);
2560 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
2569 FcConfigXdgDataHome (void)
2571 const char *env = getenv ("XDG_DATA_HOME");
2572 FcChar8 *ret = NULL;
2574 if (!_FcConfigHomeEnabled)
2577 ret = FcStrCopy ((const FcChar8 *)env);
2580 const FcChar8 *home = FcConfigHome ();
2581 size_t len = home ? strlen ((const char *)home) : 0;
2583 ret = malloc (len + 13 + 1);
2587 memcpy (ret, home, len);
2588 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
2597 FcConfigXdgDataDirs (void)
2599 const char *env = getenv ("XDG_DATA_DIRS");
2600 FcStrSet *ret = FcStrSetCreate ();
2604 FcChar8 *ee, *e = ee = FcStrCopy ((const FcChar8 *) env);
2606 /* We don't intentionally use FC_SEARCH_PATH_SEPARATOR here because of:
2607 * The directories in $XDG_DATA_DIRS should be seperated with a colon ':'.
2612 FcChar8 *p = (FcChar8 *) strchr ((const char *) e, ':');
2627 len = strlen ((const char *) s);
2628 if (s[len - 1] == FC_DIR_SEPARATOR)
2634 while (len > 1 && s[len - 1] == FC_DIR_SEPARATOR);
2637 FcStrSetAdd (ret, s);
2644 /* From spec doc at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
2646 * If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.
2648 FcStrSetAdd (ret, (const FcChar8 *) "/usr/local/share");
2649 FcStrSetAdd (ret, (const FcChar8 *) "/usr/share");
2656 FcConfigEnableHome (FcBool enable)
2658 FcBool prev = _FcConfigHomeEnabled;
2659 _FcConfigHomeEnabled = enable;
2664 FcConfigGetFilename (FcConfig *config,
2667 FcChar8 *file, *dir, **path, **p;
2668 const FcChar8 *sysroot;
2670 config = FcConfigReference (config);
2673 sysroot = FcConfigGetSysRoot (config);
2676 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
2678 url = (FcChar8 *) FONTCONFIG_FILE;
2682 if (FcStrIsAbsoluteFilename(url))
2686 size_t len = strlen ((const char *) sysroot);
2688 /* Workaround to avoid adding sysroot repeatedly */
2689 if (strncmp ((const char *) url, (const char *) sysroot, len) == 0)
2692 file = FcConfigFileExists (sysroot, url);
2698 dir = FcConfigHome ();
2704 s = FcStrBuildFilename (sysroot, dir, NULL);
2707 file = FcConfigFileExists (s, url + 1);
2716 path = FcConfigGetPath ();
2722 for (p = path; *p; p++)
2727 s = FcStrBuildFilename (sysroot, *p, NULL);
2730 file = FcConfigFileExists (s, url);
2736 FcConfigFreePath (path);
2739 FcConfigDestroy (config);
2745 FcConfigFilename (const FcChar8 *url)
2747 return FcConfigGetFilename (NULL, url);
2751 FcConfigRealFilename (FcConfig *config,
2754 FcChar8 *n = FcConfigGetFilename (config, url);
2758 FcChar8 buf[FC_PATH_MAX];
2762 if ((len = FcReadLink (n, buf, sizeof (buf) - 1)) != -1)
2766 /* We try to pick up a config from FONTCONFIG_FILE
2767 * when url is null. don't try to address the real filename
2768 * if it is a named pipe.
2770 if (!url && FcStat (n, &sb) == 0 && S_ISFIFO (sb.st_mode))
2772 else if (!FcStrIsAbsoluteFilename (buf))
2774 FcChar8 *dirname = FcStrDirname (n);
2779 FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL);
2780 FcStrFree (dirname);
2784 n = FcStrCanonFilename (path);
2799 * Manage the application-specific fonts
2803 FcConfigAppFontAddFile (FcConfig *config,
2804 const FcChar8 *file)
2810 FcBool ret = FcTrue;
2812 config = FcConfigReference (config);
2816 subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
2823 set = FcConfigGetFonts (config, FcSetApplication);
2826 set = FcFontSetCreate ();
2829 FcStrSetDestroy (subdirs);
2833 FcConfigSetFonts (config, set, FcSetApplication);
2836 if (!FcFileScanConfig (set, subdirs, file, config))
2838 FcStrSetDestroy (subdirs);
2842 if ((sublist = FcStrListCreate (subdirs)))
2844 while ((subdir = FcStrListNext (sublist)))
2846 FcConfigAppFontAddDir (config, subdir);
2848 FcStrListDone (sublist);
2850 FcStrSetDestroy (subdirs);
2852 FcConfigDestroy (config);
2858 FcConfigAppFontAddDir (FcConfig *config,
2863 FcBool ret = FcTrue;
2865 config = FcConfigReference (config);
2869 dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
2876 set = FcConfigGetFonts (config, FcSetApplication);
2879 set = FcFontSetCreate ();
2882 FcStrSetDestroy (dirs);
2886 FcConfigSetFonts (config, set, FcSetApplication);
2889 FcStrSetAddFilename (dirs, dir);
2891 if (!FcConfigAddDirList (config, FcSetApplication, dirs))
2893 FcStrSetDestroy (dirs);
2897 FcStrSetDestroy (dirs);
2899 FcConfigDestroy (config);
2905 FcConfigAppFontClear (FcConfig *config)
2907 config = FcConfigReference (config);
2911 FcConfigSetFonts (config, 0, FcSetApplication);
2913 FcConfigDestroy (config);
2917 * Manage filename-based font source selectors
2921 FcConfigGlobAdd (FcConfig *config,
2922 const FcChar8 *glob,
2925 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
2926 FcChar8 *realglob = FcStrCopyFilename(glob);
2930 FcBool ret = FcStrSetAdd (set, realglob);
2931 FcStrFree(realglob);
2936 FcConfigGlobsMatch (const FcStrSet *globs,
2937 const FcChar8 *string)
2941 for (i = 0; i < globs->num; i++)
2942 if (FcStrGlobMatch (globs->strs[i], string))
2948 FcConfigAcceptFilename (FcConfig *config,
2949 const FcChar8 *filename)
2951 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2953 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2959 * Manage font-pattern based font source selectors
2963 FcConfigPatternsAdd (FcConfig *config,
2967 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
2969 return FcFontSetAdd (set, pattern);
2973 FcConfigPatternsMatch (const FcFontSet *patterns,
2974 const FcPattern *font)
2978 for (i = 0; i < patterns->nfont; i++)
2979 if (FcListPatternMatchAny (patterns->fonts[i], font))
2985 FcConfigAcceptFont (FcConfig *config,
2986 const FcPattern *font)
2988 if (FcConfigPatternsMatch (config->acceptPatterns, font))
2990 if (FcConfigPatternsMatch (config->rejectPatterns, font))
2996 FcConfigGetSysRoot (const FcConfig *config)
3000 config = FcConfigGetCurrent ();
3004 return config->sysRoot;
3008 FcConfigSetSysRoot (FcConfig *config,
3009 const FcChar8 *sysroot)
3012 FcBool init = FcFalse;
3018 /* We can't use FcConfigGetCurrent() here to ensure
3019 * the sysroot is set prior to initialize FcConfig,
3020 * to avoid loading caches from non-sysroot dirs.
3021 * So postpone the initialization later.
3023 config = fc_atomic_ptr_get (&_fcConfig);
3026 config = FcConfigCreate ();
3035 s = FcStrRealPath (sysroot);
3040 if (config->sysRoot)
3041 FcStrFree (config->sysRoot);
3043 config->sysRoot = s;
3046 config = FcInitLoadOwnConfigAndFonts (config);
3049 /* Something failed. this is usually unlikely. so retrying */
3053 fprintf (stderr, "Fontconfig warning: Unable to initialize config and retry limit exceeded. sysroot functionality may not work as expected.\n");
3058 FcConfigSetCurrent (config);
3059 /* FcConfigSetCurrent() increases the refcount.
3060 * decrease it here to avoid the memory leak.
3062 FcConfigDestroy (config);
3067 FcRuleSetCreate (const FcChar8 *name)
3069 FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet));
3074 p = (const FcChar8 *)"";
3080 ret->name = FcStrdup (p);
3081 ret->description = NULL;
3083 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3084 ret->subst[k] = FcPtrListCreate (FcDestroyAsRule);
3085 FcRefInit (&ret->ref, 1);
3092 FcRuleSetDestroy (FcRuleSet *rs)
3098 if (FcRefDec (&rs->ref) != 1)
3102 FcStrFree (rs->name);
3103 if (rs->description)
3104 FcStrFree (rs->description);
3106 FcStrFree (rs->domain);
3107 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3108 FcPtrListDestroy (rs->subst[k]);
3114 FcRuleSetReference (FcRuleSet *rs)
3116 if (!FcRefIsConst (&rs->ref))
3117 FcRefInc (&rs->ref);
3121 FcRuleSetEnable (FcRuleSet *rs,
3127 /* XXX: we may want to provide a feature
3128 * to enable/disable rulesets through API
3135 FcRuleSetAddDescription (FcRuleSet *rs,
3136 const FcChar8 *domain,
3137 const FcChar8 *description)
3140 FcStrFree (rs->domain);
3141 if (rs->description)
3142 FcStrFree (rs->description);
3144 rs->domain = domain ? FcStrdup (domain) : NULL;
3145 rs->description = description ? FcStrdup (description) : NULL;
3149 FcRuleSetAdd (FcRuleSet *rs,
3158 kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
3160 FcPtrListIterInitAtLast (rs->subst[kind], &iter);
3161 if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule))
3164 for (r = rule; r; r = r->next)
3171 if (r->u.test->kind == FcMatchDefault)
3172 r->u.test->kind = kind;
3173 if (n < r->u.test->object)
3174 n = r->u.test->object;
3178 if (n < r->u.edit->object)
3179 n = r->u.edit->object;
3185 if (FcDebug () & FC_DBG_EDIT)
3187 printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name);
3190 ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
3192 return ret < 0 ? 0 : ret;
3196 FcConfigFileInfoIterInit (FcConfig *config,
3197 FcConfigFileInfoIter *iter)
3200 FcPtrListIter *i = (FcPtrListIter *)iter;
3203 c = FcConfigGetCurrent ();
3206 FcPtrListIterInit (c->rulesetList, i);
3210 FcConfigFileInfoIterNext (FcConfig *config,
3211 FcConfigFileInfoIter *iter)
3214 FcPtrListIter *i = (FcPtrListIter *)iter;
3217 c = FcConfigGetCurrent ();
3220 if (FcPtrListIterIsValid (c->rulesetList, i))
3222 FcPtrListIterNext (c->rulesetList, i);
3231 FcConfigFileInfoIterGet (FcConfig *config,
3232 FcConfigFileInfoIter *iter,
3234 FcChar8 **description,
3239 FcPtrListIter *i = (FcPtrListIter *)iter;
3242 c = FcConfigGetCurrent ();
3245 if (!FcPtrListIterIsValid (c->rulesetList, i))
3247 r = FcPtrListIterGetValue (c->rulesetList, i);
3249 *name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf");
3251 *description = FcStrdup (!r->description ? _("No description") :
3252 dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf",
3253 (const char *) r->description));
3255 *enabled = r->enabled;
3261 #include "fcaliastail.h"