X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ffccfg.c;h=f62e2282507c49b2c55f6e7dfd8c5b63230792c6;hb=7aa11e43ef72a5b04665c1efb407cfccc188af27;hp=d7c48e8c5811d21ae806349fb957a84461a6a3c6;hpb=2ed73cdd0f0785ca235adf7800e6e43137117a4c;p=platform%2Fupstream%2Ffontconfig.git diff --git a/src/fccfg.c b/src/fccfg.c index d7c48e8..f62e228 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -25,14 +25,65 @@ /* Objects MT-safe for readonly access. */ #include "fcint.h" +#ifdef HAVE_DIRENT_H #include +#endif #include #if defined (_WIN32) && !defined (R_OK) #define R_OK 4 #endif +#if defined(_WIN32) && !defined(S_ISFIFO) +#define S_ISFIFO(m) 0 +#endif + static FcConfig *_fcConfig; /* MT-safe */ +static FcMutex *_lock; + +static void +lock_config (void) +{ + FcMutex *lock; +retry: + lock = fc_atomic_ptr_get (&_lock); + if (!lock) + { + lock = (FcMutex *) malloc (sizeof (FcMutex)); + FcMutexInit (lock); + if (!fc_atomic_ptr_cmpexch (&_lock, NULL, lock)) + { + FcMutexFinish (lock); + free (lock); + goto retry; + } + FcMutexLock (lock); + /* Initialize random state */ + FcRandom (); + return; + } + FcMutexLock (lock); +} + +static void +unlock_config (void) +{ + FcMutex *lock; + lock = fc_atomic_ptr_get (&_lock); + FcMutexUnlock (lock); +} + +static void +free_lock (void) +{ + FcMutex *lock; + lock = fc_atomic_ptr_get (&_lock); + if (lock && fc_atomic_ptr_cmpexch (&_lock, lock, NULL)) + { + FcMutexFinish (lock); + free (lock); + } +} static FcConfig * FcConfigEnsure (void) @@ -44,26 +95,15 @@ retry: { config = FcInitLoadConfigAndFonts (); - if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { - FcConfigDestroy (config); + if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { + if (config) + FcConfigDestroy (config); goto retry; } } return config; } -static FcChar32 -FcHashAsStrIgnoreCase (const void *data) -{ - return FcStrHashIgnoreCase (data); -} - -static int -FcCompareAsStr (const void *v1, const void *v2) -{ - return FcStrCmp (v1, v2); -} - static void FcDestroyAsRule (void *data) { @@ -76,12 +116,6 @@ FcDestroyAsRuleSet (void *data) FcRuleSetDestroy (data); } -static void -FcDestroyAsStr (void *data) -{ - FcStrFree (data); -} - FcBool FcConfigInit (void) { @@ -94,9 +128,9 @@ FcConfigFini (void) FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) FcConfigDestroy (cfg); + free_lock (); } - FcConfig * FcConfigCreate (void) { @@ -113,6 +147,10 @@ FcConfigCreate (void) if (!config->configDirs) goto bail1; + config->configMapDirs = FcStrSetCreate(); + if (!config->configMapDirs) + goto bail1_5; + config->configFiles = FcStrSetCreate (); if (!config->configFiles) goto bail2; @@ -159,7 +197,7 @@ FcConfigCreate (void) config->expr_pool = NULL; - config->sysRoot = NULL; + config->sysRoot = FcStrRealPath ((const FcChar8 *) getenv("FONTCONFIG_SYSROOT")); config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet); if (!config->rulesetList) @@ -168,13 +206,6 @@ FcConfigCreate (void) if (!config->availConfigFiles) goto bail10; - config->uuid_table = FcHashTableCreate (FcHashAsStrIgnoreCase, - FcCompareAsStr, - FcHashStrCopy, - FcHashUuidCopy, - FcDestroyAsStr, - FcHashUuidFree); - FcRefInit (&config->ref, 1); return config; @@ -199,6 +230,8 @@ bail4: bail3: FcStrSetDestroy (config->configFiles); bail2: + FcStrSetDestroy (config->configMapDirs); +bail1_5: FcStrSetDestroy (config->configDirs); bail1: free (config); @@ -233,12 +266,12 @@ FcConfigUptoDate (FcConfig *config) { FcFileTime config_time, config_dir_time, font_time; time_t now = time(0); + FcBool ret = FcTrue; + + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } + return FcFalse; + config_time = FcConfigNewestFile (config->configFiles); config_dir_time = FcConfigNewestFile (config->configDirs); font_time = FcConfigNewestFile (config->fontDirs); @@ -254,13 +287,19 @@ FcConfigUptoDate (FcConfig *config) fprintf (stderr, "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); config->rescanTime = now; - return FcTrue; + goto bail; } else - return FcFalse; + { + ret = FcFalse; + goto bail; + } } config->rescanTime = now; - return FcTrue; +bail: + FcConfigDestroy (config); + + return ret; } FcExpr * @@ -287,12 +326,31 @@ FcConfigReference (FcConfig *config) { if (!config) { - config = FcConfigGetCurrent (); + /* lock during obtaining the value from _fcConfig and count up refcount there, + * there are the race between them. + */ + lock_config (); + retry: + config = fc_atomic_ptr_get (&_fcConfig); if (!config) - return 0; - } + { + unlock_config (); - FcRefInc (&config->ref); + config = FcInitLoadConfigAndFonts (); + if (!config) + goto retry; + lock_config (); + if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) + { + FcConfigDestroy (config); + goto retry; + } + } + FcRefInc (&config->ref); + unlock_config (); + } + else + FcRefInc (&config->ref); return config; } @@ -304,41 +362,43 @@ FcConfigDestroy (FcConfig *config) FcExprPage *page; FcMatchKind k; - if (FcRefDec (&config->ref) != 1) - return; - - (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); + if (config) + { + if (FcRefDec (&config->ref) != 1) + return; - FcStrSetDestroy (config->configDirs); - FcStrSetDestroy (config->fontDirs); - FcStrSetDestroy (config->cacheDirs); - FcStrSetDestroy (config->configFiles); - FcStrSetDestroy (config->acceptGlobs); - FcStrSetDestroy (config->rejectGlobs); - FcFontSetDestroy (config->acceptPatterns); - FcFontSetDestroy (config->rejectPatterns); + (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); - for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) - FcPtrListDestroy (config->subst[k]); - FcPtrListDestroy (config->rulesetList); - FcStrSetDestroy (config->availConfigFiles); - for (set = FcSetSystem; set <= FcSetApplication; set++) - if (config->fonts[set]) - FcFontSetDestroy (config->fonts[set]); + FcStrSetDestroy (config->configDirs); + FcStrSetDestroy (config->configMapDirs); + FcStrSetDestroy (config->fontDirs); + FcStrSetDestroy (config->cacheDirs); + FcStrSetDestroy (config->configFiles); + FcStrSetDestroy (config->acceptGlobs); + FcStrSetDestroy (config->rejectGlobs); + FcFontSetDestroy (config->acceptPatterns); + FcFontSetDestroy (config->rejectPatterns); - page = config->expr_pool; - while (page) - { - FcExprPage *next = page->next_page; - free (page); - page = next; - } - if (config->sysRoot) + for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) + FcPtrListDestroy (config->subst[k]); + FcPtrListDestroy (config->rulesetList); + FcStrSetDestroy (config->availConfigFiles); + for (set = FcSetSystem; set <= FcSetApplication; set++) + if (config->fonts[set]) + FcFontSetDestroy (config->fonts[set]); + + page = config->expr_pool; + while (page) + { + FcExprPage *next = page->next_page; + free (page); + page = next; + } + if (config->sysRoot) FcStrFree (config->sysRoot); - FcHashTableDestroy (config->uuid_table); - - free (config); + free (config); + } } /* @@ -364,7 +424,7 @@ FcConfigAddCache (FcConfig *config, FcCache *cache, if (fs) { int nref = 0; - + for (i = 0; i < fs->nfont; i++) { FcPattern *font = FcFontSetFont (fs, i); @@ -448,7 +508,7 @@ FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) dirlist = FcStrListCreate (dirSet); if (!dirlist) return FcFalse; - + while ((dir = FcStrListNext (dirlist))) { if (FcDebug () & FC_DBG_FONTSET) @@ -472,25 +532,32 @@ FcBool FcConfigBuildFonts (FcConfig *config) { FcFontSet *fonts; + FcBool ret = FcTrue; + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - + return FcFalse; + fonts = FcFontSetCreate (); if (!fonts) - return FcFalse; + { + ret = FcFalse; + goto bail; + } FcConfigSetFonts (config, fonts, FcSetSystem); if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) - return FcFalse; + { + ret = FcFalse; + goto bail; + } if (FcDebug () & FC_DBG_FONTSET) FcFontSetPrint (fonts); - return FcTrue; +bail: + FcConfigDestroy (config); + + return ret; } FcBool @@ -498,20 +565,29 @@ FcConfigSetCurrent (FcConfig *config) { FcConfig *cfg; + if (config) + { + if (!config->fonts[FcSetSystem]) + if (!FcConfigBuildFonts (config)) + return FcFalse; + FcRefInc (&config->ref); + } + + lock_config (); retry: cfg = fc_atomic_ptr_get (&_fcConfig); if (config == cfg) + { + unlock_config (); + if (config) + FcConfigDestroy (config); return FcTrue; - - if (config && !config->fonts[FcSetSystem]) - if (!FcConfigBuildFonts (config)) - return FcFalse; + } if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) goto retry; - - FcConfigReference (config); + unlock_config (); if (cfg) FcConfigDestroy (cfg); @@ -534,32 +610,133 @@ FcConfigAddConfigDir (FcConfig *config, FcStrList * FcConfigGetConfigDirs (FcConfig *config) { + FcStrList *ret; + + config = FcConfigReference (config); if (!config) + return NULL; + ret = FcStrListCreate (config->configDirs); + FcConfigDestroy (config); + + return ret; +} + +FcBool +FcConfigAddFontDir (FcConfig *config, + const FcChar8 *d, + const FcChar8 *m, + const FcChar8 *salt) +{ + if (FcDebug() & FC_DBG_CACHE) { - config = FcConfigGetCurrent (); - if (!config) - return 0; + if (m) + { + printf ("%s -> %s%s%s%s\n", d, m, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : ""); + } + else if (salt) + { + printf ("%s%s%s%s\n", d, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : ""); + } } - return FcStrListCreate (config->configDirs); + return FcStrSetAddFilenamePairWithSalt (config->fontDirs, d, m, salt); } FcBool -FcConfigAddFontDir (FcConfig *config, - const FcChar8 *d) +FcConfigResetFontDirs (FcConfig *config) { - return FcStrSetAddFilename (config->fontDirs, d); + if (FcDebug() & FC_DBG_CACHE) + { + printf ("Reset font directories!\n"); + } + return FcStrSetDeleteAll (config->fontDirs); } FcStrList * FcConfigGetFontDirs (FcConfig *config) { + FcStrList *ret; + + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; + return NULL; + ret = FcStrListCreate (config->fontDirs); + FcConfigDestroy (config); + + return ret; +} + +static FcBool +FcConfigPathStartsWith(const FcChar8 *path, + const FcChar8 *start) +{ + int len = strlen((char *) start); + + if (strncmp((char *) path, (char *) start, len) != 0) + return FcFalse; + + switch (path[len]) { + case '\0': + case FC_DIR_SEPARATOR: + return FcTrue; + default: + return FcFalse; } - return FcStrListCreate (config->fontDirs); +} + +FcChar8 * +FcConfigMapFontPath(FcConfig *config, + const FcChar8 *path) +{ + FcStrList *list; + FcChar8 *dir; + const FcChar8 *map, *rpath; + FcChar8 *retval; + + list = FcConfigGetFontDirs(config); + if (!list) + return 0; + while ((dir = FcStrListNext(list))) + if (FcConfigPathStartsWith(path, dir)) + break; + FcStrListDone(list); + if (!dir) + return 0; + map = FcStrTripleSecond(dir); + if (!map) + return 0; + rpath = path + strlen ((char *) dir); + while (*rpath == '/') + rpath++; + retval = FcStrBuildFilename(map, rpath, NULL); + if (retval) + { + size_t len = strlen ((const char *) retval); + while (len > 0 && retval[len-1] == '/') + len--; + /* trim the last slash */ + retval[len] = 0; + } + return retval; +} + +const FcChar8 * +FcConfigMapSalt (FcConfig *config, + const FcChar8 *path) +{ + FcStrList *list; + FcChar8 *dir; + + list = FcConfigGetFontDirs (config); + if (!list) + return NULL; + while ((dir = FcStrListNext (list))) + if (FcConfigPathStartsWith (path, dir)) + break; + FcStrListDone (list); + if (!dir) + return NULL; + + return FcStrTripleThird (dir); } FcBool @@ -570,15 +747,17 @@ FcConfigAddCacheDir (FcConfig *config, } FcStrList * -FcConfigGetCacheDirs (const FcConfig *config) +FcConfigGetCacheDirs (FcConfig *config) { + FcStrList *ret; + + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return FcStrListCreate (config->cacheDirs); + return NULL; + ret = FcStrListCreate (config->cacheDirs); + FcConfigDestroy (config); + + return ret; } FcBool @@ -586,7 +765,7 @@ FcConfigAddConfigFile (FcConfig *config, const FcChar8 *f) { FcBool ret; - FcChar8 *file = FcConfigFilename (f); + FcChar8 *file = FcConfigGetFilename (config, f); if (!file) return FcFalse; @@ -599,13 +778,15 @@ FcConfigAddConfigFile (FcConfig *config, FcStrList * FcConfigGetConfigFiles (FcConfig *config) { + FcStrList *ret; + + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return FcStrListCreate (config->configFiles); + return NULL; + ret = FcStrListCreate (config->configFiles); + FcConfigDestroy (config); + + return ret; } FcChar8 * @@ -684,25 +865,26 @@ FcConfigAddBlank (FcConfig *config FC_UNUSED, int FcConfigGetRescanInterval (FcConfig *config) { + int ret; + + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return config->rescanInterval; + return 0; + ret = config->rescanInterval; + FcConfigDestroy (config); + + return ret; } FcBool FcConfigSetRescanInterval (FcConfig *config, int rescanInterval) { + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } + return FcFalse; config->rescanInterval = rescanInterval; + FcConfigDestroy (config); + return FcTrue; } @@ -733,35 +915,45 @@ FcConfigAddRule (FcConfig *config, static FcValue FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) { - if (v.type == FcTypeInteger) - { - v.type = FcTypeDouble; - v.u.d = (double) v.u.i; - } - else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) - { - v.u.m = &FcIdentityMatrix; - v.type = FcTypeMatrix; - } - else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) - { - v.u.l = FcLangSetPromote (v.u.s, buf); - v.type = FcTypeLangSet; - } - else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet) - { - v.u.l = FcLangSetPromote (NULL, buf); - v.type = FcTypeLangSet; - } - else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet) - { - v.u.c = FcCharSetPromote (buf); - v.type = FcTypeCharSet; - } - if (buf && v.type == FcTypeDouble && u.type == FcTypeRange) - { - v.u.r = FcRangePromote (v.u.d, buf); - v.type = FcTypeRange; + switch (v.type) + { + case FcTypeInteger: + v.type = FcTypeDouble; + v.u.d = (double) v.u.i; + /* Fallthrough */ + case FcTypeDouble: + if (u.type == FcTypeRange && buf) + { + v.u.r = FcRangePromote (v.u.d, buf); + v.type = FcTypeRange; + } + break; + case FcTypeVoid: + if (u.type == FcTypeMatrix) + { + v.u.m = &FcIdentityMatrix; + v.type = FcTypeMatrix; + } + else if (u.type == FcTypeLangSet && buf) + { + v.u.l = FcLangSetPromote (NULL, buf); + v.type = FcTypeLangSet; + } + else if (u.type == FcTypeCharSet && buf) + { + v.u.c = FcCharSetPromote (buf); + v.type = FcTypeCharSet; + } + break; + case FcTypeString: + if (u.type == FcTypeLangSet && buf) + { + v.u.l = FcLangSetPromote (v.u.s, buf); + v.type = FcTypeLangSet; + } + break; + default: + break; } return v; } @@ -771,195 +963,247 @@ FcConfigCompareValue (const FcValue *left_o, unsigned int op_, const FcValue *right_o) { - FcValue left = FcValueCanonicalize(left_o); - FcValue right = FcValueCanonicalize(right_o); + FcValue left; + FcValue right; FcBool ret = FcFalse; FcOp op = FC_OP_GET_OP (op_); int flags = FC_OP_GET_FLAGS (op_); FcValuePromotionBuffer buf1, buf2; - left = FcConfigPromote (left, right, &buf1); - right = FcConfigPromote (right, left, &buf2); - if (left.type == right.type) - { - switch (left.type) { - case FcTypeUnknown: - break; /* No way to guess how to compare for this object */ - case FcTypeInteger: - break; /* FcConfigPromote prevents this from happening */ - case FcTypeDouble: - switch ((int) op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = left.u.d == right.u.d; - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = left.u.d != right.u.d; - break; - case FcOpLess: - ret = left.u.d < right.u.d; - break; - case FcOpLessEqual: - ret = left.u.d <= right.u.d; - break; - case FcOpMore: - ret = left.u.d > right.u.d; - break; - case FcOpMoreEqual: - ret = left.u.d >= right.u.d; - break; - default: - break; - } - break; - case FcTypeBool: - switch ((int) op) { - case FcOpEqual: - ret = left.u.b == right.u.b; - break; - case FcOpContains: - case FcOpListing: - ret = left.u.b == right.u.b || left.u.b == FcDontCare; - break; - case FcOpNotEqual: - ret = left.u.b != right.u.b; - break; - case FcOpNotContains: - ret = !(left.u.b == right.u.b || left.u.b == FcDontCare); - break; - case FcOpLess: - ret = left.u.b != right.u.b && right.u.b == FcDontCare; - break; - case FcOpLessEqual: - ret = left.u.b == right.u.b || right.u.b == FcDontCare; - break; - case FcOpMore: - ret = left.u.b != right.u.b && left.u.b == FcDontCare; - break; - case FcOpMoreEqual: - ret = left.u.b == right.u.b || left.u.b == FcDontCare; - break; - default: - break; - } - break; - case FcTypeString: - switch ((int) op) { - case FcOpEqual: - case FcOpListing: - if (flags & FcOpFlagIgnoreBlanks) - ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; - else - ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; - break; - case FcOpContains: - ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; - break; - case FcOpNotEqual: - if (flags & FcOpFlagIgnoreBlanks) - ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; - else - ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; - break; - case FcOpNotContains: - ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; - break; - default: - break; - } - break; - case FcTypeMatrix: - switch ((int) op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = FcMatrixEqual (left.u.m, right.u.m); - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = !FcMatrixEqual (left.u.m, right.u.m); - break; - default: - break; - } - break; - case FcTypeCharSet: - switch ((int) op) { - case FcOpContains: - case FcOpListing: - /* left contains right if right is a subset of left */ - ret = FcCharSetIsSubset (right.u.c, left.u.c); - break; - case FcOpNotContains: - /* left contains right if right is a subset of left */ - ret = !FcCharSetIsSubset (right.u.c, left.u.c); - break; - case FcOpEqual: - ret = FcCharSetEqual (left.u.c, right.u.c); - break; - case FcOpNotEqual: - ret = !FcCharSetEqual (left.u.c, right.u.c); - break; - default: - break; - } - break; - case FcTypeLangSet: - switch ((int) op) { - case FcOpContains: - case FcOpListing: - ret = FcLangSetContains (left.u.l, right.u.l); - break; - case FcOpNotContains: - ret = !FcLangSetContains (left.u.l, right.u.l); - break; - case FcOpEqual: - ret = FcLangSetEqual (left.u.l, right.u.l); - break; - case FcOpNotEqual: - ret = !FcLangSetEqual (left.u.l, right.u.l); - break; - default: - break; - } - break; - case FcTypeVoid: - switch ((int) op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = FcTrue; - break; - default: - break; - } - break; - case FcTypeFTFace: - switch ((int) op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = left.u.f == right.u.f; - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = left.u.f != right.u.f; - break; - default: - break; - } - break; - case FcTypeRange: - ret = FcRangeCompare (op, left.u.r, right.u.r); - break; - } + if (left_o->type != right_o->type) + { + left = FcValueCanonicalize(left_o); + right = FcValueCanonicalize(right_o); + left = FcConfigPromote (left, right, &buf1); + right = FcConfigPromote (right, left, &buf2); + left_o = &left; + right_o = &right; + if (left_o->type != right_o->type) + { + if (op == FcOpNotEqual || op == FcOpNotContains) + ret = FcTrue; + return ret; + } + } + switch (left_o->type) { + case FcTypeUnknown: + break; /* No way to guess how to compare for this object */ + case FcTypeInteger: { + int l = left_o->u.i; + int r = right_o->u.i; + switch ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = l == r; + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = l != r; + break; + case FcOpLess: + ret = l < r; + break; + case FcOpLessEqual: + ret = l <= r; + break; + case FcOpMore: + ret = l > r; + break; + case FcOpMoreEqual: + ret = l >= r; + break; + default: + break; + } + break; + } + case FcTypeDouble: { + double l = left_o->u.d; + double r = right_o->u.d; + switch ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = l == r; + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = l != r; + break; + case FcOpLess: + ret = l < r; + break; + case FcOpLessEqual: + ret = l <= r; + break; + case FcOpMore: + ret = l > r; + break; + case FcOpMoreEqual: + ret = l >= r; + break; + default: + break; + } + break; + } + case FcTypeBool: { + FcBool l = left_o->u.b; + FcBool r = right_o->u.b; + switch ((int) op) { + case FcOpEqual: + ret = l == r; + break; + case FcOpContains: + case FcOpListing: + ret = l == r || l >= FcDontCare; + break; + case FcOpNotEqual: + ret = l != r; + break; + case FcOpNotContains: + ret = !(l == r || l >= FcDontCare); + break; + case FcOpLess: + ret = l != r && r >= FcDontCare; + break; + case FcOpLessEqual: + ret = l == r || r >= FcDontCare; + break; + case FcOpMore: + ret = l != r && l >= FcDontCare; + break; + case FcOpMoreEqual: + ret = l == r || l >= FcDontCare; + break; + default: + break; + } + break; + } + case FcTypeString: { + const FcChar8 *l = FcValueString (left_o); + const FcChar8 *r = FcValueString (right_o); + switch ((int) op) { + case FcOpEqual: + case FcOpListing: + if (flags & FcOpFlagIgnoreBlanks) + ret = FcStrCmpIgnoreBlanksAndCase (l, r) == 0; + else + ret = FcStrCmpIgnoreCase (l, r) == 0; + break; + case FcOpContains: + ret = FcStrStrIgnoreCase (l, r) != 0; + break; + case FcOpNotEqual: + if (flags & FcOpFlagIgnoreBlanks) + ret = FcStrCmpIgnoreBlanksAndCase (l, r) != 0; + else + ret = FcStrCmpIgnoreCase (l, r) != 0; + break; + case FcOpNotContains: + ret = FcStrStrIgnoreCase (l, r) == 0; + break; + default: + break; + } + break; + } + case FcTypeMatrix: { + switch ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = FcMatrixEqual (left_o->u.m, right_o->u.m); + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = !FcMatrixEqual (left_o->u.m, right_o->u.m); + break; + default: + break; + } + break; + } + case FcTypeCharSet: { + const FcCharSet *l = FcValueCharSet (left_o); + const FcCharSet *r = FcValueCharSet (right_o); + switch ((int) op) { + case FcOpContains: + case FcOpListing: + /* left contains right if right is a subset of left */ + ret = FcCharSetIsSubset (r, l); + break; + case FcOpNotContains: + /* left contains right if right is a subset of left */ + ret = !FcCharSetIsSubset (r, l); + break; + case FcOpEqual: + ret = FcCharSetEqual (l, r); + break; + case FcOpNotEqual: + ret = !FcCharSetEqual (l, r); + break; + default: + break; + } + break; + } + case FcTypeLangSet: { + const FcLangSet *l = FcValueLangSet (left_o); + const FcLangSet *r = FcValueLangSet (right_o); + switch ((int) op) { + case FcOpContains: + case FcOpListing: + ret = FcLangSetContains (l, r); + break; + case FcOpNotContains: + ret = !FcLangSetContains (l, r); + break; + case FcOpEqual: + ret = FcLangSetEqual (l, r); + break; + case FcOpNotEqual: + ret = !FcLangSetEqual (l, r); + break; + default: + break; + } + break; + } + case FcTypeVoid: + switch ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = FcTrue; + break; + default: + break; + } + break; + case FcTypeFTFace: + switch ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = left_o->u.f == right_o->u.f; + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = left_o->u.f != right_o->u.f; + break; + default: + break; + } + break; + case FcTypeRange: { + const FcRange *l = FcValueRange (left_o); + const FcRange *r = FcValueRange (right_o); + ret = FcRangeCompare (op, l, r); + break; } - else - { - if (op == FcOpNotEqual || op == FcOpNotContains) - ret = FcTrue; } return ret; } @@ -1090,7 +1334,7 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) v.u.b = FcConfigCompareValue (&vl, e->op, &vr); FcValueDestroy (vl); FcValueDestroy (vr); - break; + break; case FcOpOr: case FcOpAnd: case FcOpPlus: @@ -1106,7 +1350,7 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) switch ((int) vle.type) { case FcTypeDouble: switch ((int) op) { - case FcOpPlus: + case FcOpPlus: v.type = FcTypeDouble; v.u.d = vle.u.d + vre.u.d; break; @@ -1155,7 +1399,7 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) str = FcStrPlus (vle.u.s, vre.u.s); v.u.s = FcStrdup (str); FcStrFree (str); - + if (!v.u.s) v.type = FcTypeVoid; break; @@ -1316,17 +1560,141 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) return v; } +/* The bulk of the time in FcConfigSubstitute is spent walking + * lists of family names. We speed this up with a hash table. + * Since we need to take the ignore-blanks option into account, + * we use two separate hash tables. + */ +typedef struct +{ + int count; +} FamilyTableEntry; + + +typedef struct +{ + FcHashTable *family_blank_hash; + FcHashTable *family_hash; +} FamilyTable; + +static FcBool +FamilyTableLookup (FamilyTable *table, + FcOp _op, + const FcChar8 *s) +{ + FamilyTableEntry *fe; + int flags = FC_OP_GET_FLAGS (_op); + FcHashTable *hash; + + if (flags & FcOpFlagIgnoreBlanks) + hash = table->family_blank_hash; + else + hash = table->family_hash; + + return FcHashTableFind (hash, (const void *)s, (void **)&fe); +} + +static void +FamilyTableAdd (FamilyTable *table, + FcValueListPtr values) +{ + FcValueListPtr ll; + for (ll = values; ll; ll = FcValueListNext (ll)) + { + const FcChar8 *s = FcValueString (&ll->value); + FamilyTableEntry *fe; + + if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe)) + { + fe = malloc (sizeof (FamilyTableEntry)); + fe->count = 0; + FcHashTableAdd (table->family_hash, (void *)s, fe); + } + fe->count++; + + if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe)) + { + fe = malloc (sizeof (FamilyTableEntry)); + fe->count = 0; + FcHashTableAdd (table->family_blank_hash, (void *)s, fe); + } + fe->count++; + } +} + +static void +FamilyTableDel (FamilyTable *table, + const FcChar8 *s) +{ + FamilyTableEntry *fe; + + if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe)) + { + fe->count--; + if (fe->count == 0) + FcHashTableRemove (table->family_hash, (void *)s); + } + + if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe)) + { + fe->count--; + if (fe->count == 0) + FcHashTableRemove (table->family_blank_hash, (void *)s); + } +} + +static FcBool +copy_string (const void *src, void **dest) +{ + *dest = strdup ((char *)src); + return FcTrue; +} + +static void +FamilyTableInit (FamilyTable *table, + FcPattern *p) +{ + FcPatternElt *e; + + table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase, + (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase, + (FcCopyFunc)copy_string, + NULL, + free, + free); + table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase, + (FcCompareFunc)FcStrCmpIgnoreCase, + (FcCopyFunc)copy_string, + NULL, + free, + free); + e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT); + if (e) + FamilyTableAdd (table, FcPatternEltValues (e)); +} + +static void +FamilyTableClear (FamilyTable *table) +{ + if (table->family_blank_hash) + FcHashTableDestroy (table->family_blank_hash); + if (table->family_hash) + FcHashTableDestroy (table->family_hash); +} + static FcValueList * FcConfigMatchValueList (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcTest *t, - FcValueList *values) + FcValueList *values, + FamilyTable *table) { FcValueList *ret = 0; FcExpr *e = t->expr; FcValue value; FcValueList *v; + FcOp op; while (e) { @@ -1342,6 +1710,27 @@ FcConfigMatchValueList (FcPattern *p, e = 0; } + if (t->object == FC_FAMILY_OBJECT && table) + { + op = FC_OP_GET_OP (t->op); + if (op == FcOpEqual || op == FcOpListing) + { + if (!FamilyTableLookup (table, t->op, FcValueString (&value))) + { + ret = 0; + goto done; + } + } + if (op == FcOpNotEqual && t->qual == FcQualAll) + { + ret = 0; + if (!FamilyTableLookup (table, t->op, FcValueString (&value))) + { + ret = values; + } + goto done; + } + } for (v = values; v; v = FcValueListNext(v)) { /* Compare the pattern value to the match expression value */ @@ -1349,6 +1738,8 @@ FcConfigMatchValueList (FcPattern *p, { if (!ret) ret = v; + if (t->qual != FcQualAll) + break; } else { @@ -1359,6 +1750,7 @@ FcConfigMatchValueList (FcPattern *p, } } } +done: FcValueDestroy (value); } return ret; @@ -1401,7 +1793,8 @@ FcConfigAdd (FcValueListPtr *head, FcValueList *position, FcBool append, FcValueList *new, - FcObject object) + FcObject object, + FamilyTable *table) { FcValueListPtr *prev, l, last, v; FcValueBinding sameBinding; @@ -1427,6 +1820,11 @@ FcConfigAdd (FcValueListPtr *head, } } + if (object == FC_FAMILY_OBJECT && table) + { + FamilyTableAdd (table, new); + } + if (position) sameBinding = position->binding; else @@ -1493,10 +1891,17 @@ FcConfigAdd (FcValueListPtr *head, static void FcConfigDel (FcValueListPtr *head, - FcValueList *position) + FcValueList *position, + FcObject object, + FamilyTable *table) { FcValueListPtr *prev; + if (object == FC_FAMILY_OBJECT && table) + { + FamilyTableDel (table, FcValueString (&position->value)); + } + for (prev = head; *prev != NULL; prev = &(*prev)->next) { if (*prev == position) @@ -1511,9 +1916,10 @@ FcConfigDel (FcValueListPtr *head, static void FcConfigPatternAdd (FcPattern *p, - FcObject object, + FcObject object, FcValueList *list, - FcBool append) + FcBool append, + FamilyTable *table) { if (list) { @@ -1521,7 +1927,7 @@ FcConfigPatternAdd (FcPattern *p, if (!e) return; - FcConfigAdd (&e->values, 0, append, list, object); + FcConfigAdd (&e->values, 0, append, list, object, table); } } @@ -1530,13 +1936,14 @@ FcConfigPatternAdd (FcPattern *p, */ static void FcConfigPatternDel (FcPattern *p, - FcObject object) + FcObject object, + FamilyTable *table) { FcPatternElt *e = FcPatternObjectFindElt (p, object); if (!e) return; while (e->values != NULL) - FcConfigDel (&e->values, e->values); + FcConfigDel (&e->values, e->values, object, table); } static void @@ -1569,16 +1976,16 @@ FcConfigSubstituteWithPat (FcConfig *config, int i, nobjs; FcBool retval = FcTrue; FcTest **tst = NULL; - - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } + FamilyTable data; + FamilyTable *table = &data; if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd) return FcFalse; + + config = FcConfigReference (config); + if (!config) + return FcFalse; + s = config->subst[kind]; if (kind == FcMatchPattern) { @@ -1668,6 +2075,9 @@ FcConfigSubstituteWithPat (FcConfig *config, printf ("FcConfigSubstitute "); FcPatternPrint (p); } + + FamilyTableInit (&data, p); + FcPtrListIterInit (s, &iter); for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter)) { @@ -1704,9 +2114,15 @@ FcConfigSubstituteWithPat (FcConfig *config, FcTestPrint (r->u.test); } if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) + { m = p_pat; + table = NULL; + } else + { m = p; + table = &data; + } if (m) e = FcPatternObjectFindElt (m, r->u.test->object); else @@ -1739,7 +2155,7 @@ FcConfigSubstituteWithPat (FcConfig *config, * Check to see if there is a match, mark the location * to apply match-relative edits */ - vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); + vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table); /* different 'kind' won't be the target of edit */ if (!value[object] && kind == r->u.test->kind) value[object] = vl; @@ -1763,7 +2179,7 @@ FcConfigSubstituteWithPat (FcConfig *config, /* * Evaluate the list of expressions */ - l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); + l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding); if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) elt[object] = FcPatternObjectFindElt (p, tst[object]->object); @@ -1781,12 +2197,12 @@ FcConfigSubstituteWithPat (FcConfig *config, /* * Append the new list of values after the current value */ - FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); + FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table); /* * Delete the marked value */ if (thisValue) - FcConfigDel (&elt[object]->values, thisValue); + FcConfigDel (&elt[object]->values, thisValue, object, table); /* * Adjust a pointer into the value list to ensure * future edits occur at the same place @@ -1800,8 +2216,8 @@ FcConfigSubstituteWithPat (FcConfig *config, * Delete all of the values and insert * the new set */ - FcConfigPatternDel (p, r->u.edit->object); - FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); + FcConfigPatternDel (p, r->u.edit->object, table); + FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table); /* * Adjust a pointer into the value list as they no * longer point to anything valid @@ -1811,33 +2227,33 @@ FcConfigSubstituteWithPat (FcConfig *config, case FcOpPrepend: if (value[object]) { - FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); + FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table); break; } /* fall through ... */ case FcOpPrependFirst: - FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); + FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table); break; case FcOpAppend: if (value[object]) { - FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); + FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table); break; } /* fall through ... */ case FcOpAppendLast: - FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); + FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table); break; case FcOpDelete: if (value[object]) { - FcConfigDel (&elt[object]->values, value[object]); + FcConfigDel (&elt[object]->values, value[object], object, table); FcValueListDestroy (l); break; } /* fall through ... */ case FcOpDeleteAll: - FcConfigPatternDel (p, r->u.edit->object); + FcConfigPatternDel (p, r->u.edit->object, table); FcValueListDestroy (l); break; default: @@ -1867,12 +2283,14 @@ FcConfigSubstituteWithPat (FcConfig *config, FcPatternPrint (p); } bail1: + FamilyTableClear (&data); if (elt) free (elt); if (value) free (value); if (tst) free (tst); + FcConfigDestroy (config); return retval; } @@ -2099,7 +2517,7 @@ FcConfigXdgCacheHome (void) if (!_FcConfigHomeEnabled) return NULL; - if (env) + if (env && env[0]) ret = FcStrCopy ((const FcChar8 *)env); else { @@ -2175,6 +2593,65 @@ FcConfigXdgDataHome (void) return ret; } +FcStrSet * +FcConfigXdgDataDirs (void) +{ + const char *env = getenv ("XDG_DATA_DIRS"); + FcStrSet *ret = FcStrSetCreate (); + + if (env) + { + FcChar8 *ee, *e = ee = FcStrCopy ((const FcChar8 *) env); + + /* We don't intentionally use FC_SEARCH_PATH_SEPARATOR here because of: + * The directories in $XDG_DATA_DIRS should be seperated with a colon ':'. + * in doc. + */ + while (e) + { + FcChar8 *p = (FcChar8 *) strchr ((const char *) e, ':'); + FcChar8 *s; + size_t len; + + if (!p) + { + s = FcStrCopy (e); + e = NULL; + } + else + { + *p = 0; + s = FcStrCopy (e); + e = p + 1; + } + len = strlen ((const char *) s); + if (s[len - 1] == FC_DIR_SEPARATOR) + { + do + { + len--; + } + while (len > 1 && s[len - 1] == FC_DIR_SEPARATOR); + s[len] = 0; + } + FcStrSetAdd (ret, s); + FcStrFree (s); + } + FcStrFree (ee); + } + else + { + /* From spec doc at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables + * + * If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. + */ + FcStrSetAdd (ret, (const FcChar8 *) "/usr/local/share"); + FcStrSetAdd (ret, (const FcChar8 *) "/usr/share"); + } + + return ret; +} + FcBool FcConfigEnableHome (FcBool enable) { @@ -2184,10 +2661,16 @@ FcConfigEnableHome (FcBool enable) } FcChar8 * -FcConfigFilename (const FcChar8 *url) +FcConfigGetFilename (FcConfig *config, + const FcChar8 *url) { FcChar8 *file, *dir, **path, **p; + const FcChar8 *sysroot; + config = FcConfigReference (config); + if (!config) + return NULL; + sysroot = FcConfigGetSysRoot (config); if (!url || !*url) { url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); @@ -2197,57 +2680,99 @@ FcConfigFilename (const FcChar8 *url) file = 0; if (FcStrIsAbsoluteFilename(url)) - return FcConfigFileExists (0, url); + { + if (sysroot) + { + size_t len = strlen ((const char *) sysroot); + + /* Workaround to avoid adding sysroot repeatedly */ + if (strncmp ((const char *) url, (const char *) sysroot, len) == 0) + sysroot = NULL; + } + file = FcConfigFileExists (sysroot, url); + goto bail; + } if (*url == '~') { dir = FcConfigHome (); if (dir) - file = FcConfigFileExists (dir, url + 1); + { + FcChar8 *s; + + if (sysroot) + s = FcStrBuildFilename (sysroot, dir, NULL); + else + s = dir; + file = FcConfigFileExists (s, url + 1); + if (sysroot) + FcStrFree (s); + } else file = 0; } - - path = FcConfigGetPath (); - if (!path) - return NULL; - for (p = path; *p; p++) + else { - file = FcConfigFileExists (*p, url); - if (file) - break; + path = FcConfigGetPath (); + if (!path) + { + file = NULL; + goto bail; + } + for (p = path; *p; p++) + { + FcChar8 *s; + + if (sysroot) + s = FcStrBuildFilename (sysroot, *p, NULL); + else + s = *p; + file = FcConfigFileExists (s, url); + if (sysroot) + FcStrFree (s); + if (file) + break; + } + FcConfigFreePath (path); } - FcConfigFreePath (path); +bail: + FcConfigDestroy (config); + return file; } FcChar8 * +FcConfigFilename (const FcChar8 *url) +{ + return FcConfigGetFilename (NULL, url); +} + +FcChar8 * FcConfigRealFilename (FcConfig *config, const FcChar8 *url) { - const FcChar8 *sysroot = FcConfigGetSysRoot (config); - FcChar8 *n = FcConfigFilename (url); - FcChar8 *nn = NULL; + FcChar8 *n = FcConfigGetFilename (config, url); if (n) { - FcChar8 buf[PATH_MAX]; + FcChar8 buf[FC_PATH_MAX]; ssize_t len; + struct stat sb; - if (sysroot) - nn = FcStrBuildFilename (sysroot, n, NULL); - else - nn = FcStrdup (n); - FcStrFree (n); - - if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1) + if ((len = FcReadLink (n, buf, sizeof (buf) - 1)) != -1) { buf[len] = 0; - if (!FcStrIsAbsoluteFilename (buf)) + /* We try to pick up a config from FONTCONFIG_FILE + * when url is null. don't try to address the real filename + * if it is a named pipe. + */ + if (!url && FcStat (n, &sb) == 0 && S_ISFIFO (sb.st_mode)) + return n; + else if (!FcStrIsAbsoluteFilename (buf)) { - FcChar8 *dirname = FcStrDirname (nn); - FcStrFree (nn); + FcChar8 *dirname = FcStrDirname (n); + FcStrFree (n); if (!dirname) return NULL; @@ -2256,18 +2781,18 @@ FcConfigRealFilename (FcConfig *config, if (!path) return NULL; - nn = FcStrCanonFilename (path); + n = FcStrCanonFilename (path); FcStrFree (path); } else { - FcStrFree (nn); - nn = FcStrdup (buf); + FcStrFree (n); + n = FcStrdup (buf); } } } - return nn; + return n; } /* @@ -2282,17 +2807,18 @@ FcConfigAppFontAddFile (FcConfig *config, FcStrSet *subdirs; FcStrList *sublist; FcChar8 *subdir; + FcBool ret = FcTrue; + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } + return FcFalse; subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64); if (!subdirs) - return FcFalse; + { + ret = FcFalse; + goto bail; + } set = FcConfigGetFonts (config, FcSetApplication); if (!set) @@ -2301,15 +2827,17 @@ FcConfigAppFontAddFile (FcConfig *config, if (!set) { FcStrSetDestroy (subdirs); - return FcFalse; + ret = FcFalse; + goto bail; } FcConfigSetFonts (config, set, FcSetApplication); } - + if (!FcFileScanConfig (set, subdirs, file, config)) { FcStrSetDestroy (subdirs); - return FcFalse; + ret = FcFalse; + goto bail; } if ((sublist = FcStrListCreate (subdirs))) { @@ -2320,7 +2848,10 @@ FcConfigAppFontAddFile (FcConfig *config, FcStrListDone (sublist); } FcStrSetDestroy (subdirs); - return FcTrue; +bail: + FcConfigDestroy (config); + + return ret; } FcBool @@ -2329,17 +2860,18 @@ FcConfigAppFontAddDir (FcConfig *config, { FcFontSet *set; FcStrSet *dirs; + FcBool ret = FcTrue; + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } + return FcFalse; dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); if (!dirs) - return FcFalse; + { + ret = FcFalse; + goto bail; + } set = FcConfigGetFonts (config, FcSetApplication); if (!set) @@ -2348,7 +2880,8 @@ FcConfigAppFontAddDir (FcConfig *config, if (!set) { FcStrSetDestroy (dirs); - return FcFalse; + ret = FcFalse; + goto bail; } FcConfigSetFonts (config, set, FcSetApplication); } @@ -2358,23 +2891,26 @@ FcConfigAppFontAddDir (FcConfig *config, if (!FcConfigAddDirList (config, FcSetApplication, dirs)) { FcStrSetDestroy (dirs); - return FcFalse; + ret = FcFalse; + goto bail; } FcStrSetDestroy (dirs); - return FcTrue; +bail: + FcConfigDestroy (config); + + return ret; } void FcConfigAppFontClear (FcConfig *config) { + config = FcConfigReference (config); if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return; - } + return; FcConfigSetFonts (config, 0, FcSetApplication); + + FcConfigDestroy (config); } /* @@ -2387,8 +2923,13 @@ FcConfigGlobAdd (FcConfig *config, FcBool accept) { FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; + FcChar8 *realglob = FcStrCopyFilename(glob); + if (!realglob) + return FcFalse; - return FcStrSetAdd (set, glob); + FcBool ret = FcStrSetAdd (set, realglob); + FcStrFree(realglob); + return ret; } static FcBool @@ -2460,11 +3001,7 @@ FcConfigGetSysRoot (const FcConfig *config) if (!config) return NULL; } - - if (config->sysRoot) - return config->sysRoot; - - return (FcChar8 *) getenv ("FONTCONFIG_SYSROOT"); + return config->sysRoot; } void @@ -2473,7 +3010,9 @@ FcConfigSetSysRoot (FcConfig *config, { FcChar8 *s = NULL; FcBool init = FcFalse; + int nretry = 3; +retry: if (!config) { /* We can't use FcConfigGetCurrent() here to ensure @@ -2493,7 +3032,7 @@ FcConfigSetSysRoot (FcConfig *config, if (sysroot) { - s = FcStrCopyFilename (sysroot); + s = FcStrRealPath (sysroot); if (!s) return; } @@ -2505,6 +3044,17 @@ FcConfigSetSysRoot (FcConfig *config, if (init) { config = FcInitLoadOwnConfigAndFonts (config); + if (!config) + { + /* Something failed. this is usually unlikely. so retrying */ + init = FcFalse; + if (--nretry == 0) + { + fprintf (stderr, "Fontconfig warning: Unable to initialize config and retry limit exceeded. sysroot functionality may not work as expected.\n"); + return; + } + goto retry; + } FcConfigSetCurrent (config); /* FcConfigSetCurrent() increases the refcount. * decrease it here to avoid the memory leak.