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. */
29 #include <sys/types.h>
30 #include "../fc-blanks/fcblanks.h"
32 #if defined (_WIN32) && !defined (R_OK)
36 static FcConfig *_fcConfig; /* MT-safe */
43 config = fc_atomic_ptr_get (&_fcConfig);
46 config = FcInitLoadConfigAndFonts ();
48 if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
49 FcConfigDestroy (config);
59 return FcConfigEnsure () ? FcTrue : FcFalse;
65 FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
66 if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
67 FcConfigDestroy (cfg);
77 config = malloc (sizeof (FcConfig));
81 config->configDirs = FcStrSetCreate ();
82 if (!config->configDirs)
85 config->configFiles = FcStrSetCreate ();
86 if (!config->configFiles)
89 config->fontDirs = FcStrSetCreate ();
90 if (!config->fontDirs)
93 config->acceptGlobs = FcStrSetCreate ();
94 if (!config->acceptGlobs)
97 config->rejectGlobs = FcStrSetCreate ();
98 if (!config->rejectGlobs)
101 config->acceptPatterns = FcFontSetCreate ();
102 if (!config->acceptPatterns)
105 config->rejectPatterns = FcFontSetCreate ();
106 if (!config->rejectPatterns)
109 config->cacheDirs = FcStrSetCreate ();
110 if (!config->cacheDirs)
113 config->blanks = &fcBlanks;
115 config->substPattern = 0;
116 config->substFont = 0;
117 config->substScan = 0;
118 config->maxObjects = 0;
119 for (set = FcSetSystem; set <= FcSetApplication; set++)
120 config->fonts[set] = 0;
122 config->rescanTime = time(0);
123 config->rescanInterval = 30;
125 config->expr_pool = NULL;
127 config->sysRoot = NULL;
129 FcRefInit (&config->ref, 1);
134 FcFontSetDestroy (config->rejectPatterns);
136 FcFontSetDestroy (config->acceptPatterns);
138 FcStrSetDestroy (config->rejectGlobs);
140 FcStrSetDestroy (config->acceptGlobs);
142 FcStrSetDestroy (config->fontDirs);
144 FcStrSetDestroy (config->configFiles);
146 FcStrSetDestroy (config->configDirs);
154 FcConfigNewestFile (FcStrSet *files)
156 FcStrList *list = FcStrListCreate (files);
157 FcFileTime newest = { 0, FcFalse };
163 while ((file = FcStrListNext (list)))
164 if (FcStat (file, &statb) == 0)
165 if (!newest.set || statb.st_mtime - newest.time > 0)
168 newest.time = statb.st_mtime;
170 FcStrListDone (list);
176 FcConfigUptoDate (FcConfig *config)
178 FcFileTime config_time, config_dir_time, font_time;
179 time_t now = time(0);
182 config = FcConfigGetCurrent ();
186 config_time = FcConfigNewestFile (config->configFiles);
187 config_dir_time = FcConfigNewestFile (config->configDirs);
188 font_time = FcConfigNewestFile (config->fontDirs);
189 if ((config_time.set && config_time.time - config->rescanTime > 0) ||
190 (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
191 (font_time.set && (font_time.time - config->rescanTime) > 0))
193 /* We need to check for potential clock problems here (OLPC ticket #6046) */
194 if ((config_time.set && (config_time.time - now) > 0) ||
195 (config_dir_time.set && (config_dir_time.time - now) > 0) ||
196 (font_time.set && (font_time.time - now) > 0))
199 "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
200 config->rescanTime = now;
206 config->rescanTime = now;
211 FcSubstDestroy (FcSubst *s)
219 FcRuleDestroy (s->rule);
226 FcConfigAllocExpr (FcConfig *config)
228 if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
230 FcExprPage *new_page;
232 new_page = malloc (sizeof (FcExprPage));
236 new_page->next_page = config->expr_pool;
237 new_page->next = new_page->exprs;
238 config->expr_pool = new_page;
241 return config->expr_pool->next++;
245 FcConfigReference (FcConfig *config)
249 config = FcConfigGetCurrent ();
254 FcRefInc (&config->ref);
260 FcConfigDestroy (FcConfig *config)
265 if (FcRefDec (&config->ref) != 1)
268 (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
270 FcStrSetDestroy (config->configDirs);
271 FcStrSetDestroy (config->fontDirs);
272 FcStrSetDestroy (config->cacheDirs);
273 FcStrSetDestroy (config->configFiles);
274 FcStrSetDestroy (config->acceptGlobs);
275 FcStrSetDestroy (config->rejectGlobs);
276 FcFontSetDestroy (config->acceptPatterns);
277 FcFontSetDestroy (config->rejectPatterns);
280 FcBlanksDestroy (config->blanks);
282 FcSubstDestroy (config->substPattern);
283 FcSubstDestroy (config->substFont);
284 FcSubstDestroy (config->substScan);
285 for (set = FcSetSystem; set <= FcSetApplication; set++)
286 if (config->fonts[set])
287 FcFontSetDestroy (config->fonts[set]);
289 page = config->expr_pool;
292 FcExprPage *next = page->next_page;
297 FcStrFree (config->sysRoot);
303 * Add cache to configuration, adding fonts and directories
307 FcConfigAddCache (FcConfig *config, FcCache *cache,
308 FcSetName set, FcStrSet *dirSet)
317 fs = FcCacheSet (cache);
322 for (i = 0; i < fs->nfont; i++)
324 FcPattern *font = FcFontSetFont (fs, i);
328 * Check to see if font is banned by filename
330 if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
331 0, &font_file) == FcResultMatch &&
332 !FcConfigAcceptFilename (config, font_file))
338 * Check to see if font is banned by pattern
340 if (!FcConfigAcceptFont (config, font))
343 if (FcFontSetAdd (config->fonts[set], font))
346 FcDirCacheReference (cache, nref);
352 dirs = FcCacheDirs (cache);
355 for (i = 0; i < cache->dirs_count; i++)
357 FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
358 if (FcConfigAcceptFilename (config, dir))
359 FcStrSetAddFilename (dirSet, dir);
366 FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
371 FcBool ret = FcFalse;
373 dirlist = FcStrListCreate (dirSet);
377 while ((dir = FcStrListNext (dirlist)))
379 if (FcDebug () & FC_DBG_FONTSET)
380 printf ("adding fonts from %s\n", dir);
381 cache = FcDirCacheRead (dir, FcFalse, config);
384 FcConfigAddCache (config, cache, set, dirSet);
385 FcDirCacheUnload (cache);
388 FcStrListDone (dirlist);
393 * Scan the current list of directories in the configuration
394 * and build the set of available fonts.
398 FcConfigBuildFonts (FcConfig *config)
404 config = FcConfigGetCurrent ();
409 fonts = FcFontSetCreate ();
413 FcConfigSetFonts (config, fonts, FcSetSystem);
415 if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
417 if (FcDebug () & FC_DBG_FONTSET)
418 FcFontSetPrint (fonts);
423 FcConfigSetCurrent (FcConfig *config)
428 cfg = fc_atomic_ptr_get (&_fcConfig);
433 if (config && !config->fonts[FcSetSystem])
434 if (!FcConfigBuildFonts (config))
437 if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
440 FcConfigReference (config);
442 FcConfigDestroy (cfg);
448 FcConfigGetCurrent (void)
450 return FcConfigEnsure ();
454 FcConfigAddConfigDir (FcConfig *config,
457 return FcStrSetAddFilename (config->configDirs, d);
461 FcConfigGetConfigDirs (FcConfig *config)
465 config = FcConfigGetCurrent ();
469 return FcStrListCreate (config->configDirs);
473 FcConfigAddFontDir (FcConfig *config,
476 return FcStrSetAddFilename (config->fontDirs, d);
480 FcConfigAddDir (FcConfig *config,
483 return (FcConfigAddConfigDir (config, d) &&
484 FcConfigAddFontDir (config, d));
488 FcConfigGetFontDirs (FcConfig *config)
492 config = FcConfigGetCurrent ();
496 return FcStrListCreate (config->fontDirs);
500 FcConfigAddCacheDir (FcConfig *config,
503 return FcStrSetAddFilename (config->cacheDirs, d);
507 FcConfigGetCacheDirs (const FcConfig *config)
511 config = FcConfigGetCurrent ();
515 return FcStrListCreate (config->cacheDirs);
519 FcConfigAddConfigFile (FcConfig *config,
523 FcChar8 *file = FcConfigFilename (f);
528 ret = FcStrSetAdd (config->configFiles, file);
534 FcConfigGetConfigFiles (FcConfig *config)
538 config = FcConfigGetCurrent ();
542 return FcStrListCreate (config->configFiles);
546 FcConfigGetCache (FcConfig *config FC_UNUSED)
552 FcConfigGetFonts (FcConfig *config,
557 config = FcConfigGetCurrent ();
561 return config->fonts[set];
565 FcConfigSetFonts (FcConfig *config,
569 if (config->fonts[set])
570 FcFontSetDestroy (config->fonts[set]);
571 config->fonts[set] = fonts;
575 FcConfigGetBlanks (FcConfig *config)
579 config = FcConfigGetCurrent ();
583 return config->blanks;
587 FcConfigAddBlank (FcConfig *config,
590 FcBlanks *b, *freeme = 0;
595 freeme = b = FcBlanksCreate ();
599 if (!FcBlanksAdd (b, blank))
602 FcBlanksDestroy (freeme);
610 FcConfigGetRescanInterval (FcConfig *config)
614 config = FcConfigGetCurrent ();
618 return config->rescanInterval;
622 FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
626 config = FcConfigGetCurrent ();
630 config->rescanInterval = rescanInterval;
635 * A couple of typos escaped into the library
638 FcConfigGetRescanInverval (FcConfig *config)
640 return FcConfigGetRescanInterval (config);
644 FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
646 return FcConfigSetRescanInterval (config, rescanInterval);
650 FcConfigAddRule (FcConfig *config,
654 FcSubst *subst, **prev;
662 prev = &config->substPattern;
665 prev = &config->substFont;
668 prev = &config->substScan;
673 subst = (FcSubst *) malloc (sizeof (FcSubst));
676 for (; *prev; prev = &(*prev)->next);
680 for (r = rule; r; r = r->next)
686 r->u.test->kind == FcMatchDefault)
687 r->u.test->kind = kind;
689 if (n < r->u.test->object)
690 n = r->u.test->object;
693 if (n < r->u.edit->object)
694 n = r->u.edit->object;
700 n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
701 if (config->maxObjects < n)
702 config->maxObjects = n;
703 if (FcDebug () & FC_DBG_EDIT)
705 printf ("Add Subst ");
706 FcSubstPrint (subst);
712 FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
714 if (v.type == FcTypeInteger)
716 v.type = FcTypeDouble;
717 v.u.d = (double) v.u.i;
719 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
721 v.u.m = &FcIdentityMatrix;
722 v.type = FcTypeMatrix;
724 else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
726 v.u.l = FcLangSetPromote (v.u.s, buf);
727 v.type = FcTypeLangSet;
729 else if (v.type == FcTypeVoid && u.type == FcTypeLangSet)
731 v.u.l = FcLangSetPromote (NULL, buf);
732 v.type = FcTypeLangSet;
734 else if (v.type == FcTypeVoid && u.type == FcTypeCharSet)
736 v.u.c = FcCharSetPromote (buf);
737 v.type = FcTypeCharSet;
739 if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
741 v.u.r = FcRangePromote (v.u.d, buf);
742 v.type = FcTypeRange;
748 FcConfigCompareValue (const FcValue *left_o,
750 const FcValue *right_o)
752 FcValue left = FcValueCanonicalize(left_o);
753 FcValue right = FcValueCanonicalize(right_o);
754 FcBool ret = FcFalse;
755 FcOp op = FC_OP_GET_OP (op_);
756 int flags = FC_OP_GET_FLAGS (op_);
757 FcValuePromotionBuffer buf1, buf2;
759 left = FcConfigPromote (left, right, &buf1);
760 right = FcConfigPromote (right, left, &buf2);
761 if (left.type == right.type)
765 break; /* No way to guess how to compare for this object */
767 break; /* FcConfigPromote prevents this from happening */
773 ret = left.u.d == right.u.d;
776 case FcOpNotContains:
777 ret = left.u.d != right.u.d;
780 ret = left.u.d < right.u.d;
783 ret = left.u.d <= right.u.d;
786 ret = left.u.d > right.u.d;
789 ret = left.u.d >= right.u.d;
800 ret = left.u.b == right.u.b;
803 case FcOpNotContains:
804 ret = left.u.b != right.u.b;
814 if (flags & FcOpFlagIgnoreBlanks)
815 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
817 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
820 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
823 if (flags & FcOpFlagIgnoreBlanks)
824 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
826 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
828 case FcOpNotContains:
829 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
840 ret = FcMatrixEqual (left.u.m, right.u.m);
843 case FcOpNotContains:
844 ret = !FcMatrixEqual (left.u.m, right.u.m);
854 /* left contains right if right is a subset of left */
855 ret = FcCharSetIsSubset (right.u.c, left.u.c);
857 case FcOpNotContains:
858 /* left contains right if right is a subset of left */
859 ret = !FcCharSetIsSubset (right.u.c, left.u.c);
862 ret = FcCharSetEqual (left.u.c, right.u.c);
865 ret = !FcCharSetEqual (left.u.c, right.u.c);
875 ret = FcLangSetContains (left.u.l, right.u.l);
877 case FcOpNotContains:
878 ret = !FcLangSetContains (left.u.l, right.u.l);
881 ret = FcLangSetEqual (left.u.l, right.u.l);
884 ret = !FcLangSetEqual (left.u.l, right.u.l);
906 ret = left.u.f == right.u.f;
909 case FcOpNotContains:
910 ret = left.u.f != right.u.f;
917 ret = FcRangeCompare (op, left.u.r, right.u.r);
923 if (op == FcOpNotEqual || op == FcOpNotContains)
930 #define _FcDoubleFloor(d) ((int) (d))
931 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
932 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
933 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
934 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
935 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
938 FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
940 FcValue v, vl, vr, vle, vre;
943 FcOp op = FC_OP_GET_OP (e->op);
944 FcValuePromotionBuffer buf1, buf2;
948 v.type = FcTypeInteger;
952 v.type = FcTypeDouble;
956 v.type = FcTypeString;
963 FcValue xx, xy, yx, yy;
964 v.type = FcTypeMatrix;
965 xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
966 xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
967 yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
968 yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
969 if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
970 yx.type == FcTypeDouble && yy.type == FcTypeDouble)
984 v.type = FcTypeCharSet;
989 v.type = FcTypeLangSet;
994 v.type = FcTypeRange;
1003 if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
1005 if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
1006 v.type = FcTypeVoid;
1008 else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
1011 "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
1012 v.type = FcTypeVoid;
1016 if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
1017 v.type = FcTypeVoid;
1019 v = FcValueSave (v);
1022 if (FcNameConstant (e->u.constant, &v.u.i))
1023 v.type = FcTypeInteger;
1025 v.type = FcTypeVoid;
1028 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1029 if (vl.type == FcTypeBool)
1032 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
1034 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
1037 v.type = FcTypeVoid;
1038 FcValueDestroy (vl);
1047 case FcOpNotContains:
1049 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1050 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1051 v.type = FcTypeBool;
1052 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
1053 FcValueDestroy (vl);
1054 FcValueDestroy (vr);
1062 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1063 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1064 vle = FcConfigPromote (vl, vr, &buf1);
1065 vre = FcConfigPromote (vr, vle, &buf2);
1066 if (vle.type == vre.type)
1068 switch ((int) vle.type) {
1072 v.type = FcTypeDouble;
1073 v.u.d = vle.u.d + vre.u.d;
1076 v.type = FcTypeDouble;
1077 v.u.d = vle.u.d - vre.u.d;
1080 v.type = FcTypeDouble;
1081 v.u.d = vle.u.d * vre.u.d;
1084 v.type = FcTypeDouble;
1085 v.u.d = vle.u.d / vre.u.d;
1088 v.type = FcTypeVoid;
1091 if (v.type == FcTypeDouble &&
1092 v.u.d == (double) (int) v.u.d)
1094 v.type = FcTypeInteger;
1095 v.u.i = (int) v.u.d;
1101 v.type = FcTypeBool;
1102 v.u.b = vle.u.b || vre.u.b;
1105 v.type = FcTypeBool;
1106 v.u.b = vle.u.b && vre.u.b;
1109 v.type = FcTypeVoid;
1116 v.type = FcTypeString;
1117 str = FcStrPlus (vle.u.s, vre.u.s);
1118 v.u.s = FcStrdup (str);
1122 v.type = FcTypeVoid;
1125 v.type = FcTypeVoid;
1132 v.type = FcTypeMatrix;
1133 m = malloc (sizeof (FcMatrix));
1136 FcMatrixMultiply (m, vle.u.m, vre.u.m);
1141 v.type = FcTypeVoid;
1145 v.type = FcTypeVoid;
1152 v.type = FcTypeCharSet;
1153 v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
1155 v.type = FcTypeVoid;
1158 v.type = FcTypeCharSet;
1159 v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
1161 v.type = FcTypeVoid;
1164 v.type = FcTypeVoid;
1171 v.type = FcTypeLangSet;
1172 v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
1174 v.type = FcTypeVoid;
1177 v.type = FcTypeLangSet;
1178 v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
1180 v.type = FcTypeVoid;
1183 v.type = FcTypeVoid;
1188 v.type = FcTypeVoid;
1193 v.type = FcTypeVoid;
1194 FcValueDestroy (vl);
1195 FcValueDestroy (vr);
1198 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1199 switch ((int) vl.type) {
1201 v.type = FcTypeBool;
1205 v.type = FcTypeVoid;
1208 FcValueDestroy (vl);
1211 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1212 switch ((int) vl.type) {
1217 v.type = FcTypeInteger;
1218 v.u.i = FcDoubleFloor (vl.u.d);
1221 v.type = FcTypeVoid;
1224 FcValueDestroy (vl);
1227 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1228 switch ((int) vl.type) {
1233 v.type = FcTypeInteger;
1234 v.u.i = FcDoubleCeil (vl.u.d);
1237 v.type = FcTypeVoid;
1240 FcValueDestroy (vl);
1243 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1244 switch ((int) vl.type) {
1249 v.type = FcTypeInteger;
1250 v.u.i = FcDoubleRound (vl.u.d);
1253 v.type = FcTypeVoid;
1256 FcValueDestroy (vl);
1259 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1260 switch ((int) vl.type) {
1265 v.type = FcTypeInteger;
1266 v.u.i = FcDoubleTrunc (vl.u.d);
1269 v.type = FcTypeVoid;
1272 FcValueDestroy (vl);
1275 v.type = FcTypeVoid;
1281 static FcValueList *
1282 FcConfigMatchValueList (FcPattern *p,
1286 FcValueList *values)
1288 FcValueList *ret = 0;
1289 FcExpr *e = t->expr;
1295 /* Compute the value of the match expression */
1296 if (FC_OP_GET_OP (e->op) == FcOpComma)
1298 value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1299 e = e->u.tree.right;
1303 value = FcConfigEvaluate (p, p_pat, kind, e);
1307 for (v = values; v; v = FcValueListNext(v))
1309 /* Compare the pattern value to the match expression value */
1310 if (FcConfigCompareValue (&v->value, t->op, &value))
1317 if (t->qual == FcQualAll)
1324 FcValueDestroy (value);
1329 static FcValueList *
1330 FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
1336 l = (FcValueList *) malloc (sizeof (FcValueList));
1339 if (FC_OP_GET_OP (e->op) == FcOpComma)
1341 l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1342 l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
1346 l->value = FcConfigEvaluate (p, p_pat, kind, e);
1349 l->binding = binding;
1350 if (l->value.type == FcTypeVoid)
1352 FcValueList *next = FcValueListNext(l);
1362 FcConfigAdd (FcValueListPtr *head,
1363 FcValueList *position,
1368 FcValueListPtr *prev, l, last, v;
1369 FcValueBinding sameBinding;
1372 * Make sure the stored type is valid for built-in objects
1374 for (l = new; l != NULL; l = FcValueListNext (l))
1376 if (!FcObjectValidType (object, l->value.type))
1379 "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1380 FcValuePrintFile (stderr, l->value);
1381 fprintf (stderr, "\n");
1383 if (FcDebug () & FC_DBG_EDIT)
1385 printf ("Not adding\n");
1393 sameBinding = position->binding;
1395 sameBinding = FcValueBindingWeak;
1396 for (v = new; v != NULL; v = FcValueListNext(v))
1397 if (v->binding == FcValueBindingSame)
1398 v->binding = sameBinding;
1402 prev = &position->next;
1404 for (prev = head; *prev != NULL;
1405 prev = &(*prev)->next)
1412 for (prev = head; *prev != NULL;
1413 prev = &(*prev)->next)
1415 if (*prev == position)
1422 if (FcDebug () & FC_DBG_EDIT)
1425 printf ("position not on list\n");
1429 if (FcDebug () & FC_DBG_EDIT)
1431 printf ("%s list before ", append ? "Append" : "Prepend");
1432 FcValueListPrintWithPosition (*head, *prev);
1439 while (last->next != NULL)
1446 if (FcDebug () & FC_DBG_EDIT)
1448 printf ("%s list after ", append ? "Append" : "Prepend");
1449 FcValueListPrint (*head);
1457 FcConfigDel (FcValueListPtr *head,
1458 FcValueList *position)
1460 FcValueListPtr *prev;
1462 for (prev = head; *prev != NULL; prev = &(*prev)->next)
1464 if (*prev == position)
1466 *prev = position->next;
1467 position->next = NULL;
1468 FcValueListDestroy (position);
1475 FcConfigPatternAdd (FcPattern *p,
1482 FcPatternElt *e = FcPatternObjectInsertElt (p, object);
1486 FcConfigAdd (&e->values, 0, append, list, object);
1491 * Delete all values associated with a field
1494 FcConfigPatternDel (FcPattern *p,
1497 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1500 while (e->values != NULL)
1501 FcConfigDel (&e->values, e->values);
1505 FcConfigPatternCanon (FcPattern *p,
1508 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1511 if (e->values == NULL)
1512 FcPatternObjectDel (p, object);
1516 FcConfigSubstituteWithPat (FcConfig *config,
1524 FcValueList *l, **value = NULL, *vl;
1527 FcObject object = FC_INVALID_OBJECT;
1528 FcPatternElt **elt = NULL, *e;
1530 FcBool retval = FcTrue;
1531 FcTest **tst = NULL;
1535 config = FcConfigGetCurrent ();
1541 case FcMatchPattern:
1542 s = config->substPattern;
1543 strs = FcGetDefaultLangs ();
1546 FcStrList *l = FcStrListCreate (strs);
1549 FcLangSet *lsund = FcLangSetCreate ();
1551 FcLangSetAdd (lsund, (const FcChar8 *)"und");
1552 FcStrSetDestroy (strs);
1553 while (l && (lang = FcStrListNext (l)))
1555 FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
1561 for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
1563 FcValue vv = FcValueCanonicalize (&ll->value);
1565 if (vv.type == FcTypeLangSet)
1567 FcLangSet *ls = FcLangSetCreate ();
1570 FcLangSetAdd (ls, lang);
1571 b = FcLangSetContains (vv.u.l, ls);
1572 FcLangSetDestroy (ls);
1575 if (FcLangSetContains (vv.u.l, lsund))
1580 if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
1582 if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
1587 v.type = FcTypeString;
1590 FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1594 FcLangSetDestroy (lsund);
1596 if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
1598 FcChar8 *prgname = FcGetPrgname ();
1600 FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
1604 s = config->substFont;
1607 s = config->substScan;
1613 nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
1614 value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs);
1620 elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs);
1626 tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs);
1633 if (FcDebug () & FC_DBG_EDIT)
1635 printf ("FcConfigSubstitute ");
1638 for (; s; s = s->next)
1641 for (i = 0; i < nobjs; i++)
1647 for (; r; r = r->next)
1651 /* shouldn't be reached */
1654 object = FC_OBJ_ID (r->u.test->object);
1656 * Check the tests to see if
1657 * they all match the pattern
1659 if (FcDebug () & FC_DBG_EDIT)
1661 printf ("FcConfigSubstitute test ");
1662 FcTestPrint (r->u.test);
1664 if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
1669 e = FcPatternObjectFindElt (m, r->u.test->object);
1672 /* different 'kind' won't be the target of edit */
1673 if (!elt[object] && kind == r->u.test->kind)
1676 tst[object] = r->u.test;
1679 * If there's no such field in the font,
1680 * then FcQualAll matches while FcQualAny does not
1684 if (r->u.test->qual == FcQualAll)
1686 value[object] = NULL;
1691 if (FcDebug () & FC_DBG_EDIT)
1692 printf ("No match\n");
1697 * Check to see if there is a match, mark the location
1698 * to apply match-relative edits
1700 vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
1701 /* different 'kind' won't be the target of edit */
1702 if (!value[object] && kind == r->u.test->kind)
1705 (r->u.test->qual == FcQualFirst && vl != e->values) ||
1706 (r->u.test->qual == FcQualNotFirst && vl == e->values))
1708 if (FcDebug () & FC_DBG_EDIT)
1709 printf ("No match\n");
1714 object = FC_OBJ_ID (r->u.edit->object);
1715 if (FcDebug () & FC_DBG_EDIT)
1717 printf ("Substitute ");
1718 FcEditPrint (r->u.edit);
1722 * Evaluate the list of expressions
1724 l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding);
1725 if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
1726 elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
1728 switch (FC_OP_GET_OP (r->u.edit->op)) {
1731 * If there was a test, then replace the matched
1732 * value with the new list of values
1736 FcValueList *thisValue = value[object];
1737 FcValueList *nextValue = l;
1740 * Append the new list of values after the current value
1742 FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
1744 * Delete the marked value
1747 FcConfigDel (&elt[object]->values, thisValue);
1749 * Adjust a pointer into the value list to ensure
1750 * future edits occur at the same place
1752 value[object] = nextValue;
1755 /* fall through ... */
1756 case FcOpAssignReplace:
1758 * Delete all of the values and insert
1761 FcConfigPatternDel (p, r->u.edit->object);
1762 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
1764 * Adjust a pointer into the value list as they no
1765 * longer point to anything valid
1767 value[object] = NULL;
1772 FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
1775 /* fall through ... */
1776 case FcOpPrependFirst:
1777 FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
1782 FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
1785 /* fall through ... */
1786 case FcOpAppendLast:
1787 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
1792 FcConfigDel (&elt[object]->values, value[object]);
1795 /* fall through ... */
1797 FcConfigPatternDel (p, r->u.edit->object);
1800 FcValueListDestroy (l);
1804 * Now go through the pattern and eliminate
1805 * any properties without data
1807 FcConfigPatternCanon (p, r->u.edit->object);
1809 if (FcDebug () & FC_DBG_EDIT)
1811 printf ("FcConfigSubstitute edit");
1819 if (FcDebug () & FC_DBG_EDIT)
1821 printf ("FcConfigSubstitute done");
1836 FcConfigSubstitute (FcConfig *config,
1840 return FcConfigSubstituteWithPat (config, p, 0, kind);
1843 #if defined (_WIN32)
1845 static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
1847 # if (defined (PIC) || defined (DLL_EXPORT))
1850 DllMain (HINSTANCE hinstDLL,
1852 LPVOID lpvReserved);
1855 DllMain (HINSTANCE hinstDLL,
1861 switch (fdwReason) {
1862 case DLL_PROCESS_ATTACH:
1863 if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
1864 sizeof (fontconfig_path)))
1867 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1868 * assume it's a Unix-style installation tree, and use
1869 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1870 * folder where the DLL is as FONTCONFIG_PATH.
1872 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1876 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1877 if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1878 FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
1880 strcat ((char *) fontconfig_path, "\\etc\\fonts");
1883 fontconfig_path[0] = '\0';
1893 #undef FONTCONFIG_PATH
1894 #define FONTCONFIG_PATH fontconfig_path
1896 #endif /* !_WIN32 */
1898 #ifndef FONTCONFIG_FILE
1899 #define FONTCONFIG_FILE "fonts.conf"
1903 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1909 dir = (FcChar8 *) "";
1911 osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
1913 * workaround valgrind warning because glibc takes advantage of how it knows memory is
1914 * allocated to implement strlen by reading in groups of 4
1916 size = (osize + 3) & ~3;
1918 path = malloc (size);
1922 strcpy ((char *) path, (const char *) dir);
1923 /* make sure there's a single separator */
1925 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1926 path[strlen((char *) path)-1] != '\\')) &&
1929 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1930 strcat ((char *) path, "\\");
1932 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1933 strcat ((char *) path, "/");
1937 strcat ((char *) path, (char *) file);
1939 if (access ((char *) path, R_OK) == 0)
1948 FcConfigGetPath (void)
1951 FcChar8 *env, *e, *colon;
1956 npath = 2; /* default dir + null */
1957 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1963 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1966 path = calloc (npath, sizeof (FcChar8 *));
1976 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1978 colon = e + strlen ((char *) e);
1979 path[i] = malloc (colon - e + 1);
1982 strncpy ((char *) path[i], (const char *) e, colon - e);
1983 path[i][colon - e] = '\0';
1993 if (fontconfig_path[0] == '\0')
1996 if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
1998 p = strrchr ((const char *) fontconfig_path, '\\');
2000 strcat ((char *) fontconfig_path, "\\fonts");
2003 dir = (FcChar8 *) FONTCONFIG_PATH;
2004 path[i] = malloc (strlen ((char *) dir) + 1);
2007 strcpy ((char *) path[i], (const char *) dir);
2011 for (i = 0; path[i]; i++)
2019 FcConfigFreePath (FcChar8 **path)
2023 for (p = path; *p; p++)
2028 static FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
2033 if (_FcConfigHomeEnabled)
2035 char *home = getenv ("HOME");
2039 home = getenv ("USERPROFILE");
2042 return (FcChar8 *) home;
2048 FcConfigXdgCacheHome (void)
2050 const char *env = getenv ("XDG_CACHE_HOME");
2051 FcChar8 *ret = NULL;
2053 if (!_FcConfigHomeEnabled)
2056 ret = FcStrCopy ((const FcChar8 *)env);
2059 const FcChar8 *home = FcConfigHome ();
2060 size_t len = home ? strlen ((const char *)home) : 0;
2062 ret = malloc (len + 7 + 1);
2065 memcpy (ret, home, len);
2066 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
2075 FcConfigXdgConfigHome (void)
2077 const char *env = getenv ("XDG_CONFIG_HOME");
2078 FcChar8 *ret = NULL;
2080 if (!_FcConfigHomeEnabled)
2083 ret = FcStrCopy ((const FcChar8 *)env);
2086 const FcChar8 *home = FcConfigHome ();
2087 size_t len = home ? strlen ((const char *)home) : 0;
2089 ret = malloc (len + 8 + 1);
2092 memcpy (ret, home, len);
2093 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
2102 FcConfigXdgDataHome (void)
2104 const char *env = getenv ("XDG_DATA_HOME");
2105 FcChar8 *ret = NULL;
2107 if (!_FcConfigHomeEnabled)
2110 ret = FcStrCopy ((const FcChar8 *)env);
2113 const FcChar8 *home = FcConfigHome ();
2114 size_t len = home ? strlen ((const char *)home) : 0;
2116 ret = malloc (len + 13 + 1);
2119 memcpy (ret, home, len);
2120 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
2129 FcConfigEnableHome (FcBool enable)
2131 FcBool prev = _FcConfigHomeEnabled;
2132 _FcConfigHomeEnabled = enable;
2137 FcConfigFilename (const FcChar8 *url)
2139 FcChar8 *file, *dir, **path, **p;
2143 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
2145 url = (FcChar8 *) FONTCONFIG_FILE;
2150 if (isalpha (*url) &&
2152 (url[2] == '/' || url[2] == '\\'))
2158 dir = FcConfigHome ();
2160 file = FcConfigFileExists (dir, url + 1);
2169 file = FcConfigFileExists (0, url);
2172 path = FcConfigGetPath ();
2175 for (p = path; *p; p++)
2177 file = FcConfigFileExists (*p, url);
2181 FcConfigFreePath (path);
2189 * Manage the application-specific fonts
2193 FcConfigAppFontAddFile (FcConfig *config,
2194 const FcChar8 *file)
2200 FcBool ret = FcFalse;
2204 config = FcConfigGetCurrent ();
2209 subdirs = FcStrSetCreate ();
2213 set = FcConfigGetFonts (config, FcSetApplication);
2216 set = FcFontSetCreate ();
2219 FcStrSetDestroy (subdirs);
2222 FcConfigSetFonts (config, set, FcSetApplication);
2225 if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
2227 FcStrSetDestroy (subdirs);
2230 if ((sublist = FcStrListCreate (subdirs)))
2232 while ((subdir = FcStrListNext (sublist)))
2234 if (FcConfigAppFontAddDir (config, subdir))
2237 FcStrListDone (sublist);
2239 FcStrSetDestroy (subdirs);
2244 FcConfigAppFontAddDir (FcConfig *config,
2249 FcBool ret = FcTrue;
2253 config = FcConfigGetCurrent ();
2258 dirs = FcStrSetCreate ();
2262 set = FcConfigGetFonts (config, FcSetApplication);
2265 set = FcFontSetCreate ();
2271 FcConfigSetFonts (config, set, FcSetApplication);
2274 FcStrSetAddFilename (dirs, dir);
2276 if (!FcConfigAddDirList (config, FcSetApplication, dirs))
2279 FcStrSetDestroy (dirs);
2284 FcConfigAppFontClear (FcConfig *config)
2288 config = FcConfigGetCurrent ();
2293 FcConfigSetFonts (config, 0, FcSetApplication);
2297 * Manage filename-based font source selectors
2301 FcConfigGlobAdd (FcConfig *config,
2302 const FcChar8 *glob,
2305 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
2307 return FcStrSetAdd (set, glob);
2311 FcConfigGlobsMatch (const FcStrSet *globs,
2312 const FcChar8 *string)
2316 for (i = 0; i < globs->num; i++)
2317 if (FcStrGlobMatch (globs->strs[i], string))
2323 FcConfigAcceptFilename (FcConfig *config,
2324 const FcChar8 *filename)
2326 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2328 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2334 * Manage font-pattern based font source selectors
2338 FcConfigPatternsAdd (FcConfig *config,
2342 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
2344 return FcFontSetAdd (set, pattern);
2348 FcConfigPatternsMatch (const FcFontSet *patterns,
2349 const FcPattern *font)
2353 for (i = 0; i < patterns->nfont; i++)
2354 if (FcListPatternMatchAny (patterns->fonts[i], font))
2360 FcConfigAcceptFont (FcConfig *config,
2361 const FcPattern *font)
2363 if (FcConfigPatternsMatch (config->acceptPatterns, font))
2365 if (FcConfigPatternsMatch (config->rejectPatterns, font))
2371 FcConfigGetSysRoot (const FcConfig *config)
2375 config = FcConfigGetCurrent ();
2380 return config->sysRoot;
2384 FcConfigSetSysRoot (FcConfig *config,
2385 const FcChar8 *sysroot)
2388 FcBool init = FcFalse;
2392 /* We can't use FcConfigGetCurrent() here to ensure
2393 * the sysroot is set prior to initialize FcConfig,
2394 * to avoid loading caches from non-sysroot dirs.
2395 * So postpone the initialization later.
2397 config = fc_atomic_ptr_get (&_fcConfig);
2400 config = FcConfigCreate ();
2409 s = FcStrCopyFilename (sysroot);
2414 if (config->sysRoot)
2415 FcStrFree (config->sysRoot);
2417 config->sysRoot = s;
2420 config = FcInitLoadOwnConfigAndFonts (config);
2421 FcConfigSetCurrent (config);
2422 /* FcConfigSetCurrent() increases the refcount.
2423 * decrease it here to avoid the memory leak.
2425 FcConfigDestroy (config);
2430 #include "fcaliastail.h"