fccfg.c revision 1887081f
12c393a42Smrg/* 2a6844aabSmrg * fontconfig/src/fccfg.c 32c393a42Smrg * 42c393a42Smrg * Copyright © 2000 Keith Packard 52c393a42Smrg * 62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its 72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that 82c393a42Smrg * the above copyright notice appear in all copies and that both that 92c393a42Smrg * copyright notice and this permission notice appear in supporting 10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 12ca08ab68Smrg * specific, written prior permission. The authors make no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE. 232c393a42Smrg */ 242c393a42Smrg 25c9710b42Smrg/* Objects MT-safe for readonly access. */ 26c9710b42Smrg 272c393a42Smrg#include "fcint.h" 282c393a42Smrg#include <dirent.h> 292c393a42Smrg#include <sys/types.h> 302c393a42Smrg 312c393a42Smrg#if defined (_WIN32) && !defined (R_OK) 322c393a42Smrg#define R_OK 4 332c393a42Smrg#endif 342c393a42Smrg 35c9710b42Smrgstatic FcConfig *_fcConfig; /* MT-safe */ 36c9710b42Smrg 37c9710b42Smrgstatic FcConfig * 38c9710b42SmrgFcConfigEnsure (void) 39c9710b42Smrg{ 40c9710b42Smrg FcConfig *config; 41c9710b42Smrgretry: 42c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 43c9710b42Smrg if (!config) 44c9710b42Smrg { 45c9710b42Smrg config = FcInitLoadConfigAndFonts (); 46c9710b42Smrg 47c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { 48c9710b42Smrg FcConfigDestroy (config); 49c9710b42Smrg goto retry; 50c9710b42Smrg } 51c9710b42Smrg } 52c9710b42Smrg return config; 53c9710b42Smrg} 54c9710b42Smrg 551887081fSmrgstatic FcChar32 561887081fSmrgFcHashAsStrIgnoreCase (const void *data) 571887081fSmrg{ 581887081fSmrg return FcStrHashIgnoreCase (data); 591887081fSmrg} 601887081fSmrg 611887081fSmrgstatic int 621887081fSmrgFcCompareAsStr (const void *v1, const void *v2) 631887081fSmrg{ 641887081fSmrg return FcStrCmp (v1, v2); 651887081fSmrg} 661887081fSmrg 671887081fSmrgstatic void 681887081fSmrgFcDestroyAsRule (void *data) 691887081fSmrg{ 701887081fSmrg FcRuleDestroy (data); 711887081fSmrg} 721887081fSmrg 731887081fSmrgstatic void 741887081fSmrgFcDestroyAsRuleSet (void *data) 751887081fSmrg{ 761887081fSmrg FcRuleSetDestroy (data); 771887081fSmrg} 781887081fSmrg 791887081fSmrgstatic void 801887081fSmrgFcDestroyAsStr (void *data) 811887081fSmrg{ 821887081fSmrg FcStrFree (data); 831887081fSmrg} 841887081fSmrg 85c9710b42SmrgFcBool 86c9710b42SmrgFcConfigInit (void) 87c9710b42Smrg{ 88c9710b42Smrg return FcConfigEnsure () ? FcTrue : FcFalse; 89c9710b42Smrg} 90c9710b42Smrg 91c9710b42Smrgvoid 92c9710b42SmrgFcConfigFini (void) 93c9710b42Smrg{ 94c9710b42Smrg FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); 95c9710b42Smrg if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) 96c9710b42Smrg FcConfigDestroy (cfg); 97c9710b42Smrg} 98c9710b42Smrg 992c393a42Smrg 1002c393a42SmrgFcConfig * 1012c393a42SmrgFcConfigCreate (void) 1022c393a42Smrg{ 1032c393a42Smrg FcSetName set; 1042c393a42Smrg FcConfig *config; 1051887081fSmrg FcMatchKind k; 1061887081fSmrg FcBool err = FcFalse; 1072c393a42Smrg 1082c393a42Smrg config = malloc (sizeof (FcConfig)); 1092c393a42Smrg if (!config) 1102c393a42Smrg goto bail0; 111ca08ab68Smrg 1122c393a42Smrg config->configDirs = FcStrSetCreate (); 1132c393a42Smrg if (!config->configDirs) 1142c393a42Smrg goto bail1; 115ca08ab68Smrg 1162c393a42Smrg config->configFiles = FcStrSetCreate (); 1172c393a42Smrg if (!config->configFiles) 1182c393a42Smrg goto bail2; 119ca08ab68Smrg 1202c393a42Smrg config->fontDirs = FcStrSetCreate (); 1212c393a42Smrg if (!config->fontDirs) 1222c393a42Smrg goto bail3; 123ca08ab68Smrg 1242c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 1252c393a42Smrg if (!config->acceptGlobs) 1262c393a42Smrg goto bail4; 1272c393a42Smrg 1282c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 1292c393a42Smrg if (!config->rejectGlobs) 1302c393a42Smrg goto bail5; 1312c393a42Smrg 1322c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 1332c393a42Smrg if (!config->acceptPatterns) 1342c393a42Smrg goto bail6; 135ca08ab68Smrg 1362c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 1372c393a42Smrg if (!config->rejectPatterns) 1382c393a42Smrg goto bail7; 1392c393a42Smrg 1402c393a42Smrg config->cacheDirs = FcStrSetCreate (); 1412c393a42Smrg if (!config->cacheDirs) 1422c393a42Smrg goto bail8; 143ca08ab68Smrg 1441887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 1451887081fSmrg { 1461887081fSmrg config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet); 1471887081fSmrg if (!config->subst[k]) 1481887081fSmrg err = FcTrue; 1491887081fSmrg } 1501887081fSmrg if (err) 1511887081fSmrg goto bail9; 1522c393a42Smrg 1532c393a42Smrg config->maxObjects = 0; 1542c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 1552c393a42Smrg config->fonts[set] = 0; 1562c393a42Smrg 1572c393a42Smrg config->rescanTime = time(0); 158ca08ab68Smrg config->rescanInterval = 30; 159a6844aabSmrg 160a6844aabSmrg config->expr_pool = NULL; 161a6844aabSmrg 162c9710b42Smrg config->sysRoot = NULL; 163c9710b42Smrg 1641887081fSmrg config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet); 1651887081fSmrg if (!config->rulesetList) 1661887081fSmrg goto bail9; 1671887081fSmrg config->availConfigFiles = FcStrSetCreate (); 1681887081fSmrg if (!config->availConfigFiles) 1691887081fSmrg goto bail10; 1701887081fSmrg 1711887081fSmrg config->uuid_table = FcHashTableCreate (FcHashAsStrIgnoreCase, 1721887081fSmrg FcCompareAsStr, 1731887081fSmrg FcHashStrCopy, 1741887081fSmrg FcHashUuidCopy, 1751887081fSmrg FcDestroyAsStr, 1761887081fSmrg FcHashUuidFree); 1771887081fSmrg 178c9710b42Smrg FcRefInit (&config->ref, 1); 179ca08ab68Smrg 1802c393a42Smrg return config; 1812c393a42Smrg 1821887081fSmrgbail10: 1831887081fSmrg FcPtrListDestroy (config->rulesetList); 1841887081fSmrgbail9: 1851887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 1861887081fSmrg if (config->subst[k]) 1871887081fSmrg FcPtrListDestroy (config->subst[k]); 1881887081fSmrg FcStrSetDestroy (config->cacheDirs); 1892c393a42Smrgbail8: 1902c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 1912c393a42Smrgbail7: 1922c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 1932c393a42Smrgbail6: 1942c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 1952c393a42Smrgbail5: 1962c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 1972c393a42Smrgbail4: 1982c393a42Smrg FcStrSetDestroy (config->fontDirs); 1992c393a42Smrgbail3: 2002c393a42Smrg FcStrSetDestroy (config->configFiles); 2012c393a42Smrgbail2: 2022c393a42Smrg FcStrSetDestroy (config->configDirs); 2032c393a42Smrgbail1: 2042c393a42Smrg free (config); 2052c393a42Smrgbail0: 2062c393a42Smrg return 0; 2072c393a42Smrg} 2082c393a42Smrg 2092c393a42Smrgstatic FcFileTime 2102c393a42SmrgFcConfigNewestFile (FcStrSet *files) 2112c393a42Smrg{ 2122c393a42Smrg FcStrList *list = FcStrListCreate (files); 2132c393a42Smrg FcFileTime newest = { 0, FcFalse }; 2142c393a42Smrg FcChar8 *file; 2152c393a42Smrg struct stat statb; 2162c393a42Smrg 2172c393a42Smrg if (list) 2182c393a42Smrg { 2192c393a42Smrg while ((file = FcStrListNext (list))) 220ca08ab68Smrg if (FcStat (file, &statb) == 0) 2212c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 2222c393a42Smrg { 2232c393a42Smrg newest.set = FcTrue; 2242c393a42Smrg newest.time = statb.st_mtime; 2252c393a42Smrg } 2262c393a42Smrg FcStrListDone (list); 2272c393a42Smrg } 2282c393a42Smrg return newest; 2292c393a42Smrg} 2302c393a42Smrg 2312c393a42SmrgFcBool 2322c393a42SmrgFcConfigUptoDate (FcConfig *config) 2332c393a42Smrg{ 2342c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 2352c393a42Smrg time_t now = time(0); 2362c393a42Smrg if (!config) 2372c393a42Smrg { 2382c393a42Smrg config = FcConfigGetCurrent (); 2392c393a42Smrg if (!config) 2402c393a42Smrg return FcFalse; 2412c393a42Smrg } 2422c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 2432c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 2442c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 2452c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 2462c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 2472c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 2482c393a42Smrg { 2492c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 2502c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 2512c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 2522c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 2532c393a42Smrg { 2542c393a42Smrg fprintf (stderr, 255c9710b42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); 2562c393a42Smrg config->rescanTime = now; 2572c393a42Smrg return FcTrue; 2582c393a42Smrg } 2592c393a42Smrg else 2602c393a42Smrg return FcFalse; 2612c393a42Smrg } 2622c393a42Smrg config->rescanTime = now; 2632c393a42Smrg return FcTrue; 2642c393a42Smrg} 2652c393a42Smrg 266a6844aabSmrgFcExpr * 267a6844aabSmrgFcConfigAllocExpr (FcConfig *config) 268a6844aabSmrg{ 2696fc018e4Smrg if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 2706fc018e4Smrg { 2716fc018e4Smrg FcExprPage *new_page; 272a6844aabSmrg 2736fc018e4Smrg new_page = malloc (sizeof (FcExprPage)); 2746fc018e4Smrg if (!new_page) 2756fc018e4Smrg return 0; 276a6844aabSmrg 2776fc018e4Smrg new_page->next_page = config->expr_pool; 2786fc018e4Smrg new_page->next = new_page->exprs; 2796fc018e4Smrg config->expr_pool = new_page; 2806fc018e4Smrg } 281a6844aabSmrg 2826fc018e4Smrg return config->expr_pool->next++; 283a6844aabSmrg} 284a6844aabSmrg 285a6844aabSmrgFcConfig * 286a6844aabSmrgFcConfigReference (FcConfig *config) 287a6844aabSmrg{ 288a6844aabSmrg if (!config) 289a6844aabSmrg { 290a6844aabSmrg config = FcConfigGetCurrent (); 291a6844aabSmrg if (!config) 292a6844aabSmrg return 0; 293a6844aabSmrg } 294a6844aabSmrg 295c9710b42Smrg FcRefInc (&config->ref); 296a6844aabSmrg 297a6844aabSmrg return config; 298a6844aabSmrg} 299a6844aabSmrg 3002c393a42Smrgvoid 3012c393a42SmrgFcConfigDestroy (FcConfig *config) 3022c393a42Smrg{ 3032c393a42Smrg FcSetName set; 304a6844aabSmrg FcExprPage *page; 3051887081fSmrg FcMatchKind k; 306a6844aabSmrg 307c9710b42Smrg if (FcRefDec (&config->ref) != 1) 308a6844aabSmrg return; 3092c393a42Smrg 310c9710b42Smrg (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); 3112c393a42Smrg 3122c393a42Smrg FcStrSetDestroy (config->configDirs); 3132c393a42Smrg FcStrSetDestroy (config->fontDirs); 3142c393a42Smrg FcStrSetDestroy (config->cacheDirs); 3152c393a42Smrg FcStrSetDestroy (config->configFiles); 3162c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 3172c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 3182c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 3192c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 3202c393a42Smrg 3211887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 3221887081fSmrg FcPtrListDestroy (config->subst[k]); 3231887081fSmrg FcPtrListDestroy (config->rulesetList); 3241887081fSmrg FcStrSetDestroy (config->availConfigFiles); 3252c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 3262c393a42Smrg if (config->fonts[set]) 3272c393a42Smrg FcFontSetDestroy (config->fonts[set]); 3282c393a42Smrg 329a6844aabSmrg page = config->expr_pool; 330a6844aabSmrg while (page) 331a6844aabSmrg { 332a6844aabSmrg FcExprPage *next = page->next_page; 333a6844aabSmrg free (page); 334a6844aabSmrg page = next; 335a6844aabSmrg } 336c9710b42Smrg if (config->sysRoot) 337c9710b42Smrg FcStrFree (config->sysRoot); 338a6844aabSmrg 3391887081fSmrg FcHashTableDestroy (config->uuid_table); 3401887081fSmrg 3412c393a42Smrg free (config); 3422c393a42Smrg} 3432c393a42Smrg 3442c393a42Smrg/* 3452c393a42Smrg * Add cache to configuration, adding fonts and directories 3462c393a42Smrg */ 3472c393a42Smrg 3482c393a42SmrgFcBool 349ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 3501887081fSmrg FcSetName set, FcStrSet *dirSet, FcChar8 *forDir) 3512c393a42Smrg{ 3522c393a42Smrg FcFontSet *fs; 3532c393a42Smrg intptr_t *dirs; 3542c393a42Smrg int i; 3551887081fSmrg FcBool relocated = FcFalse; 3561887081fSmrg 3571887081fSmrg if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0) 3581887081fSmrg relocated = FcTrue; 3592c393a42Smrg 3602c393a42Smrg /* 3612c393a42Smrg * Add fonts 3622c393a42Smrg */ 3632c393a42Smrg fs = FcCacheSet (cache); 3642c393a42Smrg if (fs) 3652c393a42Smrg { 3662c393a42Smrg int nref = 0; 3672c393a42Smrg 3682c393a42Smrg for (i = 0; i < fs->nfont; i++) 3692c393a42Smrg { 3702c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 3712c393a42Smrg FcChar8 *font_file; 3721887081fSmrg FcChar8 *relocated_font_file = NULL; 3732c393a42Smrg 3742c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 3751887081fSmrg 0, &font_file) == FcResultMatch) 3762c393a42Smrg { 3771887081fSmrg if (relocated) 3781887081fSmrg { 3791887081fSmrg FcChar8 *slash = FcStrLastSlash (font_file); 3801887081fSmrg relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL); 3811887081fSmrg font_file = relocated_font_file; 3821887081fSmrg } 3831887081fSmrg 3841887081fSmrg /* 3851887081fSmrg * Check to see if font is banned by filename 3861887081fSmrg */ 3871887081fSmrg if (!FcConfigAcceptFilename (config, font_file)) 3881887081fSmrg { 3891887081fSmrg free (relocated_font_file); 3901887081fSmrg continue; 3911887081fSmrg } 3922c393a42Smrg } 3931887081fSmrg 3942c393a42Smrg /* 3952c393a42Smrg * Check to see if font is banned by pattern 3962c393a42Smrg */ 3972c393a42Smrg if (!FcConfigAcceptFont (config, font)) 3981887081fSmrg { 3991887081fSmrg free (relocated_font_file); 4002c393a42Smrg continue; 4011887081fSmrg } 4021887081fSmrg 4031887081fSmrg if (relocated_font_file) 4041887081fSmrg { 4051887081fSmrg font = FcPatternCacheRewriteFile (font, cache, relocated_font_file); 4061887081fSmrg free (relocated_font_file); 4071887081fSmrg } 4081887081fSmrg 409c9710b42Smrg if (FcFontSetAdd (config->fonts[set], font)) 410c9710b42Smrg nref++; 4112c393a42Smrg } 4122c393a42Smrg FcDirCacheReference (cache, nref); 4132c393a42Smrg } 4142c393a42Smrg 4152c393a42Smrg /* 4162c393a42Smrg * Add directories 4172c393a42Smrg */ 4182c393a42Smrg dirs = FcCacheDirs (cache); 4192c393a42Smrg if (dirs) 4202c393a42Smrg { 4212c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 4222c393a42Smrg { 4231887081fSmrg const FcChar8 *dir = FcCacheSubdir (cache, i); 4241887081fSmrg FcChar8 *s = NULL; 4251887081fSmrg 4261887081fSmrg if (relocated) 4271887081fSmrg { 4281887081fSmrg FcChar8 *base = FcStrBasename (dir); 4291887081fSmrg dir = s = FcStrBuildFilename (forDir, base, NULL); 4301887081fSmrg FcStrFree (base); 4311887081fSmrg } 4322c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 4332c393a42Smrg FcStrSetAddFilename (dirSet, dir); 4341887081fSmrg if (s) 4351887081fSmrg FcStrFree (s); 4362c393a42Smrg } 4372c393a42Smrg } 4382c393a42Smrg return FcTrue; 4392c393a42Smrg} 4402c393a42Smrg 4412c393a42Smrgstatic FcBool 4422c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 4432c393a42Smrg{ 4442c393a42Smrg FcStrList *dirlist; 4452c393a42Smrg FcChar8 *dir; 4462c393a42Smrg FcCache *cache; 447ca08ab68Smrg 4482c393a42Smrg dirlist = FcStrListCreate (dirSet); 4492c393a42Smrg if (!dirlist) 4502c393a42Smrg return FcFalse; 4512c393a42Smrg 4522c393a42Smrg while ((dir = FcStrListNext (dirlist))) 4532c393a42Smrg { 4542c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 45518bd4a06Smrg printf ("adding fonts from %s\n", dir); 4562c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 4572c393a42Smrg if (!cache) 4582c393a42Smrg continue; 4591887081fSmrg FcConfigAddCache (config, cache, set, dirSet, dir); 4602c393a42Smrg FcDirCacheUnload (cache); 4612c393a42Smrg } 4622c393a42Smrg FcStrListDone (dirlist); 4632c393a42Smrg return FcTrue; 4642c393a42Smrg} 4652c393a42Smrg 4662c393a42Smrg/* 4672c393a42Smrg * Scan the current list of directories in the configuration 4682c393a42Smrg * and build the set of available fonts. 4692c393a42Smrg */ 4702c393a42Smrg 4712c393a42SmrgFcBool 4722c393a42SmrgFcConfigBuildFonts (FcConfig *config) 4732c393a42Smrg{ 4742c393a42Smrg FcFontSet *fonts; 4752c393a42Smrg 4762c393a42Smrg if (!config) 4772c393a42Smrg { 4782c393a42Smrg config = FcConfigGetCurrent (); 4792c393a42Smrg if (!config) 4802c393a42Smrg return FcFalse; 4812c393a42Smrg } 4822c393a42Smrg 4832c393a42Smrg fonts = FcFontSetCreate (); 4842c393a42Smrg if (!fonts) 4852c393a42Smrg return FcFalse; 486ca08ab68Smrg 4872c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 488ca08ab68Smrg 4892c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 4902c393a42Smrg return FcFalse; 4912c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 4922c393a42Smrg FcFontSetPrint (fonts); 4932c393a42Smrg return FcTrue; 4942c393a42Smrg} 4952c393a42Smrg 4962c393a42SmrgFcBool 4972c393a42SmrgFcConfigSetCurrent (FcConfig *config) 4982c393a42Smrg{ 499c9710b42Smrg FcConfig *cfg; 500c9710b42Smrg 501c9710b42Smrgretry: 502c9710b42Smrg cfg = fc_atomic_ptr_get (&_fcConfig); 503c9710b42Smrg 504c9710b42Smrg if (config == cfg) 5052c393a42Smrg return FcTrue; 5062c393a42Smrg 507c9710b42Smrg if (config && !config->fonts[FcSetSystem]) 5082c393a42Smrg if (!FcConfigBuildFonts (config)) 5092c393a42Smrg return FcFalse; 5102c393a42Smrg 511c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) 512c9710b42Smrg goto retry; 513c9710b42Smrg 51418bd4a06Smrg FcConfigReference (config); 515c9710b42Smrg if (cfg) 516c9710b42Smrg FcConfigDestroy (cfg); 517c9710b42Smrg 5182c393a42Smrg return FcTrue; 5192c393a42Smrg} 5202c393a42Smrg 5212c393a42SmrgFcConfig * 5222c393a42SmrgFcConfigGetCurrent (void) 5232c393a42Smrg{ 524c9710b42Smrg return FcConfigEnsure (); 5252c393a42Smrg} 5262c393a42Smrg 5272c393a42SmrgFcBool 5282c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 5292c393a42Smrg const FcChar8 *d) 5302c393a42Smrg{ 5312c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 5322c393a42Smrg} 5332c393a42Smrg 5342c393a42SmrgFcStrList * 5352c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 5362c393a42Smrg{ 5372c393a42Smrg if (!config) 5382c393a42Smrg { 5392c393a42Smrg config = FcConfigGetCurrent (); 5402c393a42Smrg if (!config) 5412c393a42Smrg return 0; 5422c393a42Smrg } 5432c393a42Smrg return FcStrListCreate (config->configDirs); 5442c393a42Smrg} 5452c393a42Smrg 5462c393a42SmrgFcBool 5472c393a42SmrgFcConfigAddFontDir (FcConfig *config, 5482c393a42Smrg const FcChar8 *d) 5492c393a42Smrg{ 5502c393a42Smrg return FcStrSetAddFilename (config->fontDirs, d); 5512c393a42Smrg} 5522c393a42Smrg 5532c393a42SmrgFcStrList * 5542c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 5552c393a42Smrg{ 5562c393a42Smrg if (!config) 5572c393a42Smrg { 5582c393a42Smrg config = FcConfigGetCurrent (); 5592c393a42Smrg if (!config) 5602c393a42Smrg return 0; 5612c393a42Smrg } 5622c393a42Smrg return FcStrListCreate (config->fontDirs); 5632c393a42Smrg} 5642c393a42Smrg 5652c393a42SmrgFcBool 5662c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 5672c393a42Smrg const FcChar8 *d) 5682c393a42Smrg{ 5692c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 5702c393a42Smrg} 5712c393a42Smrg 5722c393a42SmrgFcStrList * 573ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config) 5742c393a42Smrg{ 5752c393a42Smrg if (!config) 5762c393a42Smrg { 5772c393a42Smrg config = FcConfigGetCurrent (); 5782c393a42Smrg if (!config) 5792c393a42Smrg return 0; 5802c393a42Smrg } 5812c393a42Smrg return FcStrListCreate (config->cacheDirs); 5822c393a42Smrg} 583ca08ab68Smrg 5842c393a42SmrgFcBool 5852c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 5862c393a42Smrg const FcChar8 *f) 5872c393a42Smrg{ 5882c393a42Smrg FcBool ret; 5892c393a42Smrg FcChar8 *file = FcConfigFilename (f); 590ca08ab68Smrg 5912c393a42Smrg if (!file) 5922c393a42Smrg return FcFalse; 593ca08ab68Smrg 5942c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 5952c393a42Smrg FcStrFree (file); 5962c393a42Smrg return ret; 5972c393a42Smrg} 5982c393a42Smrg 5992c393a42SmrgFcStrList * 6002c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 6012c393a42Smrg{ 6022c393a42Smrg if (!config) 6032c393a42Smrg { 6042c393a42Smrg config = FcConfigGetCurrent (); 6052c393a42Smrg if (!config) 6062c393a42Smrg return 0; 6072c393a42Smrg } 6082c393a42Smrg return FcStrListCreate (config->configFiles); 6092c393a42Smrg} 6102c393a42Smrg 6112c393a42SmrgFcChar8 * 612c9710b42SmrgFcConfigGetCache (FcConfig *config FC_UNUSED) 6132c393a42Smrg{ 6142c393a42Smrg return NULL; 6152c393a42Smrg} 6162c393a42Smrg 6172c393a42SmrgFcFontSet * 6182c393a42SmrgFcConfigGetFonts (FcConfig *config, 6192c393a42Smrg FcSetName set) 6202c393a42Smrg{ 6212c393a42Smrg if (!config) 6222c393a42Smrg { 6232c393a42Smrg config = FcConfigGetCurrent (); 6242c393a42Smrg if (!config) 6252c393a42Smrg return 0; 6262c393a42Smrg } 6272c393a42Smrg return config->fonts[set]; 6282c393a42Smrg} 6292c393a42Smrg 6302c393a42Smrgvoid 6312c393a42SmrgFcConfigSetFonts (FcConfig *config, 6322c393a42Smrg FcFontSet *fonts, 6332c393a42Smrg FcSetName set) 6342c393a42Smrg{ 6352c393a42Smrg if (config->fonts[set]) 6362c393a42Smrg FcFontSetDestroy (config->fonts[set]); 6372c393a42Smrg config->fonts[set] = fonts; 6382c393a42Smrg} 6392c393a42Smrg 6401887081fSmrg 6412c393a42SmrgFcBlanks * 6421887081fSmrgFcBlanksCreate (void) 6432c393a42Smrg{ 6441887081fSmrg /* Deprecated. */ 6451887081fSmrg return NULL; 6461887081fSmrg} 6471887081fSmrg 6481887081fSmrgvoid 6491887081fSmrgFcBlanksDestroy (FcBlanks *b FC_UNUSED) 6501887081fSmrg{ 6511887081fSmrg /* Deprecated. */ 6522c393a42Smrg} 6532c393a42Smrg 6542c393a42SmrgFcBool 6551887081fSmrgFcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) 6562c393a42Smrg{ 6571887081fSmrg /* Deprecated. */ 6581887081fSmrg return FcFalse; 6591887081fSmrg} 660ca08ab68Smrg 6611887081fSmrgFcBool 6621887081fSmrgFcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) 6631887081fSmrg{ 6641887081fSmrg /* Deprecated. */ 6651887081fSmrg return FcFalse; 6661887081fSmrg} 6671887081fSmrg 6681887081fSmrgFcBlanks * 6691887081fSmrgFcConfigGetBlanks (FcConfig *config FC_UNUSED) 6701887081fSmrg{ 6711887081fSmrg /* Deprecated. */ 6721887081fSmrg return NULL; 6731887081fSmrg} 6741887081fSmrg 6751887081fSmrgFcBool 6761887081fSmrgFcConfigAddBlank (FcConfig *config FC_UNUSED, 6771887081fSmrg FcChar32 blank FC_UNUSED) 6781887081fSmrg{ 6791887081fSmrg /* Deprecated. */ 6801887081fSmrg return FcFalse; 6812c393a42Smrg} 6822c393a42Smrg 6831887081fSmrg 6842c393a42Smrgint 6852c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 6862c393a42Smrg{ 6872c393a42Smrg if (!config) 6882c393a42Smrg { 6892c393a42Smrg config = FcConfigGetCurrent (); 6902c393a42Smrg if (!config) 6912c393a42Smrg return 0; 6922c393a42Smrg } 6932c393a42Smrg return config->rescanInterval; 6942c393a42Smrg} 6952c393a42Smrg 6962c393a42SmrgFcBool 6972c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 6982c393a42Smrg{ 6992c393a42Smrg if (!config) 7002c393a42Smrg { 7012c393a42Smrg config = FcConfigGetCurrent (); 7022c393a42Smrg if (!config) 7032c393a42Smrg return FcFalse; 7042c393a42Smrg } 7052c393a42Smrg config->rescanInterval = rescanInterval; 7062c393a42Smrg return FcTrue; 7072c393a42Smrg} 7082c393a42Smrg 7092c393a42Smrg/* 7102c393a42Smrg * A couple of typos escaped into the library 7112c393a42Smrg */ 7122c393a42Smrgint 7132c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 7142c393a42Smrg{ 7152c393a42Smrg return FcConfigGetRescanInterval (config); 7162c393a42Smrg} 7172c393a42Smrg 7182c393a42SmrgFcBool 7192c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 7202c393a42Smrg{ 7212c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 7222c393a42Smrg} 7232c393a42Smrg 7242c393a42SmrgFcBool 7256fc018e4SmrgFcConfigAddRule (FcConfig *config, 7266fc018e4Smrg FcRule *rule, 7272c393a42Smrg FcMatchKind kind) 7282c393a42Smrg{ 7291887081fSmrg /* deprecated */ 7301887081fSmrg return FcFalse; 7312c393a42Smrg} 7322c393a42Smrg 7332c393a42Smrgstatic FcValue 734c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) 7352c393a42Smrg{ 7362c393a42Smrg if (v.type == FcTypeInteger) 7372c393a42Smrg { 7382c393a42Smrg v.type = FcTypeDouble; 7392c393a42Smrg v.u.d = (double) v.u.i; 7402c393a42Smrg } 7412c393a42Smrg else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 7422c393a42Smrg { 7432c393a42Smrg v.u.m = &FcIdentityMatrix; 7442c393a42Smrg v.type = FcTypeMatrix; 7452c393a42Smrg } 746c9710b42Smrg else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) 7472c393a42Smrg { 748c9710b42Smrg v.u.l = FcLangSetPromote (v.u.s, buf); 7492c393a42Smrg v.type = FcTypeLangSet; 7502c393a42Smrg } 7511887081fSmrg else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet) 75218bd4a06Smrg { 75318bd4a06Smrg v.u.l = FcLangSetPromote (NULL, buf); 75418bd4a06Smrg v.type = FcTypeLangSet; 75518bd4a06Smrg } 7561887081fSmrg else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet) 75718bd4a06Smrg { 75818bd4a06Smrg v.u.c = FcCharSetPromote (buf); 75918bd4a06Smrg v.type = FcTypeCharSet; 76018bd4a06Smrg } 76118bd4a06Smrg if (buf && v.type == FcTypeDouble && u.type == FcTypeRange) 76218bd4a06Smrg { 76318bd4a06Smrg v.u.r = FcRangePromote (v.u.d, buf); 76418bd4a06Smrg v.type = FcTypeRange; 76518bd4a06Smrg } 7662c393a42Smrg return v; 7672c393a42Smrg} 7682c393a42Smrg 7692c393a42SmrgFcBool 7702c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 7716fc018e4Smrg unsigned int op_, 7722c393a42Smrg const FcValue *right_o) 7732c393a42Smrg{ 7742c393a42Smrg FcValue left = FcValueCanonicalize(left_o); 7752c393a42Smrg FcValue right = FcValueCanonicalize(right_o); 7762c393a42Smrg FcBool ret = FcFalse; 777ca08ab68Smrg FcOp op = FC_OP_GET_OP (op_); 778ca08ab68Smrg int flags = FC_OP_GET_FLAGS (op_); 779c9710b42Smrg FcValuePromotionBuffer buf1, buf2; 780ca08ab68Smrg 781c9710b42Smrg left = FcConfigPromote (left, right, &buf1); 782c9710b42Smrg right = FcConfigPromote (right, left, &buf2); 783ca08ab68Smrg if (left.type == right.type) 7842c393a42Smrg { 7852c393a42Smrg switch (left.type) { 7866fc018e4Smrg case FcTypeUnknown: 7876fc018e4Smrg break; /* No way to guess how to compare for this object */ 7882c393a42Smrg case FcTypeInteger: 7892c393a42Smrg break; /* FcConfigPromote prevents this from happening */ 7902c393a42Smrg case FcTypeDouble: 791c9710b42Smrg switch ((int) op) { 7922c393a42Smrg case FcOpEqual: 7932c393a42Smrg case FcOpContains: 7942c393a42Smrg case FcOpListing: 7952c393a42Smrg ret = left.u.d == right.u.d; 7962c393a42Smrg break; 7972c393a42Smrg case FcOpNotEqual: 7982c393a42Smrg case FcOpNotContains: 7992c393a42Smrg ret = left.u.d != right.u.d; 8002c393a42Smrg break; 801ca08ab68Smrg case FcOpLess: 8022c393a42Smrg ret = left.u.d < right.u.d; 8032c393a42Smrg break; 804ca08ab68Smrg case FcOpLessEqual: 8052c393a42Smrg ret = left.u.d <= right.u.d; 8062c393a42Smrg break; 807ca08ab68Smrg case FcOpMore: 8082c393a42Smrg ret = left.u.d > right.u.d; 8092c393a42Smrg break; 810ca08ab68Smrg case FcOpMoreEqual: 8112c393a42Smrg ret = left.u.d >= right.u.d; 8122c393a42Smrg break; 8132c393a42Smrg default: 8142c393a42Smrg break; 8152c393a42Smrg } 8162c393a42Smrg break; 8172c393a42Smrg case FcTypeBool: 818c9710b42Smrg switch ((int) op) { 819ca08ab68Smrg case FcOpEqual: 8201887081fSmrg ret = left.u.b == right.u.b; 8211887081fSmrg break; 8222c393a42Smrg case FcOpContains: 8232c393a42Smrg case FcOpListing: 8241887081fSmrg ret = left.u.b == right.u.b || left.u.b == FcDontCare; 8252c393a42Smrg break; 8262c393a42Smrg case FcOpNotEqual: 8272c393a42Smrg ret = left.u.b != right.u.b; 8282c393a42Smrg break; 8291887081fSmrg case FcOpNotContains: 8301887081fSmrg ret = !(left.u.b == right.u.b || left.u.b == FcDontCare); 8311887081fSmrg break; 8321887081fSmrg case FcOpLess: 8331887081fSmrg ret = left.u.b != right.u.b && right.u.b == FcDontCare; 8341887081fSmrg break; 8351887081fSmrg case FcOpLessEqual: 8361887081fSmrg ret = left.u.b == right.u.b || right.u.b == FcDontCare; 8371887081fSmrg break; 8381887081fSmrg case FcOpMore: 8391887081fSmrg ret = left.u.b != right.u.b && left.u.b == FcDontCare; 8401887081fSmrg break; 8411887081fSmrg case FcOpMoreEqual: 8421887081fSmrg ret = left.u.b == right.u.b || left.u.b == FcDontCare; 8431887081fSmrg break; 8442c393a42Smrg default: 8452c393a42Smrg break; 8462c393a42Smrg } 8472c393a42Smrg break; 8482c393a42Smrg case FcTypeString: 849c9710b42Smrg switch ((int) op) { 850ca08ab68Smrg case FcOpEqual: 8512c393a42Smrg case FcOpListing: 852ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 853ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 854ca08ab68Smrg else 855ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 8562c393a42Smrg break; 8572c393a42Smrg case FcOpContains: 8582c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 8592c393a42Smrg break; 8602c393a42Smrg case FcOpNotEqual: 861ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 862ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 863ca08ab68Smrg else 864ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 8652c393a42Smrg break; 8662c393a42Smrg case FcOpNotContains: 8672c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 8682c393a42Smrg break; 8692c393a42Smrg default: 8702c393a42Smrg break; 8712c393a42Smrg } 8722c393a42Smrg break; 8732c393a42Smrg case FcTypeMatrix: 874c9710b42Smrg switch ((int) op) { 8752c393a42Smrg case FcOpEqual: 8762c393a42Smrg case FcOpContains: 8772c393a42Smrg case FcOpListing: 8782c393a42Smrg ret = FcMatrixEqual (left.u.m, right.u.m); 8792c393a42Smrg break; 8802c393a42Smrg case FcOpNotEqual: 8812c393a42Smrg case FcOpNotContains: 8822c393a42Smrg ret = !FcMatrixEqual (left.u.m, right.u.m); 8832c393a42Smrg break; 8842c393a42Smrg default: 8852c393a42Smrg break; 8862c393a42Smrg } 8872c393a42Smrg break; 8882c393a42Smrg case FcTypeCharSet: 889c9710b42Smrg switch ((int) op) { 8902c393a42Smrg case FcOpContains: 8912c393a42Smrg case FcOpListing: 8922c393a42Smrg /* left contains right if right is a subset of left */ 8932c393a42Smrg ret = FcCharSetIsSubset (right.u.c, left.u.c); 8942c393a42Smrg break; 8952c393a42Smrg case FcOpNotContains: 8962c393a42Smrg /* left contains right if right is a subset of left */ 8972c393a42Smrg ret = !FcCharSetIsSubset (right.u.c, left.u.c); 8982c393a42Smrg break; 8992c393a42Smrg case FcOpEqual: 9002c393a42Smrg ret = FcCharSetEqual (left.u.c, right.u.c); 9012c393a42Smrg break; 9022c393a42Smrg case FcOpNotEqual: 9032c393a42Smrg ret = !FcCharSetEqual (left.u.c, right.u.c); 9042c393a42Smrg break; 9052c393a42Smrg default: 9062c393a42Smrg break; 9072c393a42Smrg } 9082c393a42Smrg break; 9092c393a42Smrg case FcTypeLangSet: 910c9710b42Smrg switch ((int) op) { 9112c393a42Smrg case FcOpContains: 9122c393a42Smrg case FcOpListing: 9132c393a42Smrg ret = FcLangSetContains (left.u.l, right.u.l); 9142c393a42Smrg break; 9152c393a42Smrg case FcOpNotContains: 9162c393a42Smrg ret = !FcLangSetContains (left.u.l, right.u.l); 9172c393a42Smrg break; 9182c393a42Smrg case FcOpEqual: 9192c393a42Smrg ret = FcLangSetEqual (left.u.l, right.u.l); 9202c393a42Smrg break; 9212c393a42Smrg case FcOpNotEqual: 9222c393a42Smrg ret = !FcLangSetEqual (left.u.l, right.u.l); 9232c393a42Smrg break; 9242c393a42Smrg default: 9252c393a42Smrg break; 9262c393a42Smrg } 9272c393a42Smrg break; 9282c393a42Smrg case FcTypeVoid: 929c9710b42Smrg switch ((int) op) { 9302c393a42Smrg case FcOpEqual: 9312c393a42Smrg case FcOpContains: 9322c393a42Smrg case FcOpListing: 9332c393a42Smrg ret = FcTrue; 9342c393a42Smrg break; 9352c393a42Smrg default: 9362c393a42Smrg break; 9372c393a42Smrg } 9382c393a42Smrg break; 9392c393a42Smrg case FcTypeFTFace: 940c9710b42Smrg switch ((int) op) { 9412c393a42Smrg case FcOpEqual: 9422c393a42Smrg case FcOpContains: 9432c393a42Smrg case FcOpListing: 9442c393a42Smrg ret = left.u.f == right.u.f; 9452c393a42Smrg break; 9462c393a42Smrg case FcOpNotEqual: 9472c393a42Smrg case FcOpNotContains: 9482c393a42Smrg ret = left.u.f != right.u.f; 9492c393a42Smrg break; 9502c393a42Smrg default: 9512c393a42Smrg break; 9522c393a42Smrg } 9532c393a42Smrg break; 95418bd4a06Smrg case FcTypeRange: 95518bd4a06Smrg ret = FcRangeCompare (op, left.u.r, right.u.r); 95618bd4a06Smrg break; 9572c393a42Smrg } 9582c393a42Smrg } 9592c393a42Smrg else 9602c393a42Smrg { 9612c393a42Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 9622c393a42Smrg ret = FcTrue; 9632c393a42Smrg } 9642c393a42Smrg return ret; 9652c393a42Smrg} 9662c393a42Smrg 9672c393a42Smrg 9682c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 9692c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 9702c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 9712c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 9722c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 9732c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 9742c393a42Smrg 9752c393a42Smrgstatic FcValue 976c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) 9772c393a42Smrg{ 97818bd4a06Smrg FcValue v, vl, vr, vle, vre; 9792c393a42Smrg FcMatrix *m; 9802c393a42Smrg FcChar8 *str; 981ca08ab68Smrg FcOp op = FC_OP_GET_OP (e->op); 98218bd4a06Smrg FcValuePromotionBuffer buf1, buf2; 983ca08ab68Smrg 984c9710b42Smrg switch ((int) op) { 9852c393a42Smrg case FcOpInteger: 9862c393a42Smrg v.type = FcTypeInteger; 9872c393a42Smrg v.u.i = e->u.ival; 9882c393a42Smrg break; 9892c393a42Smrg case FcOpDouble: 9902c393a42Smrg v.type = FcTypeDouble; 9912c393a42Smrg v.u.d = e->u.dval; 9922c393a42Smrg break; 9932c393a42Smrg case FcOpString: 9942c393a42Smrg v.type = FcTypeString; 995a6844aabSmrg v.u.s = e->u.sval; 996a6844aabSmrg v = FcValueSave (v); 9972c393a42Smrg break; 9982c393a42Smrg case FcOpMatrix: 999c9710b42Smrg { 1000c9710b42Smrg FcMatrix m; 1001c9710b42Smrg FcValue xx, xy, yx, yy; 1002c9710b42Smrg v.type = FcTypeMatrix; 1003c9710b42Smrg xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); 1004c9710b42Smrg xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); 1005c9710b42Smrg yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); 1006c9710b42Smrg yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); 1007c9710b42Smrg if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && 1008c9710b42Smrg yx.type == FcTypeDouble && yy.type == FcTypeDouble) 1009c9710b42Smrg { 1010c9710b42Smrg m.xx = xx.u.d; 1011c9710b42Smrg m.xy = xy.u.d; 1012c9710b42Smrg m.yx = yx.u.d; 1013c9710b42Smrg m.yy = yy.u.d; 1014c9710b42Smrg v.u.m = &m; 1015c9710b42Smrg } 1016c9710b42Smrg else 1017c9710b42Smrg v.type = FcTypeVoid; 1018c9710b42Smrg v = FcValueSave (v); 1019c9710b42Smrg } 10202c393a42Smrg break; 10212c393a42Smrg case FcOpCharSet: 10222c393a42Smrg v.type = FcTypeCharSet; 10232c393a42Smrg v.u.c = e->u.cval; 10242c393a42Smrg v = FcValueSave (v); 10252c393a42Smrg break; 1026ca08ab68Smrg case FcOpLangSet: 1027ca08ab68Smrg v.type = FcTypeLangSet; 1028ca08ab68Smrg v.u.l = e->u.lval; 1029ca08ab68Smrg v = FcValueSave (v); 1030ca08ab68Smrg break; 103118bd4a06Smrg case FcOpRange: 103218bd4a06Smrg v.type = FcTypeRange; 103318bd4a06Smrg v.u.r = e->u.rval; 103418bd4a06Smrg v = FcValueSave (v); 103518bd4a06Smrg break; 10362c393a42Smrg case FcOpBool: 10372c393a42Smrg v.type = FcTypeBool; 10382c393a42Smrg v.u.b = e->u.bval; 10392c393a42Smrg break; 10402c393a42Smrg case FcOpField: 1041c9710b42Smrg if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) 1042c9710b42Smrg { 1043c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) 1044c9710b42Smrg v.type = FcTypeVoid; 1045c9710b42Smrg } 1046c9710b42Smrg else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) 1047c9710b42Smrg { 1048c9710b42Smrg fprintf (stderr, 1049c9710b42Smrg "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); 10502c393a42Smrg v.type = FcTypeVoid; 1051c9710b42Smrg } 1052c9710b42Smrg else 1053c9710b42Smrg { 1054c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) 1055c9710b42Smrg v.type = FcTypeVoid; 1056c9710b42Smrg } 10572c393a42Smrg v = FcValueSave (v); 10582c393a42Smrg break; 10592c393a42Smrg case FcOpConst: 10602c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 10612c393a42Smrg v.type = FcTypeInteger; 10622c393a42Smrg else 10632c393a42Smrg v.type = FcTypeVoid; 10642c393a42Smrg break; 10652c393a42Smrg case FcOpQuest: 1066c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 10672c393a42Smrg if (vl.type == FcTypeBool) 10682c393a42Smrg { 10692c393a42Smrg if (vl.u.b) 1070c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); 10712c393a42Smrg else 1072c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right); 10732c393a42Smrg } 10742c393a42Smrg else 10752c393a42Smrg v.type = FcTypeVoid; 10762c393a42Smrg FcValueDestroy (vl); 10772c393a42Smrg break; 10782c393a42Smrg case FcOpEqual: 10792c393a42Smrg case FcOpNotEqual: 10802c393a42Smrg case FcOpLess: 10812c393a42Smrg case FcOpLessEqual: 10822c393a42Smrg case FcOpMore: 10832c393a42Smrg case FcOpMoreEqual: 10842c393a42Smrg case FcOpContains: 10852c393a42Smrg case FcOpNotContains: 10862c393a42Smrg case FcOpListing: 1087c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1088c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 10892c393a42Smrg v.type = FcTypeBool; 10902c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 10912c393a42Smrg FcValueDestroy (vl); 10922c393a42Smrg FcValueDestroy (vr); 10932c393a42Smrg break; 10942c393a42Smrg case FcOpOr: 10952c393a42Smrg case FcOpAnd: 10962c393a42Smrg case FcOpPlus: 10972c393a42Smrg case FcOpMinus: 10982c393a42Smrg case FcOpTimes: 10992c393a42Smrg case FcOpDivide: 1100c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1101c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 110218bd4a06Smrg vle = FcConfigPromote (vl, vr, &buf1); 110318bd4a06Smrg vre = FcConfigPromote (vr, vle, &buf2); 110418bd4a06Smrg if (vle.type == vre.type) 11052c393a42Smrg { 110618bd4a06Smrg switch ((int) vle.type) { 11072c393a42Smrg case FcTypeDouble: 1108c9710b42Smrg switch ((int) op) { 1109ca08ab68Smrg case FcOpPlus: 11102c393a42Smrg v.type = FcTypeDouble; 111118bd4a06Smrg v.u.d = vle.u.d + vre.u.d; 11122c393a42Smrg break; 11132c393a42Smrg case FcOpMinus: 11142c393a42Smrg v.type = FcTypeDouble; 111518bd4a06Smrg v.u.d = vle.u.d - vre.u.d; 11162c393a42Smrg break; 11172c393a42Smrg case FcOpTimes: 11182c393a42Smrg v.type = FcTypeDouble; 111918bd4a06Smrg v.u.d = vle.u.d * vre.u.d; 11202c393a42Smrg break; 11212c393a42Smrg case FcOpDivide: 11222c393a42Smrg v.type = FcTypeDouble; 112318bd4a06Smrg v.u.d = vle.u.d / vre.u.d; 11242c393a42Smrg break; 11252c393a42Smrg default: 1126ca08ab68Smrg v.type = FcTypeVoid; 11272c393a42Smrg break; 11282c393a42Smrg } 11292c393a42Smrg if (v.type == FcTypeDouble && 11302c393a42Smrg v.u.d == (double) (int) v.u.d) 11312c393a42Smrg { 11322c393a42Smrg v.type = FcTypeInteger; 11332c393a42Smrg v.u.i = (int) v.u.d; 11342c393a42Smrg } 11352c393a42Smrg break; 11362c393a42Smrg case FcTypeBool: 1137c9710b42Smrg switch ((int) op) { 11382c393a42Smrg case FcOpOr: 11392c393a42Smrg v.type = FcTypeBool; 114018bd4a06Smrg v.u.b = vle.u.b || vre.u.b; 11412c393a42Smrg break; 11422c393a42Smrg case FcOpAnd: 11432c393a42Smrg v.type = FcTypeBool; 114418bd4a06Smrg v.u.b = vle.u.b && vre.u.b; 11452c393a42Smrg break; 11462c393a42Smrg default: 1147ca08ab68Smrg v.type = FcTypeVoid; 11482c393a42Smrg break; 11492c393a42Smrg } 11502c393a42Smrg break; 11512c393a42Smrg case FcTypeString: 1152c9710b42Smrg switch ((int) op) { 11532c393a42Smrg case FcOpPlus: 11542c393a42Smrg v.type = FcTypeString; 115518bd4a06Smrg str = FcStrPlus (vle.u.s, vre.u.s); 1156c9710b42Smrg v.u.s = FcStrdup (str); 11572c393a42Smrg FcStrFree (str); 1158ca08ab68Smrg 11592c393a42Smrg if (!v.u.s) 11602c393a42Smrg v.type = FcTypeVoid; 11612c393a42Smrg break; 11622c393a42Smrg default: 11632c393a42Smrg v.type = FcTypeVoid; 11642c393a42Smrg break; 11652c393a42Smrg } 11662c393a42Smrg break; 11672c393a42Smrg case FcTypeMatrix: 1168c9710b42Smrg switch ((int) op) { 11692c393a42Smrg case FcOpTimes: 11702c393a42Smrg v.type = FcTypeMatrix; 11712c393a42Smrg m = malloc (sizeof (FcMatrix)); 11722c393a42Smrg if (m) 11732c393a42Smrg { 117418bd4a06Smrg FcMatrixMultiply (m, vle.u.m, vre.u.m); 11752c393a42Smrg v.u.m = m; 11762c393a42Smrg } 11772c393a42Smrg else 11782c393a42Smrg { 11792c393a42Smrg v.type = FcTypeVoid; 11802c393a42Smrg } 11812c393a42Smrg break; 11822c393a42Smrg default: 11832c393a42Smrg v.type = FcTypeVoid; 11842c393a42Smrg break; 11852c393a42Smrg } 11862c393a42Smrg break; 1187ca08ab68Smrg case FcTypeCharSet: 1188c9710b42Smrg switch ((int) op) { 1189ca08ab68Smrg case FcOpPlus: 1190ca08ab68Smrg v.type = FcTypeCharSet; 119118bd4a06Smrg v.u.c = FcCharSetUnion (vle.u.c, vre.u.c); 1192ca08ab68Smrg if (!v.u.c) 1193ca08ab68Smrg v.type = FcTypeVoid; 1194ca08ab68Smrg break; 1195ca08ab68Smrg case FcOpMinus: 1196ca08ab68Smrg v.type = FcTypeCharSet; 119718bd4a06Smrg v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c); 1198ca08ab68Smrg if (!v.u.c) 1199ca08ab68Smrg v.type = FcTypeVoid; 1200ca08ab68Smrg break; 1201ca08ab68Smrg default: 1202ca08ab68Smrg v.type = FcTypeVoid; 1203ca08ab68Smrg break; 1204ca08ab68Smrg } 1205ca08ab68Smrg break; 1206ca08ab68Smrg case FcTypeLangSet: 1207c9710b42Smrg switch ((int) op) { 1208ca08ab68Smrg case FcOpPlus: 1209ca08ab68Smrg v.type = FcTypeLangSet; 121018bd4a06Smrg v.u.l = FcLangSetUnion (vle.u.l, vre.u.l); 1211ca08ab68Smrg if (!v.u.l) 1212ca08ab68Smrg v.type = FcTypeVoid; 1213ca08ab68Smrg break; 1214ca08ab68Smrg case FcOpMinus: 1215ca08ab68Smrg v.type = FcTypeLangSet; 121618bd4a06Smrg v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l); 1217ca08ab68Smrg if (!v.u.l) 1218ca08ab68Smrg v.type = FcTypeVoid; 1219ca08ab68Smrg break; 1220ca08ab68Smrg default: 1221ca08ab68Smrg v.type = FcTypeVoid; 1222ca08ab68Smrg break; 1223ca08ab68Smrg } 1224ca08ab68Smrg break; 12252c393a42Smrg default: 12262c393a42Smrg v.type = FcTypeVoid; 12272c393a42Smrg break; 12282c393a42Smrg } 12292c393a42Smrg } 12302c393a42Smrg else 12312c393a42Smrg v.type = FcTypeVoid; 12322c393a42Smrg FcValueDestroy (vl); 12332c393a42Smrg FcValueDestroy (vr); 12342c393a42Smrg break; 12352c393a42Smrg case FcOpNot: 1236c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1237c9710b42Smrg switch ((int) vl.type) { 12382c393a42Smrg case FcTypeBool: 12392c393a42Smrg v.type = FcTypeBool; 12402c393a42Smrg v.u.b = !vl.u.b; 12412c393a42Smrg break; 12422c393a42Smrg default: 12432c393a42Smrg v.type = FcTypeVoid; 12442c393a42Smrg break; 12452c393a42Smrg } 12462c393a42Smrg FcValueDestroy (vl); 12472c393a42Smrg break; 12482c393a42Smrg case FcOpFloor: 1249c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1250c9710b42Smrg switch ((int) vl.type) { 12512c393a42Smrg case FcTypeInteger: 12522c393a42Smrg v = vl; 12532c393a42Smrg break; 12542c393a42Smrg case FcTypeDouble: 12552c393a42Smrg v.type = FcTypeInteger; 12562c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 12572c393a42Smrg break; 12582c393a42Smrg default: 12592c393a42Smrg v.type = FcTypeVoid; 12602c393a42Smrg break; 12612c393a42Smrg } 12622c393a42Smrg FcValueDestroy (vl); 12632c393a42Smrg break; 12642c393a42Smrg case FcOpCeil: 1265c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1266c9710b42Smrg switch ((int) vl.type) { 12672c393a42Smrg case FcTypeInteger: 12682c393a42Smrg v = vl; 12692c393a42Smrg break; 12702c393a42Smrg case FcTypeDouble: 12712c393a42Smrg v.type = FcTypeInteger; 12722c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 12732c393a42Smrg break; 12742c393a42Smrg default: 12752c393a42Smrg v.type = FcTypeVoid; 12762c393a42Smrg break; 12772c393a42Smrg } 12782c393a42Smrg FcValueDestroy (vl); 12792c393a42Smrg break; 12802c393a42Smrg case FcOpRound: 1281c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1282c9710b42Smrg switch ((int) vl.type) { 12832c393a42Smrg case FcTypeInteger: 12842c393a42Smrg v = vl; 12852c393a42Smrg break; 12862c393a42Smrg case FcTypeDouble: 12872c393a42Smrg v.type = FcTypeInteger; 12882c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 12892c393a42Smrg break; 12902c393a42Smrg default: 12912c393a42Smrg v.type = FcTypeVoid; 12922c393a42Smrg break; 12932c393a42Smrg } 12942c393a42Smrg FcValueDestroy (vl); 12952c393a42Smrg break; 12962c393a42Smrg case FcOpTrunc: 1297c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1298c9710b42Smrg switch ((int) vl.type) { 12992c393a42Smrg case FcTypeInteger: 13002c393a42Smrg v = vl; 13012c393a42Smrg break; 13022c393a42Smrg case FcTypeDouble: 13032c393a42Smrg v.type = FcTypeInteger; 13042c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 13052c393a42Smrg break; 13062c393a42Smrg default: 13072c393a42Smrg v.type = FcTypeVoid; 13082c393a42Smrg break; 13092c393a42Smrg } 13102c393a42Smrg FcValueDestroy (vl); 13112c393a42Smrg break; 13122c393a42Smrg default: 13132c393a42Smrg v.type = FcTypeVoid; 13142c393a42Smrg break; 13152c393a42Smrg } 13162c393a42Smrg return v; 13172c393a42Smrg} 13182c393a42Smrg 13192c393a42Smrgstatic FcValueList * 13202c393a42SmrgFcConfigMatchValueList (FcPattern *p, 1321c9710b42Smrg FcPattern *p_pat, 1322c9710b42Smrg FcMatchKind kind, 13232c393a42Smrg FcTest *t, 13242c393a42Smrg FcValueList *values) 13252c393a42Smrg{ 13262c393a42Smrg FcValueList *ret = 0; 13272c393a42Smrg FcExpr *e = t->expr; 13282c393a42Smrg FcValue value; 13292c393a42Smrg FcValueList *v; 1330ca08ab68Smrg 13312c393a42Smrg while (e) 13322c393a42Smrg { 13332c393a42Smrg /* Compute the value of the match expression */ 1334ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 13352c393a42Smrg { 1336c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 13372c393a42Smrg e = e->u.tree.right; 13382c393a42Smrg } 13392c393a42Smrg else 13402c393a42Smrg { 1341c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e); 13422c393a42Smrg e = 0; 13432c393a42Smrg } 13442c393a42Smrg 13452c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 13462c393a42Smrg { 13472c393a42Smrg /* Compare the pattern value to the match expression value */ 13482c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 13492c393a42Smrg { 13502c393a42Smrg if (!ret) 13512c393a42Smrg ret = v; 13522c393a42Smrg } 13532c393a42Smrg else 13542c393a42Smrg { 13552c393a42Smrg if (t->qual == FcQualAll) 13562c393a42Smrg { 13572c393a42Smrg ret = 0; 13582c393a42Smrg break; 13592c393a42Smrg } 13602c393a42Smrg } 13612c393a42Smrg } 13622c393a42Smrg FcValueDestroy (value); 13632c393a42Smrg } 13642c393a42Smrg return ret; 13652c393a42Smrg} 13662c393a42Smrg 13672c393a42Smrgstatic FcValueList * 1368c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) 13692c393a42Smrg{ 13702c393a42Smrg FcValueList *l; 1371ca08ab68Smrg 13722c393a42Smrg if (!e) 13732c393a42Smrg return 0; 13742c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 13752c393a42Smrg if (!l) 13762c393a42Smrg return 0; 1377ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 13782c393a42Smrg { 1379c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1380c9710b42Smrg l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); 13812c393a42Smrg } 13822c393a42Smrg else 13832c393a42Smrg { 1384c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e); 13852c393a42Smrg l->next = NULL; 13862c393a42Smrg } 13872c393a42Smrg l->binding = binding; 13882c393a42Smrg if (l->value.type == FcTypeVoid) 13892c393a42Smrg { 13902c393a42Smrg FcValueList *next = FcValueListNext(l); 13912c393a42Smrg 13922c393a42Smrg free (l); 13932c393a42Smrg l = next; 13942c393a42Smrg } 13952c393a42Smrg 13962c393a42Smrg return l; 13972c393a42Smrg} 13982c393a42Smrg 13992c393a42Smrgstatic FcBool 14002c393a42SmrgFcConfigAdd (FcValueListPtr *head, 14012c393a42Smrg FcValueList *position, 14022c393a42Smrg FcBool append, 1403c9710b42Smrg FcValueList *new, 1404c9710b42Smrg FcObject object) 14052c393a42Smrg{ 1406c9710b42Smrg FcValueListPtr *prev, l, last, v; 14072c393a42Smrg FcValueBinding sameBinding; 1408ca08ab68Smrg 1409c9710b42Smrg /* 1410c9710b42Smrg * Make sure the stored type is valid for built-in objects 1411c9710b42Smrg */ 1412c9710b42Smrg for (l = new; l != NULL; l = FcValueListNext (l)) 1413c9710b42Smrg { 1414c9710b42Smrg if (!FcObjectValidType (object, l->value.type)) 1415c9710b42Smrg { 1416c9710b42Smrg fprintf (stderr, 1417c9710b42Smrg "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 1418c9710b42Smrg FcValuePrintFile (stderr, l->value); 1419c9710b42Smrg fprintf (stderr, "\n"); 1420c9710b42Smrg 1421c9710b42Smrg if (FcDebug () & FC_DBG_EDIT) 1422c9710b42Smrg { 1423c9710b42Smrg printf ("Not adding\n"); 1424c9710b42Smrg } 1425c9710b42Smrg 1426c9710b42Smrg return FcFalse; 1427c9710b42Smrg } 1428c9710b42Smrg } 1429c9710b42Smrg 14302c393a42Smrg if (position) 14312c393a42Smrg sameBinding = position->binding; 14322c393a42Smrg else 14332c393a42Smrg sameBinding = FcValueBindingWeak; 14342c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 14352c393a42Smrg if (v->binding == FcValueBindingSame) 14362c393a42Smrg v->binding = sameBinding; 14372c393a42Smrg if (append) 14382c393a42Smrg { 14392c393a42Smrg if (position) 14402c393a42Smrg prev = &position->next; 14412c393a42Smrg else 1442ca08ab68Smrg for (prev = head; *prev != NULL; 14432c393a42Smrg prev = &(*prev)->next) 14442c393a42Smrg ; 14452c393a42Smrg } 14462c393a42Smrg else 14472c393a42Smrg { 14482c393a42Smrg if (position) 14492c393a42Smrg { 1450ca08ab68Smrg for (prev = head; *prev != NULL; 14512c393a42Smrg prev = &(*prev)->next) 14522c393a42Smrg { 14532c393a42Smrg if (*prev == position) 14542c393a42Smrg break; 14552c393a42Smrg } 14562c393a42Smrg } 14572c393a42Smrg else 14582c393a42Smrg prev = head; 14592c393a42Smrg 14602c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14612c393a42Smrg { 14622c393a42Smrg if (*prev == NULL) 14632c393a42Smrg printf ("position not on list\n"); 14642c393a42Smrg } 14652c393a42Smrg } 14662c393a42Smrg 14672c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14682c393a42Smrg { 14692c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 1470ca08ab68Smrg FcValueListPrintWithPosition (*head, *prev); 14712c393a42Smrg printf ("\n"); 14722c393a42Smrg } 1473ca08ab68Smrg 14742c393a42Smrg if (new) 14752c393a42Smrg { 14762c393a42Smrg last = new; 14772c393a42Smrg while (last->next != NULL) 14782c393a42Smrg last = last->next; 1479ca08ab68Smrg 14802c393a42Smrg last->next = *prev; 14812c393a42Smrg *prev = new; 14822c393a42Smrg } 1483ca08ab68Smrg 14842c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14852c393a42Smrg { 14862c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 14872c393a42Smrg FcValueListPrint (*head); 14882c393a42Smrg printf ("\n"); 14892c393a42Smrg } 1490ca08ab68Smrg 14912c393a42Smrg return FcTrue; 14922c393a42Smrg} 14932c393a42Smrg 14942c393a42Smrgstatic void 14952c393a42SmrgFcConfigDel (FcValueListPtr *head, 14962c393a42Smrg FcValueList *position) 14972c393a42Smrg{ 14982c393a42Smrg FcValueListPtr *prev; 14992c393a42Smrg 15002c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 15012c393a42Smrg { 15022c393a42Smrg if (*prev == position) 15032c393a42Smrg { 15042c393a42Smrg *prev = position->next; 15052c393a42Smrg position->next = NULL; 15062c393a42Smrg FcValueListDestroy (position); 15072c393a42Smrg break; 15082c393a42Smrg } 15092c393a42Smrg } 15102c393a42Smrg} 15112c393a42Smrg 15122c393a42Smrgstatic void 15132c393a42SmrgFcConfigPatternAdd (FcPattern *p, 15142c393a42Smrg FcObject object, 15152c393a42Smrg FcValueList *list, 15162c393a42Smrg FcBool append) 15172c393a42Smrg{ 15182c393a42Smrg if (list) 15192c393a42Smrg { 15202c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1521ca08ab68Smrg 15222c393a42Smrg if (!e) 15232c393a42Smrg return; 1524c9710b42Smrg FcConfigAdd (&e->values, 0, append, list, object); 15252c393a42Smrg } 15262c393a42Smrg} 15272c393a42Smrg 15282c393a42Smrg/* 15292c393a42Smrg * Delete all values associated with a field 15302c393a42Smrg */ 15312c393a42Smrgstatic void 15322c393a42SmrgFcConfigPatternDel (FcPattern *p, 15332c393a42Smrg FcObject object) 15342c393a42Smrg{ 15352c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 15362c393a42Smrg if (!e) 15372c393a42Smrg return; 15382c393a42Smrg while (e->values != NULL) 15392c393a42Smrg FcConfigDel (&e->values, e->values); 15402c393a42Smrg} 15412c393a42Smrg 15422c393a42Smrgstatic void 15432c393a42SmrgFcConfigPatternCanon (FcPattern *p, 15442c393a42Smrg FcObject object) 15452c393a42Smrg{ 15462c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 15472c393a42Smrg if (!e) 15482c393a42Smrg return; 15492c393a42Smrg if (e->values == NULL) 15502c393a42Smrg FcPatternObjectDel (p, object); 15512c393a42Smrg} 15522c393a42Smrg 15532c393a42SmrgFcBool 15542c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 15552c393a42Smrg FcPattern *p, 15562c393a42Smrg FcPattern *p_pat, 15572c393a42Smrg FcMatchKind kind) 15582c393a42Smrg{ 1559c9710b42Smrg FcValue v; 15601887081fSmrg FcPtrList *s; 15611887081fSmrg FcPtrListIter iter, iter2; 15626fc018e4Smrg FcRule *r; 15631887081fSmrg FcRuleSet *rs; 15646fc018e4Smrg FcValueList *l, **value = NULL, *vl; 15652c393a42Smrg FcPattern *m; 1566ca08ab68Smrg FcStrSet *strs; 15676fc018e4Smrg FcObject object = FC_INVALID_OBJECT; 15686fc018e4Smrg FcPatternElt **elt = NULL, *e; 15696fc018e4Smrg int i, nobjs; 15706fc018e4Smrg FcBool retval = FcTrue; 15716fc018e4Smrg FcTest **tst = NULL; 15722c393a42Smrg 15732c393a42Smrg if (!config) 15742c393a42Smrg { 15752c393a42Smrg config = FcConfigGetCurrent (); 15762c393a42Smrg if (!config) 15772c393a42Smrg return FcFalse; 15782c393a42Smrg } 15792c393a42Smrg 15801887081fSmrg if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd) 15811887081fSmrg return FcFalse; 15821887081fSmrg s = config->subst[kind]; 15831887081fSmrg if (kind == FcMatchPattern) 15841887081fSmrg { 1585ca08ab68Smrg strs = FcGetDefaultLangs (); 1586ca08ab68Smrg if (strs) 1587ca08ab68Smrg { 1588ca08ab68Smrg FcStrList *l = FcStrListCreate (strs); 1589ca08ab68Smrg FcChar8 *lang; 1590ca08ab68Smrg FcValue v; 159118bd4a06Smrg FcLangSet *lsund = FcLangSetCreate (); 1592ca08ab68Smrg 159318bd4a06Smrg FcLangSetAdd (lsund, (const FcChar8 *)"und"); 1594ca08ab68Smrg FcStrSetDestroy (strs); 1595ca08ab68Smrg while (l && (lang = FcStrListNext (l))) 1596ca08ab68Smrg { 159718bd4a06Smrg FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT); 159818bd4a06Smrg 159918bd4a06Smrg if (e) 160018bd4a06Smrg { 160118bd4a06Smrg FcValueListPtr ll; 160218bd4a06Smrg 160318bd4a06Smrg for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll)) 160418bd4a06Smrg { 160518bd4a06Smrg FcValue vv = FcValueCanonicalize (&ll->value); 160618bd4a06Smrg 160718bd4a06Smrg if (vv.type == FcTypeLangSet) 160818bd4a06Smrg { 160918bd4a06Smrg FcLangSet *ls = FcLangSetCreate (); 161018bd4a06Smrg FcBool b; 161118bd4a06Smrg 161218bd4a06Smrg FcLangSetAdd (ls, lang); 161318bd4a06Smrg b = FcLangSetContains (vv.u.l, ls); 161418bd4a06Smrg FcLangSetDestroy (ls); 161518bd4a06Smrg if (b) 161618bd4a06Smrg goto bail_lang; 161718bd4a06Smrg if (FcLangSetContains (vv.u.l, lsund)) 161818bd4a06Smrg goto bail_lang; 161918bd4a06Smrg } 162018bd4a06Smrg else 162118bd4a06Smrg { 162218bd4a06Smrg if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0) 162318bd4a06Smrg goto bail_lang; 162418bd4a06Smrg if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0) 162518bd4a06Smrg goto bail_lang; 162618bd4a06Smrg } 162718bd4a06Smrg } 162818bd4a06Smrg } 1629ca08ab68Smrg v.type = FcTypeString; 1630ca08ab68Smrg v.u.s = lang; 163118bd4a06Smrg 1632ca08ab68Smrg FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1633ca08ab68Smrg } 163418bd4a06Smrg bail_lang: 1635ca08ab68Smrg FcStrListDone (l); 163618bd4a06Smrg FcLangSetDestroy (lsund); 1637ca08ab68Smrg } 1638c9710b42Smrg if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) 1639c9710b42Smrg { 1640c9710b42Smrg FcChar8 *prgname = FcGetPrgname (); 1641c9710b42Smrg if (prgname) 1642c9710b42Smrg FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); 1643c9710b42Smrg } 16442c393a42Smrg } 16452c393a42Smrg 16466fc018e4Smrg nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; 1647cc1bebd6Smrg value = (FcValueList **) malloc (sizeof(void *) * nobjs); 16486fc018e4Smrg if (!value) 16496fc018e4Smrg { 16506fc018e4Smrg retval = FcFalse; 16516fc018e4Smrg goto bail1; 16526fc018e4Smrg } 1653cc1bebd6Smrg elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs); 16546fc018e4Smrg if (!elt) 16556fc018e4Smrg { 16566fc018e4Smrg retval = FcFalse; 16576fc018e4Smrg goto bail1; 16586fc018e4Smrg } 1659cc1bebd6Smrg tst = (FcTest **) malloc (sizeof(void *) * nobjs); 16606fc018e4Smrg if (!tst) 16616fc018e4Smrg { 16626fc018e4Smrg retval = FcFalse; 16636fc018e4Smrg goto bail1; 16646fc018e4Smrg } 16652c393a42Smrg 16662c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 16672c393a42Smrg { 16682c393a42Smrg printf ("FcConfigSubstitute "); 16692c393a42Smrg FcPatternPrint (p); 16702c393a42Smrg } 16711887081fSmrg FcPtrListIterInit (s, &iter); 16721887081fSmrg for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter)) 16732c393a42Smrg { 16741887081fSmrg rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter); 16751887081fSmrg if (FcDebug () & FC_DBG_EDIT) 16762c393a42Smrg { 16771887081fSmrg printf ("\nRule Set: %s\n", rs->name); 16786fc018e4Smrg } 16791887081fSmrg FcPtrListIterInit (rs->subst[kind], &iter2); 16801887081fSmrg for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2)) 16816fc018e4Smrg { 16821887081fSmrg r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2); 16831887081fSmrg for (i = 0; i < nobjs; i++) 16841887081fSmrg { 16851887081fSmrg elt[i] = NULL; 16861887081fSmrg value[i] = NULL; 16871887081fSmrg tst[i] = NULL; 16881887081fSmrg } 16891887081fSmrg for (; r; r = r->next) 16901887081fSmrg { 16911887081fSmrg switch (r->type) { 16921887081fSmrg case FcRuleUnknown: 16931887081fSmrg /* shouldn't be reached */ 16941887081fSmrg break; 16951887081fSmrg case FcRuleTest: 16961887081fSmrg object = FC_OBJ_ID (r->u.test->object); 16971887081fSmrg /* 16981887081fSmrg * Check the tests to see if 16991887081fSmrg * they all match the pattern 17001887081fSmrg */ 17011887081fSmrg if (FcDebug () & FC_DBG_EDIT) 17026fc018e4Smrg { 17031887081fSmrg printf ("FcConfigSubstitute test "); 17041887081fSmrg FcTestPrint (r->u.test); 17056fc018e4Smrg } 17061887081fSmrg if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) 17071887081fSmrg m = p_pat; 17086fc018e4Smrg else 17091887081fSmrg m = p; 17101887081fSmrg if (m) 17111887081fSmrg e = FcPatternObjectFindElt (m, r->u.test->object); 17121887081fSmrg else 17131887081fSmrg e = NULL; 17141887081fSmrg /* different 'kind' won't be the target of edit */ 17151887081fSmrg if (!elt[object] && kind == r->u.test->kind) 17161887081fSmrg { 17171887081fSmrg elt[object] = e; 17181887081fSmrg tst[object] = r->u.test; 17191887081fSmrg } 17201887081fSmrg /* 17211887081fSmrg * If there's no such field in the font, 17221887081fSmrg * then FcQualAll matches while FcQualAny does not 17231887081fSmrg */ 17241887081fSmrg if (!e) 17251887081fSmrg { 17261887081fSmrg if (r->u.test->qual == FcQualAll) 17271887081fSmrg { 17281887081fSmrg value[object] = NULL; 17291887081fSmrg continue; 17301887081fSmrg } 17311887081fSmrg else 17321887081fSmrg { 17331887081fSmrg if (FcDebug () & FC_DBG_EDIT) 17341887081fSmrg printf ("No match\n"); 17351887081fSmrg goto bail; 17361887081fSmrg } 17371887081fSmrg } 17381887081fSmrg /* 17391887081fSmrg * Check to see if there is a match, mark the location 17401887081fSmrg * to apply match-relative edits 17411887081fSmrg */ 17421887081fSmrg vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); 17431887081fSmrg /* different 'kind' won't be the target of edit */ 17441887081fSmrg if (!value[object] && kind == r->u.test->kind) 17451887081fSmrg value[object] = vl; 17461887081fSmrg if (!vl || 17471887081fSmrg (r->u.test->qual == FcQualFirst && vl != e->values) || 17481887081fSmrg (r->u.test->qual == FcQualNotFirst && vl == e->values)) 17496fc018e4Smrg { 17506fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 17516fc018e4Smrg printf ("No match\n"); 17526fc018e4Smrg goto bail; 17536fc018e4Smrg } 17541887081fSmrg break; 17551887081fSmrg case FcRuleEdit: 17561887081fSmrg object = FC_OBJ_ID (r->u.edit->object); 17576fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 17581887081fSmrg { 17591887081fSmrg printf ("Substitute "); 17601887081fSmrg FcEditPrint (r->u.edit); 17611887081fSmrg printf ("\n\n"); 17621887081fSmrg } 17632c393a42Smrg /* 17641887081fSmrg * Evaluate the list of expressions 17652c393a42Smrg */ 17661887081fSmrg l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); 17671887081fSmrg if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) 17681887081fSmrg elt[object] = FcPatternObjectFindElt (p, tst[object]->object); 17696fc018e4Smrg 17701887081fSmrg switch (FC_OP_GET_OP (r->u.edit->op)) { 17711887081fSmrg case FcOpAssign: 17726fc018e4Smrg /* 17731887081fSmrg * If there was a test, then replace the matched 17741887081fSmrg * value with the new list of values 17756fc018e4Smrg */ 17761887081fSmrg if (value[object]) 17771887081fSmrg { 17781887081fSmrg FcValueList *thisValue = value[object]; 17791887081fSmrg FcValueList *nextValue = l; 17801887081fSmrg 17811887081fSmrg /* 17821887081fSmrg * Append the new list of values after the current value 17831887081fSmrg */ 17841887081fSmrg FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); 17851887081fSmrg /* 17861887081fSmrg * Delete the marked value 17871887081fSmrg */ 17881887081fSmrg if (thisValue) 17891887081fSmrg FcConfigDel (&elt[object]->values, thisValue); 17901887081fSmrg /* 17911887081fSmrg * Adjust a pointer into the value list to ensure 17921887081fSmrg * future edits occur at the same place 17931887081fSmrg */ 17941887081fSmrg value[object] = nextValue; 17951887081fSmrg break; 17961887081fSmrg } 17971887081fSmrg /* fall through ... */ 17981887081fSmrg case FcOpAssignReplace: 17996fc018e4Smrg /* 18001887081fSmrg * Delete all of the values and insert 18011887081fSmrg * the new set 18026fc018e4Smrg */ 18031887081fSmrg FcConfigPatternDel (p, r->u.edit->object); 18041887081fSmrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 18056fc018e4Smrg /* 18061887081fSmrg * Adjust a pointer into the value list as they no 18071887081fSmrg * longer point to anything valid 18086fc018e4Smrg */ 18091887081fSmrg value[object] = NULL; 18106fc018e4Smrg break; 18111887081fSmrg case FcOpPrepend: 18121887081fSmrg if (value[object]) 18131887081fSmrg { 18141887081fSmrg FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); 18151887081fSmrg break; 18161887081fSmrg } 18171887081fSmrg /* fall through ... */ 18181887081fSmrg case FcOpPrependFirst: 18191887081fSmrg FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); 18206fc018e4Smrg break; 18211887081fSmrg case FcOpAppend: 18221887081fSmrg if (value[object]) 18231887081fSmrg { 18241887081fSmrg FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); 18251887081fSmrg break; 18261887081fSmrg } 18271887081fSmrg /* fall through ... */ 18281887081fSmrg case FcOpAppendLast: 18291887081fSmrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 18301887081fSmrg break; 18311887081fSmrg case FcOpDelete: 18321887081fSmrg if (value[object]) 18331887081fSmrg { 18341887081fSmrg FcConfigDel (&elt[object]->values, value[object]); 18351887081fSmrg FcValueListDestroy (l); 18361887081fSmrg break; 18371887081fSmrg } 18381887081fSmrg /* fall through ... */ 18391887081fSmrg case FcOpDeleteAll: 18401887081fSmrg FcConfigPatternDel (p, r->u.edit->object); 18411887081fSmrg FcValueListDestroy (l); 18421887081fSmrg break; 18431887081fSmrg default: 18441887081fSmrg FcValueListDestroy (l); 18456fc018e4Smrg break; 18462c393a42Smrg } 18471887081fSmrg /* 18481887081fSmrg * Now go through the pattern and eliminate 18491887081fSmrg * any properties without data 18501887081fSmrg */ 18511887081fSmrg FcConfigPatternCanon (p, r->u.edit->object); 18521887081fSmrg 18531887081fSmrg if (FcDebug () & FC_DBG_EDIT) 18546fc018e4Smrg { 18551887081fSmrg printf ("FcConfigSubstitute edit"); 18561887081fSmrg FcPatternPrint (p); 18576fc018e4Smrg } 18582c393a42Smrg break; 18592c393a42Smrg } 18602c393a42Smrg } 18611887081fSmrg bail:; 18622c393a42Smrg } 18632c393a42Smrg } 18642c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 18652c393a42Smrg { 18662c393a42Smrg printf ("FcConfigSubstitute done"); 18672c393a42Smrg FcPatternPrint (p); 18682c393a42Smrg } 18696fc018e4Smrgbail1: 18706fc018e4Smrg if (elt) 18716fc018e4Smrg free (elt); 18726fc018e4Smrg if (value) 18736fc018e4Smrg free (value); 18746fc018e4Smrg if (tst) 18756fc018e4Smrg free (tst); 18766fc018e4Smrg 18776fc018e4Smrg return retval; 18782c393a42Smrg} 18792c393a42Smrg 18802c393a42SmrgFcBool 18812c393a42SmrgFcConfigSubstitute (FcConfig *config, 18822c393a42Smrg FcPattern *p, 18832c393a42Smrg FcMatchKind kind) 18842c393a42Smrg{ 18852c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 18862c393a42Smrg} 18872c393a42Smrg 18882c393a42Smrg#if defined (_WIN32) 18892c393a42Smrg 1890c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ 189118bd4a06SmrgFcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */ 18922c393a42Smrg 18932c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 18942c393a42Smrg 1895c9710b42SmrgBOOL WINAPI 1896c9710b42SmrgDllMain (HINSTANCE hinstDLL, 1897c9710b42Smrg DWORD fdwReason, 1898c9710b42Smrg LPVOID lpvReserved); 1899c9710b42Smrg 19002c393a42SmrgBOOL WINAPI 19012c393a42SmrgDllMain (HINSTANCE hinstDLL, 19022c393a42Smrg DWORD fdwReason, 19032c393a42Smrg LPVOID lpvReserved) 19042c393a42Smrg{ 19052c393a42Smrg FcChar8 *p; 19062c393a42Smrg 19072c393a42Smrg switch (fdwReason) { 19082c393a42Smrg case DLL_PROCESS_ATTACH: 1909ca08ab68Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 19102c393a42Smrg sizeof (fontconfig_path))) 19112c393a42Smrg break; 19122c393a42Smrg 19132c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 19142c393a42Smrg * assume it's a Unix-style installation tree, and use 19152c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 19162c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 19172c393a42Smrg */ 1918ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 19192c393a42Smrg if (p) 19202c393a42Smrg { 19212c393a42Smrg *p = '\0'; 1922ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1923ca08ab68Smrg if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1924ca08ab68Smrg FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 19252c393a42Smrg *p = '\0'; 192618bd4a06Smrg strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path); 1927ca08ab68Smrg strcat ((char *) fontconfig_path, "\\etc\\fonts"); 19282c393a42Smrg } 19292c393a42Smrg else 19302c393a42Smrg fontconfig_path[0] = '\0'; 1931ca08ab68Smrg 19322c393a42Smrg break; 19332c393a42Smrg } 19342c393a42Smrg 19352c393a42Smrg return TRUE; 19362c393a42Smrg} 19372c393a42Smrg 19382c393a42Smrg# endif /* !PIC */ 19392c393a42Smrg 19402c393a42Smrg#undef FONTCONFIG_PATH 19412c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 19422c393a42Smrg 19432c393a42Smrg#endif /* !_WIN32 */ 19442c393a42Smrg 19452c393a42Smrg#ifndef FONTCONFIG_FILE 19462c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 19472c393a42Smrg#endif 19482c393a42Smrg 19492c393a42Smrgstatic FcChar8 * 19502c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 19512c393a42Smrg{ 19522c393a42Smrg FcChar8 *path; 1953ca08ab68Smrg int size, osize; 19542c393a42Smrg 19552c393a42Smrg if (!dir) 19562c393a42Smrg dir = (FcChar8 *) ""; 1957ca08ab68Smrg 1958ca08ab68Smrg osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1959ca08ab68Smrg /* 1960ca08ab68Smrg * workaround valgrind warning because glibc takes advantage of how it knows memory is 1961ca08ab68Smrg * allocated to implement strlen by reading in groups of 4 1962ca08ab68Smrg */ 1963ca08ab68Smrg size = (osize + 3) & ~3; 1964ca08ab68Smrg 1965ca08ab68Smrg path = malloc (size); 19662c393a42Smrg if (!path) 19672c393a42Smrg return 0; 19682c393a42Smrg 19692c393a42Smrg strcpy ((char *) path, (const char *) dir); 19702c393a42Smrg /* make sure there's a single separator */ 19712c393a42Smrg#ifdef _WIN32 19722c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 19732c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 19742c393a42Smrg !(file[0] == '/' || 19752c393a42Smrg file[0] == '\\' || 19762c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 19772c393a42Smrg strcat ((char *) path, "\\"); 19782c393a42Smrg#else 19792c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 19802c393a42Smrg strcat ((char *) path, "/"); 1981c9710b42Smrg else 1982c9710b42Smrg osize--; 19832c393a42Smrg#endif 19842c393a42Smrg strcat ((char *) path, (char *) file); 19852c393a42Smrg 19862c393a42Smrg if (access ((char *) path, R_OK) == 0) 19872c393a42Smrg return path; 1988ca08ab68Smrg 19892c393a42Smrg FcStrFree (path); 1990ca08ab68Smrg 19912c393a42Smrg return 0; 19922c393a42Smrg} 19932c393a42Smrg 19942c393a42Smrgstatic FcChar8 ** 19952c393a42SmrgFcConfigGetPath (void) 19962c393a42Smrg{ 19972c393a42Smrg FcChar8 **path; 19982c393a42Smrg FcChar8 *env, *e, *colon; 19992c393a42Smrg FcChar8 *dir; 20002c393a42Smrg int npath; 20012c393a42Smrg int i; 20022c393a42Smrg 20032c393a42Smrg npath = 2; /* default dir + null */ 20042c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 20052c393a42Smrg if (env) 20062c393a42Smrg { 20072c393a42Smrg e = env; 20082c393a42Smrg npath++; 20092c393a42Smrg while (*e) 20102c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 20112c393a42Smrg npath++; 20122c393a42Smrg } 20132c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 20142c393a42Smrg if (!path) 20152c393a42Smrg goto bail0; 20162c393a42Smrg i = 0; 20172c393a42Smrg 20182c393a42Smrg if (env) 20192c393a42Smrg { 20202c393a42Smrg e = env; 2021ca08ab68Smrg while (*e) 20222c393a42Smrg { 20232c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 20242c393a42Smrg if (!colon) 20252c393a42Smrg colon = e + strlen ((char *) e); 20262c393a42Smrg path[i] = malloc (colon - e + 1); 20272c393a42Smrg if (!path[i]) 20282c393a42Smrg goto bail1; 20292c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 20302c393a42Smrg path[i][colon - e] = '\0'; 20312c393a42Smrg if (*colon) 20322c393a42Smrg e = colon + 1; 20332c393a42Smrg else 20342c393a42Smrg e = colon; 20352c393a42Smrg i++; 20362c393a42Smrg } 20372c393a42Smrg } 2038ca08ab68Smrg 20392c393a42Smrg#ifdef _WIN32 20402c393a42Smrg if (fontconfig_path[0] == '\0') 20412c393a42Smrg { 2042a6844aabSmrg char *p; 2043ca08ab68Smrg if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 20442c393a42Smrg goto bail1; 2045ca08ab68Smrg p = strrchr ((const char *) fontconfig_path, '\\'); 20462c393a42Smrg if (p) *p = '\0'; 2047ca08ab68Smrg strcat ((char *) fontconfig_path, "\\fonts"); 20482c393a42Smrg } 20492c393a42Smrg#endif 20502c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 20512c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 20522c393a42Smrg if (!path[i]) 20532c393a42Smrg goto bail1; 20542c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 20552c393a42Smrg return path; 20562c393a42Smrg 20572c393a42Smrgbail1: 20582c393a42Smrg for (i = 0; path[i]; i++) 20592c393a42Smrg free (path[i]); 20602c393a42Smrg free (path); 20612c393a42Smrgbail0: 20622c393a42Smrg return 0; 20632c393a42Smrg} 20642c393a42Smrg 20652c393a42Smrgstatic void 20662c393a42SmrgFcConfigFreePath (FcChar8 **path) 20672c393a42Smrg{ 20682c393a42Smrg FcChar8 **p; 20692c393a42Smrg 20702c393a42Smrg for (p = path; *p; p++) 20712c393a42Smrg free (*p); 20722c393a42Smrg free (path); 20732c393a42Smrg} 20742c393a42Smrg 2075c9710b42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */ 20762c393a42Smrg 20772c393a42SmrgFcChar8 * 20782c393a42SmrgFcConfigHome (void) 20792c393a42Smrg{ 20802c393a42Smrg if (_FcConfigHomeEnabled) 20812c393a42Smrg { 20822c393a42Smrg char *home = getenv ("HOME"); 20832c393a42Smrg 20842c393a42Smrg#ifdef _WIN32 20852c393a42Smrg if (home == NULL) 20862c393a42Smrg home = getenv ("USERPROFILE"); 20872c393a42Smrg#endif 20882c393a42Smrg 20892c393a42Smrg return (FcChar8 *) home; 20902c393a42Smrg } 20912c393a42Smrg return 0; 20922c393a42Smrg} 20932c393a42Smrg 2094ca08ab68SmrgFcChar8 * 2095ca08ab68SmrgFcConfigXdgCacheHome (void) 2096ca08ab68Smrg{ 2097ca08ab68Smrg const char *env = getenv ("XDG_CACHE_HOME"); 2098ca08ab68Smrg FcChar8 *ret = NULL; 2099ca08ab68Smrg 210018bd4a06Smrg if (!_FcConfigHomeEnabled) 210118bd4a06Smrg return NULL; 2102ca08ab68Smrg if (env) 2103ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2104ca08ab68Smrg else 2105ca08ab68Smrg { 2106ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2107ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2108ca08ab68Smrg 2109ca08ab68Smrg ret = malloc (len + 7 + 1); 2110ca08ab68Smrg if (ret) 2111ca08ab68Smrg { 21121887081fSmrg if (home) 21131887081fSmrg memcpy (ret, home, len); 2114ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 2115ca08ab68Smrg ret[len + 7] = 0; 2116ca08ab68Smrg } 2117ca08ab68Smrg } 2118ca08ab68Smrg 2119ca08ab68Smrg return ret; 2120ca08ab68Smrg} 2121ca08ab68Smrg 2122ca08ab68SmrgFcChar8 * 2123ca08ab68SmrgFcConfigXdgConfigHome (void) 2124ca08ab68Smrg{ 2125ca08ab68Smrg const char *env = getenv ("XDG_CONFIG_HOME"); 2126ca08ab68Smrg FcChar8 *ret = NULL; 2127ca08ab68Smrg 212818bd4a06Smrg if (!_FcConfigHomeEnabled) 212918bd4a06Smrg return NULL; 2130ca08ab68Smrg if (env) 2131ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2132ca08ab68Smrg else 2133ca08ab68Smrg { 2134ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2135ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2136ca08ab68Smrg 2137ca08ab68Smrg ret = malloc (len + 8 + 1); 2138ca08ab68Smrg if (ret) 2139ca08ab68Smrg { 21401887081fSmrg if (home) 21411887081fSmrg memcpy (ret, home, len); 2142ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 2143ca08ab68Smrg ret[len + 8] = 0; 2144ca08ab68Smrg } 2145ca08ab68Smrg } 2146ca08ab68Smrg 2147ca08ab68Smrg return ret; 2148ca08ab68Smrg} 2149ca08ab68Smrg 2150ca08ab68SmrgFcChar8 * 2151ca08ab68SmrgFcConfigXdgDataHome (void) 2152ca08ab68Smrg{ 2153ca08ab68Smrg const char *env = getenv ("XDG_DATA_HOME"); 2154ca08ab68Smrg FcChar8 *ret = NULL; 2155ca08ab68Smrg 215618bd4a06Smrg if (!_FcConfigHomeEnabled) 215718bd4a06Smrg return NULL; 2158ca08ab68Smrg if (env) 2159ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2160ca08ab68Smrg else 2161ca08ab68Smrg { 2162ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2163ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2164ca08ab68Smrg 2165ca08ab68Smrg ret = malloc (len + 13 + 1); 2166ca08ab68Smrg if (ret) 2167ca08ab68Smrg { 21681887081fSmrg if (home) 21691887081fSmrg memcpy (ret, home, len); 2170ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 2171ca08ab68Smrg ret[len + 13] = 0; 2172ca08ab68Smrg } 2173ca08ab68Smrg } 2174ca08ab68Smrg 2175ca08ab68Smrg return ret; 2176ca08ab68Smrg} 2177ca08ab68Smrg 21782c393a42SmrgFcBool 21792c393a42SmrgFcConfigEnableHome (FcBool enable) 21802c393a42Smrg{ 21812c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 21822c393a42Smrg _FcConfigHomeEnabled = enable; 21832c393a42Smrg return prev; 21842c393a42Smrg} 21852c393a42Smrg 21862c393a42SmrgFcChar8 * 21872c393a42SmrgFcConfigFilename (const FcChar8 *url) 21882c393a42Smrg{ 21892c393a42Smrg FcChar8 *file, *dir, **path, **p; 21902c393a42Smrg 21912c393a42Smrg if (!url || !*url) 21922c393a42Smrg { 21932c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 21942c393a42Smrg if (!url) 21952c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 21962c393a42Smrg } 21972c393a42Smrg file = 0; 21982c393a42Smrg 21991887081fSmrg if (FcStrIsAbsoluteFilename(url)) 22001887081fSmrg return FcConfigFileExists (0, url); 22012c393a42Smrg 22021887081fSmrg if (*url == '~') 22031887081fSmrg { 22042c393a42Smrg dir = FcConfigHome (); 22052c393a42Smrg if (dir) 22062c393a42Smrg file = FcConfigFileExists (dir, url + 1); 22072c393a42Smrg else 22082c393a42Smrg file = 0; 22091887081fSmrg } 22101887081fSmrg 22111887081fSmrg path = FcConfigGetPath (); 22121887081fSmrg if (!path) 22131887081fSmrg return NULL; 22141887081fSmrg for (p = path; *p; p++) 22151887081fSmrg { 22161887081fSmrg file = FcConfigFileExists (*p, url); 22171887081fSmrg if (file) 22181887081fSmrg break; 22191887081fSmrg } 22201887081fSmrg FcConfigFreePath (path); 22211887081fSmrg return file; 22221887081fSmrg} 22231887081fSmrg 22241887081fSmrgFcChar8 * 22251887081fSmrgFcConfigRealFilename (FcConfig *config, 22261887081fSmrg const FcChar8 *url) 22271887081fSmrg{ 22281887081fSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 22291887081fSmrg FcChar8 *n = FcConfigFilename (url); 22301887081fSmrg FcChar8 *nn = NULL; 22311887081fSmrg 22321887081fSmrg if (n) 22331887081fSmrg { 22341887081fSmrg FcChar8 buf[PATH_MAX]; 22351887081fSmrg ssize_t len; 22361887081fSmrg 22371887081fSmrg if (sysroot) 22381887081fSmrg nn = FcStrBuildFilename (sysroot, n, NULL); 22391887081fSmrg else 22401887081fSmrg nn = FcStrdup (n); 22411887081fSmrg FcStrFree (n); 22421887081fSmrg 22431887081fSmrg if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1) 22442c393a42Smrg { 22451887081fSmrg buf[len] = 0; 22461887081fSmrg 22471887081fSmrg if (!FcStrIsAbsoluteFilename (buf)) 22481887081fSmrg { 22491887081fSmrg FcChar8 *dirname = FcStrDirname (nn); 22501887081fSmrg FcStrFree (nn); 22511887081fSmrg if (!dirname) 22521887081fSmrg return NULL; 22531887081fSmrg 22541887081fSmrg FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL); 22551887081fSmrg FcStrFree (dirname); 22561887081fSmrg if (!path) 22571887081fSmrg return NULL; 22581887081fSmrg 22591887081fSmrg nn = FcStrCanonFilename (path); 22601887081fSmrg FcStrFree (path); 22611887081fSmrg } 22621887081fSmrg else 22631887081fSmrg { 22641887081fSmrg FcStrFree (nn); 22651887081fSmrg nn = FcStrdup (buf); 22661887081fSmrg } 22672c393a42Smrg } 22682c393a42Smrg } 2269ca08ab68Smrg 22701887081fSmrg return nn; 22712c393a42Smrg} 22722c393a42Smrg 22732c393a42Smrg/* 22742c393a42Smrg * Manage the application-specific fonts 22752c393a42Smrg */ 22762c393a42Smrg 22772c393a42SmrgFcBool 22782c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 22792c393a42Smrg const FcChar8 *file) 22802c393a42Smrg{ 22812c393a42Smrg FcFontSet *set; 22822c393a42Smrg FcStrSet *subdirs; 22832c393a42Smrg FcStrList *sublist; 22842c393a42Smrg FcChar8 *subdir; 22852c393a42Smrg 22862c393a42Smrg if (!config) 22872c393a42Smrg { 22882c393a42Smrg config = FcConfigGetCurrent (); 22892c393a42Smrg if (!config) 22902c393a42Smrg return FcFalse; 22912c393a42Smrg } 22922c393a42Smrg 229318bd4a06Smrg subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 22942c393a42Smrg if (!subdirs) 22952c393a42Smrg return FcFalse; 2296ca08ab68Smrg 22972c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 22982c393a42Smrg if (!set) 22992c393a42Smrg { 23002c393a42Smrg set = FcFontSetCreate (); 23012c393a42Smrg if (!set) 23022c393a42Smrg { 23032c393a42Smrg FcStrSetDestroy (subdirs); 23042c393a42Smrg return FcFalse; 23052c393a42Smrg } 23062c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 23072c393a42Smrg } 23082c393a42Smrg 23091887081fSmrg if (!FcFileScanConfig (set, subdirs, file, config)) 23102c393a42Smrg { 23112c393a42Smrg FcStrSetDestroy (subdirs); 23122c393a42Smrg return FcFalse; 23132c393a42Smrg } 23142c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 23152c393a42Smrg { 23162c393a42Smrg while ((subdir = FcStrListNext (sublist))) 23172c393a42Smrg { 23182c393a42Smrg FcConfigAppFontAddDir (config, subdir); 23192c393a42Smrg } 23202c393a42Smrg FcStrListDone (sublist); 23212c393a42Smrg } 23222c393a42Smrg FcStrSetDestroy (subdirs); 23232c393a42Smrg return FcTrue; 23242c393a42Smrg} 23252c393a42Smrg 23262c393a42SmrgFcBool 23272c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 23282c393a42Smrg const FcChar8 *dir) 23292c393a42Smrg{ 23302c393a42Smrg FcFontSet *set; 23312c393a42Smrg FcStrSet *dirs; 2332ca08ab68Smrg 23332c393a42Smrg if (!config) 23342c393a42Smrg { 23352c393a42Smrg config = FcConfigGetCurrent (); 23362c393a42Smrg if (!config) 23372c393a42Smrg return FcFalse; 23382c393a42Smrg } 23392c393a42Smrg 234018bd4a06Smrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 23412c393a42Smrg if (!dirs) 23422c393a42Smrg return FcFalse; 2343ca08ab68Smrg 23442c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 23452c393a42Smrg if (!set) 23462c393a42Smrg { 23472c393a42Smrg set = FcFontSetCreate (); 23482c393a42Smrg if (!set) 23492c393a42Smrg { 23502c393a42Smrg FcStrSetDestroy (dirs); 23512c393a42Smrg return FcFalse; 23522c393a42Smrg } 23532c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 23542c393a42Smrg } 2355ca08ab68Smrg 23562c393a42Smrg FcStrSetAddFilename (dirs, dir); 2357ca08ab68Smrg 23582c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 23592c393a42Smrg { 23602c393a42Smrg FcStrSetDestroy (dirs); 23612c393a42Smrg return FcFalse; 23622c393a42Smrg } 23632c393a42Smrg FcStrSetDestroy (dirs); 23642c393a42Smrg return FcTrue; 23652c393a42Smrg} 23662c393a42Smrg 23672c393a42Smrgvoid 23682c393a42SmrgFcConfigAppFontClear (FcConfig *config) 23692c393a42Smrg{ 23702c393a42Smrg if (!config) 23712c393a42Smrg { 23722c393a42Smrg config = FcConfigGetCurrent (); 23732c393a42Smrg if (!config) 23742c393a42Smrg return; 23752c393a42Smrg } 23762c393a42Smrg 23772c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 23782c393a42Smrg} 23792c393a42Smrg 23802c393a42Smrg/* 23812c393a42Smrg * Manage filename-based font source selectors 23822c393a42Smrg */ 23832c393a42Smrg 23842c393a42SmrgFcBool 23852c393a42SmrgFcConfigGlobAdd (FcConfig *config, 23862c393a42Smrg const FcChar8 *glob, 23872c393a42Smrg FcBool accept) 23882c393a42Smrg{ 23892c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 23902c393a42Smrg 23912c393a42Smrg return FcStrSetAdd (set, glob); 23922c393a42Smrg} 23932c393a42Smrg 23942c393a42Smrgstatic FcBool 23952c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 23962c393a42Smrg const FcChar8 *string) 23972c393a42Smrg{ 23982c393a42Smrg int i; 23992c393a42Smrg 24002c393a42Smrg for (i = 0; i < globs->num; i++) 2401c9710b42Smrg if (FcStrGlobMatch (globs->strs[i], string)) 24022c393a42Smrg return FcTrue; 24032c393a42Smrg return FcFalse; 24042c393a42Smrg} 24052c393a42Smrg 24062c393a42SmrgFcBool 24072c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 24082c393a42Smrg const FcChar8 *filename) 24092c393a42Smrg{ 24102c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 24112c393a42Smrg return FcTrue; 24122c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 24132c393a42Smrg return FcFalse; 24142c393a42Smrg return FcTrue; 24152c393a42Smrg} 24162c393a42Smrg 24172c393a42Smrg/* 24182c393a42Smrg * Manage font-pattern based font source selectors 24192c393a42Smrg */ 24202c393a42Smrg 24212c393a42SmrgFcBool 24222c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 24232c393a42Smrg FcPattern *pattern, 24242c393a42Smrg FcBool accept) 24252c393a42Smrg{ 24262c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 24272c393a42Smrg 24282c393a42Smrg return FcFontSetAdd (set, pattern); 24292c393a42Smrg} 24302c393a42Smrg 24312c393a42Smrgstatic FcBool 24322c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 24332c393a42Smrg const FcPattern *font) 24342c393a42Smrg{ 24352c393a42Smrg int i; 2436ca08ab68Smrg 24372c393a42Smrg for (i = 0; i < patterns->nfont; i++) 24382c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 24392c393a42Smrg return FcTrue; 24402c393a42Smrg return FcFalse; 24412c393a42Smrg} 24422c393a42Smrg 24432c393a42SmrgFcBool 24442c393a42SmrgFcConfigAcceptFont (FcConfig *config, 24452c393a42Smrg const FcPattern *font) 24462c393a42Smrg{ 24472c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 24482c393a42Smrg return FcTrue; 24492c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 24502c393a42Smrg return FcFalse; 24512c393a42Smrg return FcTrue; 24522c393a42Smrg} 2453c9710b42Smrg 2454c9710b42Smrgconst FcChar8 * 2455c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config) 2456c9710b42Smrg{ 2457c9710b42Smrg if (!config) 2458c9710b42Smrg { 2459c9710b42Smrg config = FcConfigGetCurrent (); 2460c9710b42Smrg if (!config) 2461c9710b42Smrg return NULL; 2462c9710b42Smrg } 2463c9710b42Smrg 24641887081fSmrg if (config->sysRoot) 24651887081fSmrg return config->sysRoot; 24661887081fSmrg 24671887081fSmrg return (FcChar8 *) getenv ("FONTCONFIG_SYSROOT"); 2468c9710b42Smrg} 2469c9710b42Smrg 2470c9710b42Smrgvoid 2471c9710b42SmrgFcConfigSetSysRoot (FcConfig *config, 2472c9710b42Smrg const FcChar8 *sysroot) 2473c9710b42Smrg{ 247418bd4a06Smrg FcChar8 *s = NULL; 2475c9710b42Smrg FcBool init = FcFalse; 2476c9710b42Smrg 2477c9710b42Smrg if (!config) 2478c9710b42Smrg { 2479c9710b42Smrg /* We can't use FcConfigGetCurrent() here to ensure 2480c9710b42Smrg * the sysroot is set prior to initialize FcConfig, 2481c9710b42Smrg * to avoid loading caches from non-sysroot dirs. 2482c9710b42Smrg * So postpone the initialization later. 2483c9710b42Smrg */ 2484c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 2485c9710b42Smrg if (!config) 2486c9710b42Smrg { 2487c9710b42Smrg config = FcConfigCreate (); 2488c9710b42Smrg if (!config) 2489c9710b42Smrg return; 2490c9710b42Smrg init = FcTrue; 2491c9710b42Smrg } 2492c9710b42Smrg } 2493c9710b42Smrg 249418bd4a06Smrg if (sysroot) 249518bd4a06Smrg { 249618bd4a06Smrg s = FcStrCopyFilename (sysroot); 249718bd4a06Smrg if (!s) 249818bd4a06Smrg return; 249918bd4a06Smrg } 2500c9710b42Smrg 2501c9710b42Smrg if (config->sysRoot) 2502c9710b42Smrg FcStrFree (config->sysRoot); 2503c9710b42Smrg 2504c9710b42Smrg config->sysRoot = s; 2505c9710b42Smrg if (init) 2506c9710b42Smrg { 2507c9710b42Smrg config = FcInitLoadOwnConfigAndFonts (config); 2508c9710b42Smrg FcConfigSetCurrent (config); 250918bd4a06Smrg /* FcConfigSetCurrent() increases the refcount. 251018bd4a06Smrg * decrease it here to avoid the memory leak. 251118bd4a06Smrg */ 251218bd4a06Smrg FcConfigDestroy (config); 2513c9710b42Smrg } 2514c9710b42Smrg} 2515c9710b42Smrg 25161887081fSmrgFcRuleSet * 25171887081fSmrgFcRuleSetCreate (const FcChar8 *name) 25181887081fSmrg{ 25191887081fSmrg FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet)); 25201887081fSmrg FcMatchKind k; 25211887081fSmrg const FcChar8 *p; 25221887081fSmrg 25231887081fSmrg if (!name) 25241887081fSmrg p = (const FcChar8 *)""; 25251887081fSmrg else 25261887081fSmrg p = name; 25271887081fSmrg 25281887081fSmrg if (ret) 25291887081fSmrg { 25301887081fSmrg ret->name = FcStrdup (p); 25311887081fSmrg ret->description = NULL; 25321887081fSmrg ret->domain = NULL; 25331887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 25341887081fSmrg ret->subst[k] = FcPtrListCreate (FcDestroyAsRule); 25351887081fSmrg FcRefInit (&ret->ref, 1); 25361887081fSmrg } 25371887081fSmrg 25381887081fSmrg return ret; 25391887081fSmrg} 25401887081fSmrg 25411887081fSmrgvoid 25421887081fSmrgFcRuleSetDestroy (FcRuleSet *rs) 25431887081fSmrg{ 25441887081fSmrg FcMatchKind k; 25451887081fSmrg 25461887081fSmrg if (!rs) 25471887081fSmrg return; 25481887081fSmrg if (FcRefDec (&rs->ref) != 1) 25491887081fSmrg return; 25501887081fSmrg 25511887081fSmrg if (rs->name) 25521887081fSmrg FcStrFree (rs->name); 25531887081fSmrg if (rs->description) 25541887081fSmrg FcStrFree (rs->description); 25551887081fSmrg if (rs->domain) 25561887081fSmrg FcStrFree (rs->domain); 25571887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 25581887081fSmrg FcPtrListDestroy (rs->subst[k]); 25591887081fSmrg 25601887081fSmrg free (rs); 25611887081fSmrg} 25621887081fSmrg 25631887081fSmrgvoid 25641887081fSmrgFcRuleSetReference (FcRuleSet *rs) 25651887081fSmrg{ 25661887081fSmrg if (!FcRefIsConst (&rs->ref)) 25671887081fSmrg FcRefInc (&rs->ref); 25681887081fSmrg} 25691887081fSmrg 25701887081fSmrgvoid 25711887081fSmrgFcRuleSetEnable (FcRuleSet *rs, 25721887081fSmrg FcBool flag) 25731887081fSmrg{ 25741887081fSmrg if (rs) 25751887081fSmrg { 25761887081fSmrg rs->enabled = flag; 25771887081fSmrg /* XXX: we may want to provide a feature 25781887081fSmrg * to enable/disable rulesets through API 25791887081fSmrg * in the future? 25801887081fSmrg */ 25811887081fSmrg } 25821887081fSmrg} 25831887081fSmrg 25841887081fSmrgvoid 25851887081fSmrgFcRuleSetAddDescription (FcRuleSet *rs, 25861887081fSmrg const FcChar8 *domain, 25871887081fSmrg const FcChar8 *description) 25881887081fSmrg{ 25891887081fSmrg if (rs->domain) 25901887081fSmrg FcStrFree (rs->domain); 25911887081fSmrg if (rs->description) 25921887081fSmrg FcStrFree (rs->description); 25931887081fSmrg 25941887081fSmrg rs->domain = domain ? FcStrdup (domain) : NULL; 25951887081fSmrg rs->description = description ? FcStrdup (description) : NULL; 25961887081fSmrg} 25971887081fSmrg 25981887081fSmrgint 25991887081fSmrgFcRuleSetAdd (FcRuleSet *rs, 26001887081fSmrg FcRule *rule, 26011887081fSmrg FcMatchKind kind) 26021887081fSmrg{ 26031887081fSmrg FcPtrListIter iter; 26041887081fSmrg FcRule *r; 26051887081fSmrg int n = 0, ret; 26061887081fSmrg 26071887081fSmrg if (!rs || 26081887081fSmrg kind < FcMatchKindBegin || kind >= FcMatchKindEnd) 26091887081fSmrg return -1; 26101887081fSmrg FcPtrListIterInitAtLast (rs->subst[kind], &iter); 26111887081fSmrg if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule)) 26121887081fSmrg return -1; 26131887081fSmrg 26141887081fSmrg for (r = rule; r; r = r->next) 26151887081fSmrg { 26161887081fSmrg switch (r->type) 26171887081fSmrg { 26181887081fSmrg case FcRuleTest: 26191887081fSmrg if (r->u.test) 26201887081fSmrg { 26211887081fSmrg if (r->u.test->kind == FcMatchDefault) 26221887081fSmrg r->u.test->kind = kind; 26231887081fSmrg if (n < r->u.test->object) 26241887081fSmrg n = r->u.test->object; 26251887081fSmrg } 26261887081fSmrg break; 26271887081fSmrg case FcRuleEdit: 26281887081fSmrg if (n < r->u.edit->object) 26291887081fSmrg n = r->u.edit->object; 26301887081fSmrg break; 26311887081fSmrg default: 26321887081fSmrg break; 26331887081fSmrg } 26341887081fSmrg } 26351887081fSmrg if (FcDebug () & FC_DBG_EDIT) 26361887081fSmrg { 26371887081fSmrg printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name); 26381887081fSmrg FcRulePrint (rule); 26391887081fSmrg } 26401887081fSmrg ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; 26411887081fSmrg 26421887081fSmrg return ret < 0 ? 0 : ret; 26431887081fSmrg} 26441887081fSmrg 26451887081fSmrgvoid 26461887081fSmrgFcConfigFileInfoIterInit (FcConfig *config, 26471887081fSmrg FcConfigFileInfoIter *iter) 26481887081fSmrg{ 26491887081fSmrg FcConfig *c; 26501887081fSmrg FcPtrListIter *i = (FcPtrListIter *)iter; 26511887081fSmrg 26521887081fSmrg if (!config) 26531887081fSmrg c = FcConfigGetCurrent (); 26541887081fSmrg else 26551887081fSmrg c = config; 26561887081fSmrg FcPtrListIterInit (c->rulesetList, i); 26571887081fSmrg} 26581887081fSmrg 26591887081fSmrgFcBool 26601887081fSmrgFcConfigFileInfoIterNext (FcConfig *config, 26611887081fSmrg FcConfigFileInfoIter *iter) 26621887081fSmrg{ 26631887081fSmrg FcConfig *c; 26641887081fSmrg FcPtrListIter *i = (FcPtrListIter *)iter; 26651887081fSmrg 26661887081fSmrg if (!config) 26671887081fSmrg c = FcConfigGetCurrent (); 26681887081fSmrg else 26691887081fSmrg c = config; 26701887081fSmrg if (FcPtrListIterIsValid (c->rulesetList, i)) 26711887081fSmrg { 26721887081fSmrg FcPtrListIterNext (c->rulesetList, i); 26731887081fSmrg } 26741887081fSmrg else 26751887081fSmrg return FcFalse; 26761887081fSmrg 26771887081fSmrg return FcTrue; 26781887081fSmrg} 26791887081fSmrg 26801887081fSmrgFcBool 26811887081fSmrgFcConfigFileInfoIterGet (FcConfig *config, 26821887081fSmrg FcConfigFileInfoIter *iter, 26831887081fSmrg FcChar8 **name, 26841887081fSmrg FcChar8 **description, 26851887081fSmrg FcBool *enabled) 26861887081fSmrg{ 26871887081fSmrg FcConfig *c; 26881887081fSmrg FcRuleSet *r; 26891887081fSmrg FcPtrListIter *i = (FcPtrListIter *)iter; 26901887081fSmrg 26911887081fSmrg if (!config) 26921887081fSmrg c = FcConfigGetCurrent (); 26931887081fSmrg else 26941887081fSmrg c = config; 26951887081fSmrg if (!FcPtrListIterIsValid (c->rulesetList, i)) 26961887081fSmrg return FcFalse; 26971887081fSmrg r = FcPtrListIterGetValue (c->rulesetList, i); 26981887081fSmrg if (name) 26991887081fSmrg *name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf"); 27001887081fSmrg if (description) 27011887081fSmrg *description = FcStrdup (!r->description ? _("No description") : 27021887081fSmrg dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf", 27031887081fSmrg (const char *) r->description)); 27041887081fSmrg if (enabled) 27051887081fSmrg *enabled = r->enabled; 27061887081fSmrg 27071887081fSmrg return FcTrue; 27081887081fSmrg} 27091887081fSmrg 27102c393a42Smrg#define __fccfg__ 27112c393a42Smrg#include "fcaliastail.h" 27122c393a42Smrg#undef __fccfg__ 2713