fccfg.c revision c9710b42
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 55c9710b42SmrgFcBool 56c9710b42SmrgFcConfigInit (void) 57c9710b42Smrg{ 58c9710b42Smrg return FcConfigEnsure () ? FcTrue : FcFalse; 59c9710b42Smrg} 60c9710b42Smrg 61c9710b42Smrgvoid 62c9710b42SmrgFcConfigFini (void) 63c9710b42Smrg{ 64c9710b42Smrg FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); 65c9710b42Smrg if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) 66c9710b42Smrg FcConfigDestroy (cfg); 67c9710b42Smrg} 68c9710b42Smrg 692c393a42Smrg 702c393a42SmrgFcConfig * 712c393a42SmrgFcConfigCreate (void) 722c393a42Smrg{ 732c393a42Smrg FcSetName set; 742c393a42Smrg FcConfig *config; 752c393a42Smrg 762c393a42Smrg config = malloc (sizeof (FcConfig)); 772c393a42Smrg if (!config) 782c393a42Smrg goto bail0; 79ca08ab68Smrg 802c393a42Smrg config->configDirs = FcStrSetCreate (); 812c393a42Smrg if (!config->configDirs) 822c393a42Smrg goto bail1; 83ca08ab68Smrg 842c393a42Smrg config->configFiles = FcStrSetCreate (); 852c393a42Smrg if (!config->configFiles) 862c393a42Smrg goto bail2; 87ca08ab68Smrg 882c393a42Smrg config->fontDirs = FcStrSetCreate (); 892c393a42Smrg if (!config->fontDirs) 902c393a42Smrg goto bail3; 91ca08ab68Smrg 922c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 932c393a42Smrg if (!config->acceptGlobs) 942c393a42Smrg goto bail4; 952c393a42Smrg 962c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 972c393a42Smrg if (!config->rejectGlobs) 982c393a42Smrg goto bail5; 992c393a42Smrg 1002c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 1012c393a42Smrg if (!config->acceptPatterns) 1022c393a42Smrg goto bail6; 103ca08ab68Smrg 1042c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 1052c393a42Smrg if (!config->rejectPatterns) 1062c393a42Smrg goto bail7; 1072c393a42Smrg 1082c393a42Smrg config->cacheDirs = FcStrSetCreate (); 1092c393a42Smrg if (!config->cacheDirs) 1102c393a42Smrg goto bail8; 111ca08ab68Smrg 1122c393a42Smrg config->blanks = 0; 1132c393a42Smrg 1142c393a42Smrg config->substPattern = 0; 1152c393a42Smrg config->substFont = 0; 1162c393a42Smrg config->substScan = 0; 1172c393a42Smrg config->maxObjects = 0; 1182c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 1192c393a42Smrg config->fonts[set] = 0; 1202c393a42Smrg 1212c393a42Smrg config->rescanTime = time(0); 122ca08ab68Smrg config->rescanInterval = 30; 123a6844aabSmrg 124a6844aabSmrg config->expr_pool = NULL; 125a6844aabSmrg 126c9710b42Smrg config->sysRoot = NULL; 127c9710b42Smrg 128c9710b42Smrg FcRefInit (&config->ref, 1); 129ca08ab68Smrg 1302c393a42Smrg return config; 1312c393a42Smrg 1322c393a42Smrgbail8: 1332c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 1342c393a42Smrgbail7: 1352c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 1362c393a42Smrgbail6: 1372c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 1382c393a42Smrgbail5: 1392c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 1402c393a42Smrgbail4: 1412c393a42Smrg FcStrSetDestroy (config->fontDirs); 1422c393a42Smrgbail3: 1432c393a42Smrg FcStrSetDestroy (config->configFiles); 1442c393a42Smrgbail2: 1452c393a42Smrg FcStrSetDestroy (config->configDirs); 1462c393a42Smrgbail1: 1472c393a42Smrg free (config); 1482c393a42Smrgbail0: 1492c393a42Smrg return 0; 1502c393a42Smrg} 1512c393a42Smrg 1522c393a42Smrgstatic FcFileTime 1532c393a42SmrgFcConfigNewestFile (FcStrSet *files) 1542c393a42Smrg{ 1552c393a42Smrg FcStrList *list = FcStrListCreate (files); 1562c393a42Smrg FcFileTime newest = { 0, FcFalse }; 1572c393a42Smrg FcChar8 *file; 1582c393a42Smrg struct stat statb; 1592c393a42Smrg 1602c393a42Smrg if (list) 1612c393a42Smrg { 1622c393a42Smrg while ((file = FcStrListNext (list))) 163ca08ab68Smrg if (FcStat (file, &statb) == 0) 1642c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 1652c393a42Smrg { 1662c393a42Smrg newest.set = FcTrue; 1672c393a42Smrg newest.time = statb.st_mtime; 1682c393a42Smrg } 1692c393a42Smrg FcStrListDone (list); 1702c393a42Smrg } 1712c393a42Smrg return newest; 1722c393a42Smrg} 1732c393a42Smrg 1742c393a42SmrgFcBool 1752c393a42SmrgFcConfigUptoDate (FcConfig *config) 1762c393a42Smrg{ 1772c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 1782c393a42Smrg time_t now = time(0); 1792c393a42Smrg if (!config) 1802c393a42Smrg { 1812c393a42Smrg config = FcConfigGetCurrent (); 1822c393a42Smrg if (!config) 1832c393a42Smrg return FcFalse; 1842c393a42Smrg } 1852c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 1862c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 1872c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 1882c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 1892c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 1902c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 1912c393a42Smrg { 1922c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 1932c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 1942c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 1952c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 1962c393a42Smrg { 1972c393a42Smrg fprintf (stderr, 198c9710b42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); 1992c393a42Smrg config->rescanTime = now; 2002c393a42Smrg return FcTrue; 2012c393a42Smrg } 2022c393a42Smrg else 2032c393a42Smrg return FcFalse; 2042c393a42Smrg } 2052c393a42Smrg config->rescanTime = now; 2062c393a42Smrg return FcTrue; 2072c393a42Smrg} 2082c393a42Smrg 2092c393a42Smrgstatic void 2102c393a42SmrgFcSubstDestroy (FcSubst *s) 2112c393a42Smrg{ 2122c393a42Smrg FcSubst *n; 213ca08ab68Smrg 2142c393a42Smrg while (s) 2152c393a42Smrg { 2162c393a42Smrg n = s->next; 2172c393a42Smrg if (s->test) 2182c393a42Smrg FcTestDestroy (s->test); 2192c393a42Smrg if (s->edit) 2202c393a42Smrg FcEditDestroy (s->edit); 2212c393a42Smrg free (s); 2222c393a42Smrg s = n; 2232c393a42Smrg } 2242c393a42Smrg} 2252c393a42Smrg 226a6844aabSmrgFcExpr * 227a6844aabSmrgFcConfigAllocExpr (FcConfig *config) 228a6844aabSmrg{ 229a6844aabSmrg if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 230a6844aabSmrg { 231a6844aabSmrg FcExprPage *new_page; 232a6844aabSmrg 233a6844aabSmrg new_page = malloc (sizeof (FcExprPage)); 234a6844aabSmrg if (!new_page) 235a6844aabSmrg return 0; 236a6844aabSmrg 237a6844aabSmrg new_page->next_page = config->expr_pool; 238a6844aabSmrg new_page->next = new_page->exprs; 239a6844aabSmrg config->expr_pool = new_page; 240a6844aabSmrg } 241a6844aabSmrg 242a6844aabSmrg return config->expr_pool->next++; 243a6844aabSmrg} 244a6844aabSmrg 245a6844aabSmrgFcConfig * 246a6844aabSmrgFcConfigReference (FcConfig *config) 247a6844aabSmrg{ 248a6844aabSmrg if (!config) 249a6844aabSmrg { 250a6844aabSmrg config = FcConfigGetCurrent (); 251a6844aabSmrg if (!config) 252a6844aabSmrg return 0; 253a6844aabSmrg } 254a6844aabSmrg 255c9710b42Smrg FcRefInc (&config->ref); 256a6844aabSmrg 257a6844aabSmrg return config; 258a6844aabSmrg} 259a6844aabSmrg 2602c393a42Smrgvoid 2612c393a42SmrgFcConfigDestroy (FcConfig *config) 2622c393a42Smrg{ 2632c393a42Smrg FcSetName set; 264a6844aabSmrg FcExprPage *page; 265a6844aabSmrg 266c9710b42Smrg if (FcRefDec (&config->ref) != 1) 267a6844aabSmrg return; 2682c393a42Smrg 269c9710b42Smrg (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); 2702c393a42Smrg 2712c393a42Smrg FcStrSetDestroy (config->configDirs); 2722c393a42Smrg FcStrSetDestroy (config->fontDirs); 2732c393a42Smrg FcStrSetDestroy (config->cacheDirs); 2742c393a42Smrg FcStrSetDestroy (config->configFiles); 2752c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 2762c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 2772c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 2782c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 2792c393a42Smrg 2802c393a42Smrg if (config->blanks) 2812c393a42Smrg FcBlanksDestroy (config->blanks); 2822c393a42Smrg 2832c393a42Smrg FcSubstDestroy (config->substPattern); 2842c393a42Smrg FcSubstDestroy (config->substFont); 2852c393a42Smrg FcSubstDestroy (config->substScan); 2862c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 2872c393a42Smrg if (config->fonts[set]) 2882c393a42Smrg FcFontSetDestroy (config->fonts[set]); 2892c393a42Smrg 290a6844aabSmrg page = config->expr_pool; 291a6844aabSmrg while (page) 292a6844aabSmrg { 293a6844aabSmrg FcExprPage *next = page->next_page; 294a6844aabSmrg free (page); 295a6844aabSmrg page = next; 296a6844aabSmrg } 297c9710b42Smrg if (config->sysRoot) 298c9710b42Smrg FcStrFree (config->sysRoot); 299a6844aabSmrg 3002c393a42Smrg free (config); 3012c393a42Smrg} 3022c393a42Smrg 3032c393a42Smrg/* 3042c393a42Smrg * Add cache to configuration, adding fonts and directories 3052c393a42Smrg */ 3062c393a42Smrg 3072c393a42SmrgFcBool 308ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 3092c393a42Smrg FcSetName set, FcStrSet *dirSet) 3102c393a42Smrg{ 3112c393a42Smrg FcFontSet *fs; 3122c393a42Smrg intptr_t *dirs; 3132c393a42Smrg int i; 3142c393a42Smrg 3152c393a42Smrg /* 3162c393a42Smrg * Add fonts 3172c393a42Smrg */ 3182c393a42Smrg fs = FcCacheSet (cache); 3192c393a42Smrg if (fs) 3202c393a42Smrg { 3212c393a42Smrg int nref = 0; 3222c393a42Smrg 3232c393a42Smrg for (i = 0; i < fs->nfont; i++) 3242c393a42Smrg { 3252c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 3262c393a42Smrg FcChar8 *font_file; 3272c393a42Smrg 3282c393a42Smrg /* 3292c393a42Smrg * Check to see if font is banned by filename 3302c393a42Smrg */ 3312c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 3322c393a42Smrg 0, &font_file) == FcResultMatch && 3332c393a42Smrg !FcConfigAcceptFilename (config, font_file)) 3342c393a42Smrg { 3352c393a42Smrg continue; 3362c393a42Smrg } 3372c393a42Smrg 3382c393a42Smrg /* 3392c393a42Smrg * Check to see if font is banned by pattern 3402c393a42Smrg */ 3412c393a42Smrg if (!FcConfigAcceptFont (config, font)) 3422c393a42Smrg continue; 3432c393a42Smrg 344c9710b42Smrg if (FcFontSetAdd (config->fonts[set], font)) 345c9710b42Smrg nref++; 3462c393a42Smrg } 3472c393a42Smrg FcDirCacheReference (cache, nref); 3482c393a42Smrg } 3492c393a42Smrg 3502c393a42Smrg /* 3512c393a42Smrg * Add directories 3522c393a42Smrg */ 3532c393a42Smrg dirs = FcCacheDirs (cache); 3542c393a42Smrg if (dirs) 3552c393a42Smrg { 3562c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 3572c393a42Smrg { 3582c393a42Smrg FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); 3592c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 3602c393a42Smrg FcStrSetAddFilename (dirSet, dir); 3612c393a42Smrg } 3622c393a42Smrg } 3632c393a42Smrg return FcTrue; 3642c393a42Smrg} 3652c393a42Smrg 3662c393a42Smrgstatic FcBool 3672c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 3682c393a42Smrg{ 3692c393a42Smrg FcStrList *dirlist; 3702c393a42Smrg FcChar8 *dir; 3712c393a42Smrg FcCache *cache; 372ca08ab68Smrg 3732c393a42Smrg dirlist = FcStrListCreate (dirSet); 3742c393a42Smrg if (!dirlist) 3752c393a42Smrg return FcFalse; 3762c393a42Smrg 3772c393a42Smrg while ((dir = FcStrListNext (dirlist))) 3782c393a42Smrg { 3792c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 3802c393a42Smrg printf ("adding fonts from%s\n", dir); 3812c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 3822c393a42Smrg if (!cache) 3832c393a42Smrg continue; 3842c393a42Smrg FcConfigAddCache (config, cache, set, dirSet); 3852c393a42Smrg FcDirCacheUnload (cache); 3862c393a42Smrg } 3872c393a42Smrg FcStrListDone (dirlist); 3882c393a42Smrg return FcTrue; 3892c393a42Smrg} 3902c393a42Smrg 3912c393a42Smrg/* 3922c393a42Smrg * Scan the current list of directories in the configuration 3932c393a42Smrg * and build the set of available fonts. 3942c393a42Smrg */ 3952c393a42Smrg 3962c393a42SmrgFcBool 3972c393a42SmrgFcConfigBuildFonts (FcConfig *config) 3982c393a42Smrg{ 3992c393a42Smrg FcFontSet *fonts; 4002c393a42Smrg 4012c393a42Smrg if (!config) 4022c393a42Smrg { 4032c393a42Smrg config = FcConfigGetCurrent (); 4042c393a42Smrg if (!config) 4052c393a42Smrg return FcFalse; 4062c393a42Smrg } 4072c393a42Smrg 4082c393a42Smrg fonts = FcFontSetCreate (); 4092c393a42Smrg if (!fonts) 4102c393a42Smrg return FcFalse; 411ca08ab68Smrg 4122c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 413ca08ab68Smrg 4142c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 4152c393a42Smrg return FcFalse; 4162c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 4172c393a42Smrg FcFontSetPrint (fonts); 4182c393a42Smrg return FcTrue; 4192c393a42Smrg} 4202c393a42Smrg 4212c393a42SmrgFcBool 4222c393a42SmrgFcConfigSetCurrent (FcConfig *config) 4232c393a42Smrg{ 424c9710b42Smrg FcConfig *cfg; 425c9710b42Smrg 426c9710b42Smrgretry: 427c9710b42Smrg cfg = fc_atomic_ptr_get (&_fcConfig); 428c9710b42Smrg 429c9710b42Smrg if (config == cfg) 4302c393a42Smrg return FcTrue; 4312c393a42Smrg 432c9710b42Smrg if (config && !config->fonts[FcSetSystem]) 4332c393a42Smrg if (!FcConfigBuildFonts (config)) 4342c393a42Smrg return FcFalse; 4352c393a42Smrg 436c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) 437c9710b42Smrg goto retry; 438c9710b42Smrg 439c9710b42Smrg if (cfg) 440c9710b42Smrg FcConfigDestroy (cfg); 441c9710b42Smrg 4422c393a42Smrg return FcTrue; 4432c393a42Smrg} 4442c393a42Smrg 4452c393a42SmrgFcConfig * 4462c393a42SmrgFcConfigGetCurrent (void) 4472c393a42Smrg{ 448c9710b42Smrg return FcConfigEnsure (); 4492c393a42Smrg} 4502c393a42Smrg 4512c393a42SmrgFcBool 4522c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 4532c393a42Smrg const FcChar8 *d) 4542c393a42Smrg{ 4552c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 4562c393a42Smrg} 4572c393a42Smrg 4582c393a42SmrgFcStrList * 4592c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 4602c393a42Smrg{ 4612c393a42Smrg if (!config) 4622c393a42Smrg { 4632c393a42Smrg config = FcConfigGetCurrent (); 4642c393a42Smrg if (!config) 4652c393a42Smrg return 0; 4662c393a42Smrg } 4672c393a42Smrg return FcStrListCreate (config->configDirs); 4682c393a42Smrg} 4692c393a42Smrg 4702c393a42SmrgFcBool 4712c393a42SmrgFcConfigAddFontDir (FcConfig *config, 4722c393a42Smrg const FcChar8 *d) 4732c393a42Smrg{ 4742c393a42Smrg return FcStrSetAddFilename (config->fontDirs, d); 4752c393a42Smrg} 4762c393a42Smrg 4772c393a42SmrgFcBool 4782c393a42SmrgFcConfigAddDir (FcConfig *config, 4792c393a42Smrg const FcChar8 *d) 4802c393a42Smrg{ 481ca08ab68Smrg return (FcConfigAddConfigDir (config, d) && 4822c393a42Smrg FcConfigAddFontDir (config, d)); 4832c393a42Smrg} 4842c393a42Smrg 4852c393a42SmrgFcStrList * 4862c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 4872c393a42Smrg{ 4882c393a42Smrg if (!config) 4892c393a42Smrg { 4902c393a42Smrg config = FcConfigGetCurrent (); 4912c393a42Smrg if (!config) 4922c393a42Smrg return 0; 4932c393a42Smrg } 4942c393a42Smrg return FcStrListCreate (config->fontDirs); 4952c393a42Smrg} 4962c393a42Smrg 4972c393a42SmrgFcBool 4982c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 4992c393a42Smrg const FcChar8 *d) 5002c393a42Smrg{ 5012c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 5022c393a42Smrg} 5032c393a42Smrg 5042c393a42SmrgFcStrList * 505ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config) 5062c393a42Smrg{ 5072c393a42Smrg if (!config) 5082c393a42Smrg { 5092c393a42Smrg config = FcConfigGetCurrent (); 5102c393a42Smrg if (!config) 5112c393a42Smrg return 0; 5122c393a42Smrg } 5132c393a42Smrg return FcStrListCreate (config->cacheDirs); 5142c393a42Smrg} 515ca08ab68Smrg 5162c393a42SmrgFcBool 5172c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 5182c393a42Smrg const FcChar8 *f) 5192c393a42Smrg{ 5202c393a42Smrg FcBool ret; 5212c393a42Smrg FcChar8 *file = FcConfigFilename (f); 522ca08ab68Smrg 5232c393a42Smrg if (!file) 5242c393a42Smrg return FcFalse; 525ca08ab68Smrg 5262c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 5272c393a42Smrg FcStrFree (file); 5282c393a42Smrg return ret; 5292c393a42Smrg} 5302c393a42Smrg 5312c393a42SmrgFcStrList * 5322c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 5332c393a42Smrg{ 5342c393a42Smrg if (!config) 5352c393a42Smrg { 5362c393a42Smrg config = FcConfigGetCurrent (); 5372c393a42Smrg if (!config) 5382c393a42Smrg return 0; 5392c393a42Smrg } 5402c393a42Smrg return FcStrListCreate (config->configFiles); 5412c393a42Smrg} 5422c393a42Smrg 5432c393a42SmrgFcChar8 * 544c9710b42SmrgFcConfigGetCache (FcConfig *config FC_UNUSED) 5452c393a42Smrg{ 5462c393a42Smrg return NULL; 5472c393a42Smrg} 5482c393a42Smrg 5492c393a42SmrgFcFontSet * 5502c393a42SmrgFcConfigGetFonts (FcConfig *config, 5512c393a42Smrg FcSetName set) 5522c393a42Smrg{ 5532c393a42Smrg if (!config) 5542c393a42Smrg { 5552c393a42Smrg config = FcConfigGetCurrent (); 5562c393a42Smrg if (!config) 5572c393a42Smrg return 0; 5582c393a42Smrg } 5592c393a42Smrg return config->fonts[set]; 5602c393a42Smrg} 5612c393a42Smrg 5622c393a42Smrgvoid 5632c393a42SmrgFcConfigSetFonts (FcConfig *config, 5642c393a42Smrg FcFontSet *fonts, 5652c393a42Smrg FcSetName set) 5662c393a42Smrg{ 5672c393a42Smrg if (config->fonts[set]) 5682c393a42Smrg FcFontSetDestroy (config->fonts[set]); 5692c393a42Smrg config->fonts[set] = fonts; 5702c393a42Smrg} 5712c393a42Smrg 5722c393a42SmrgFcBlanks * 5732c393a42SmrgFcConfigGetBlanks (FcConfig *config) 5742c393a42Smrg{ 5752c393a42Smrg if (!config) 5762c393a42Smrg { 5772c393a42Smrg config = FcConfigGetCurrent (); 5782c393a42Smrg if (!config) 5792c393a42Smrg return 0; 5802c393a42Smrg } 5812c393a42Smrg return config->blanks; 5822c393a42Smrg} 5832c393a42Smrg 5842c393a42SmrgFcBool 5852c393a42SmrgFcConfigAddBlank (FcConfig *config, 5862c393a42Smrg FcChar32 blank) 5872c393a42Smrg{ 5882c393a42Smrg FcBlanks *b, *freeme = 0; 589ca08ab68Smrg 5902c393a42Smrg b = config->blanks; 5912c393a42Smrg if (!b) 5922c393a42Smrg { 5932c393a42Smrg freeme = b = FcBlanksCreate (); 5942c393a42Smrg if (!b) 5952c393a42Smrg return FcFalse; 5962c393a42Smrg } 5972c393a42Smrg if (!FcBlanksAdd (b, blank)) 5982c393a42Smrg { 5992c393a42Smrg if (freeme) 6002c393a42Smrg FcBlanksDestroy (freeme); 6012c393a42Smrg return FcFalse; 6022c393a42Smrg } 6032c393a42Smrg config->blanks = b; 6042c393a42Smrg return FcTrue; 6052c393a42Smrg} 6062c393a42Smrg 6072c393a42Smrgint 6082c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 6092c393a42Smrg{ 6102c393a42Smrg if (!config) 6112c393a42Smrg { 6122c393a42Smrg config = FcConfigGetCurrent (); 6132c393a42Smrg if (!config) 6142c393a42Smrg return 0; 6152c393a42Smrg } 6162c393a42Smrg return config->rescanInterval; 6172c393a42Smrg} 6182c393a42Smrg 6192c393a42SmrgFcBool 6202c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 6212c393a42Smrg{ 6222c393a42Smrg if (!config) 6232c393a42Smrg { 6242c393a42Smrg config = FcConfigGetCurrent (); 6252c393a42Smrg if (!config) 6262c393a42Smrg return FcFalse; 6272c393a42Smrg } 6282c393a42Smrg config->rescanInterval = rescanInterval; 6292c393a42Smrg return FcTrue; 6302c393a42Smrg} 6312c393a42Smrg 6322c393a42Smrg/* 6332c393a42Smrg * A couple of typos escaped into the library 6342c393a42Smrg */ 6352c393a42Smrgint 6362c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 6372c393a42Smrg{ 6382c393a42Smrg return FcConfigGetRescanInterval (config); 6392c393a42Smrg} 6402c393a42Smrg 6412c393a42SmrgFcBool 6422c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 6432c393a42Smrg{ 6442c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 6452c393a42Smrg} 6462c393a42Smrg 647ca08ab68Smrg 6482c393a42SmrgFcBool 6492c393a42SmrgFcConfigAddEdit (FcConfig *config, 6502c393a42Smrg FcTest *test, 6512c393a42Smrg FcEdit *edit, 6522c393a42Smrg FcMatchKind kind) 6532c393a42Smrg{ 6542c393a42Smrg FcSubst *subst, **prev; 6552c393a42Smrg FcTest *t; 6562c393a42Smrg int num; 6572c393a42Smrg 6582c393a42Smrg switch (kind) { 6592c393a42Smrg case FcMatchPattern: 6602c393a42Smrg prev = &config->substPattern; 6612c393a42Smrg break; 6622c393a42Smrg case FcMatchFont: 6632c393a42Smrg prev = &config->substFont; 6642c393a42Smrg break; 6652c393a42Smrg case FcMatchScan: 6662c393a42Smrg prev = &config->substScan; 6672c393a42Smrg break; 6682c393a42Smrg default: 6692c393a42Smrg return FcFalse; 6702c393a42Smrg } 6712c393a42Smrg subst = (FcSubst *) malloc (sizeof (FcSubst)); 6722c393a42Smrg if (!subst) 6732c393a42Smrg return FcFalse; 6742c393a42Smrg for (; *prev; prev = &(*prev)->next); 6752c393a42Smrg *prev = subst; 6762c393a42Smrg subst->next = 0; 6772c393a42Smrg subst->test = test; 6782c393a42Smrg subst->edit = edit; 6792c393a42Smrg num = 0; 6802c393a42Smrg for (t = test; t; t = t->next) 6812c393a42Smrg { 6822c393a42Smrg if (t->kind == FcMatchDefault) 6832c393a42Smrg t->kind = kind; 6842c393a42Smrg num++; 6852c393a42Smrg } 6862c393a42Smrg if (config->maxObjects < num) 6872c393a42Smrg config->maxObjects = num; 6882c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 6892c393a42Smrg { 6902c393a42Smrg printf ("Add Subst "); 6912c393a42Smrg FcSubstPrint (subst); 6922c393a42Smrg } 6932c393a42Smrg return FcTrue; 6942c393a42Smrg} 6952c393a42Smrg 6962c393a42Smrgtypedef struct _FcSubState { 6972c393a42Smrg FcPatternElt *elt; 6982c393a42Smrg FcValueList *value; 6992c393a42Smrg} FcSubState; 7002c393a42Smrg 7012c393a42Smrgstatic FcValue 702c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) 7032c393a42Smrg{ 7042c393a42Smrg if (v.type == FcTypeInteger) 7052c393a42Smrg { 7062c393a42Smrg v.type = FcTypeDouble; 7072c393a42Smrg v.u.d = (double) v.u.i; 7082c393a42Smrg } 7092c393a42Smrg else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 7102c393a42Smrg { 7112c393a42Smrg v.u.m = &FcIdentityMatrix; 7122c393a42Smrg v.type = FcTypeMatrix; 7132c393a42Smrg } 714c9710b42Smrg else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) 7152c393a42Smrg { 716c9710b42Smrg v.u.l = FcLangSetPromote (v.u.s, buf); 7172c393a42Smrg v.type = FcTypeLangSet; 7182c393a42Smrg } 7192c393a42Smrg return v; 7202c393a42Smrg} 7212c393a42Smrg 7222c393a42SmrgFcBool 7232c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 724ca08ab68Smrg FcOp op_, 7252c393a42Smrg const FcValue *right_o) 7262c393a42Smrg{ 7272c393a42Smrg FcValue left = FcValueCanonicalize(left_o); 7282c393a42Smrg FcValue right = FcValueCanonicalize(right_o); 7292c393a42Smrg FcBool ret = FcFalse; 730ca08ab68Smrg FcOp op = FC_OP_GET_OP (op_); 731ca08ab68Smrg int flags = FC_OP_GET_FLAGS (op_); 732c9710b42Smrg FcValuePromotionBuffer buf1, buf2; 733ca08ab68Smrg 734c9710b42Smrg left = FcConfigPromote (left, right, &buf1); 735c9710b42Smrg right = FcConfigPromote (right, left, &buf2); 736ca08ab68Smrg if (left.type == right.type) 7372c393a42Smrg { 7382c393a42Smrg switch (left.type) { 7392c393a42Smrg case FcTypeInteger: 7402c393a42Smrg break; /* FcConfigPromote prevents this from happening */ 7412c393a42Smrg case FcTypeDouble: 742c9710b42Smrg switch ((int) op) { 7432c393a42Smrg case FcOpEqual: 7442c393a42Smrg case FcOpContains: 7452c393a42Smrg case FcOpListing: 7462c393a42Smrg ret = left.u.d == right.u.d; 7472c393a42Smrg break; 7482c393a42Smrg case FcOpNotEqual: 7492c393a42Smrg case FcOpNotContains: 7502c393a42Smrg ret = left.u.d != right.u.d; 7512c393a42Smrg break; 752ca08ab68Smrg case FcOpLess: 7532c393a42Smrg ret = left.u.d < right.u.d; 7542c393a42Smrg break; 755ca08ab68Smrg case FcOpLessEqual: 7562c393a42Smrg ret = left.u.d <= right.u.d; 7572c393a42Smrg break; 758ca08ab68Smrg case FcOpMore: 7592c393a42Smrg ret = left.u.d > right.u.d; 7602c393a42Smrg break; 761ca08ab68Smrg case FcOpMoreEqual: 7622c393a42Smrg ret = left.u.d >= right.u.d; 7632c393a42Smrg break; 7642c393a42Smrg default: 7652c393a42Smrg break; 7662c393a42Smrg } 7672c393a42Smrg break; 7682c393a42Smrg case FcTypeBool: 769c9710b42Smrg switch ((int) op) { 770ca08ab68Smrg case FcOpEqual: 7712c393a42Smrg case FcOpContains: 7722c393a42Smrg case FcOpListing: 7732c393a42Smrg ret = left.u.b == right.u.b; 7742c393a42Smrg break; 7752c393a42Smrg case FcOpNotEqual: 7762c393a42Smrg case FcOpNotContains: 7772c393a42Smrg ret = left.u.b != right.u.b; 7782c393a42Smrg break; 7792c393a42Smrg default: 7802c393a42Smrg break; 7812c393a42Smrg } 7822c393a42Smrg break; 7832c393a42Smrg case FcTypeString: 784c9710b42Smrg switch ((int) op) { 785ca08ab68Smrg case FcOpEqual: 7862c393a42Smrg case FcOpListing: 787ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 788ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 789ca08ab68Smrg else 790ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 7912c393a42Smrg break; 7922c393a42Smrg case FcOpContains: 7932c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 7942c393a42Smrg break; 7952c393a42Smrg case FcOpNotEqual: 796ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 797ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 798ca08ab68Smrg else 799ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 8002c393a42Smrg break; 8012c393a42Smrg case FcOpNotContains: 8022c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 8032c393a42Smrg break; 8042c393a42Smrg default: 8052c393a42Smrg break; 8062c393a42Smrg } 8072c393a42Smrg break; 8082c393a42Smrg case FcTypeMatrix: 809c9710b42Smrg switch ((int) op) { 8102c393a42Smrg case FcOpEqual: 8112c393a42Smrg case FcOpContains: 8122c393a42Smrg case FcOpListing: 8132c393a42Smrg ret = FcMatrixEqual (left.u.m, right.u.m); 8142c393a42Smrg break; 8152c393a42Smrg case FcOpNotEqual: 8162c393a42Smrg case FcOpNotContains: 8172c393a42Smrg ret = !FcMatrixEqual (left.u.m, right.u.m); 8182c393a42Smrg break; 8192c393a42Smrg default: 8202c393a42Smrg break; 8212c393a42Smrg } 8222c393a42Smrg break; 8232c393a42Smrg case FcTypeCharSet: 824c9710b42Smrg switch ((int) op) { 8252c393a42Smrg case FcOpContains: 8262c393a42Smrg case FcOpListing: 8272c393a42Smrg /* left contains right if right is a subset of left */ 8282c393a42Smrg ret = FcCharSetIsSubset (right.u.c, left.u.c); 8292c393a42Smrg break; 8302c393a42Smrg case FcOpNotContains: 8312c393a42Smrg /* left contains right if right is a subset of left */ 8322c393a42Smrg ret = !FcCharSetIsSubset (right.u.c, left.u.c); 8332c393a42Smrg break; 8342c393a42Smrg case FcOpEqual: 8352c393a42Smrg ret = FcCharSetEqual (left.u.c, right.u.c); 8362c393a42Smrg break; 8372c393a42Smrg case FcOpNotEqual: 8382c393a42Smrg ret = !FcCharSetEqual (left.u.c, right.u.c); 8392c393a42Smrg break; 8402c393a42Smrg default: 8412c393a42Smrg break; 8422c393a42Smrg } 8432c393a42Smrg break; 8442c393a42Smrg case FcTypeLangSet: 845c9710b42Smrg switch ((int) op) { 8462c393a42Smrg case FcOpContains: 8472c393a42Smrg case FcOpListing: 8482c393a42Smrg ret = FcLangSetContains (left.u.l, right.u.l); 8492c393a42Smrg break; 8502c393a42Smrg case FcOpNotContains: 8512c393a42Smrg ret = !FcLangSetContains (left.u.l, right.u.l); 8522c393a42Smrg break; 8532c393a42Smrg case FcOpEqual: 8542c393a42Smrg ret = FcLangSetEqual (left.u.l, right.u.l); 8552c393a42Smrg break; 8562c393a42Smrg case FcOpNotEqual: 8572c393a42Smrg ret = !FcLangSetEqual (left.u.l, right.u.l); 8582c393a42Smrg break; 8592c393a42Smrg default: 8602c393a42Smrg break; 8612c393a42Smrg } 8622c393a42Smrg break; 8632c393a42Smrg case FcTypeVoid: 864c9710b42Smrg switch ((int) op) { 8652c393a42Smrg case FcOpEqual: 8662c393a42Smrg case FcOpContains: 8672c393a42Smrg case FcOpListing: 8682c393a42Smrg ret = FcTrue; 8692c393a42Smrg break; 8702c393a42Smrg default: 8712c393a42Smrg break; 8722c393a42Smrg } 8732c393a42Smrg break; 8742c393a42Smrg case FcTypeFTFace: 875c9710b42Smrg switch ((int) op) { 8762c393a42Smrg case FcOpEqual: 8772c393a42Smrg case FcOpContains: 8782c393a42Smrg case FcOpListing: 8792c393a42Smrg ret = left.u.f == right.u.f; 8802c393a42Smrg break; 8812c393a42Smrg case FcOpNotEqual: 8822c393a42Smrg case FcOpNotContains: 8832c393a42Smrg ret = left.u.f != right.u.f; 8842c393a42Smrg break; 8852c393a42Smrg default: 8862c393a42Smrg break; 8872c393a42Smrg } 8882c393a42Smrg break; 8892c393a42Smrg } 8902c393a42Smrg } 8912c393a42Smrg else 8922c393a42Smrg { 8932c393a42Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 8942c393a42Smrg ret = FcTrue; 8952c393a42Smrg } 8962c393a42Smrg return ret; 8972c393a42Smrg} 8982c393a42Smrg 8992c393a42Smrg 9002c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 9012c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 9022c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 9032c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 9042c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 9052c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 9062c393a42Smrg 9072c393a42Smrgstatic FcValue 908c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) 9092c393a42Smrg{ 9102c393a42Smrg FcValue v, vl, vr; 9112c393a42Smrg FcMatrix *m; 9122c393a42Smrg FcChar8 *str; 913ca08ab68Smrg FcOp op = FC_OP_GET_OP (e->op); 914ca08ab68Smrg 915c9710b42Smrg switch ((int) op) { 9162c393a42Smrg case FcOpInteger: 9172c393a42Smrg v.type = FcTypeInteger; 9182c393a42Smrg v.u.i = e->u.ival; 9192c393a42Smrg break; 9202c393a42Smrg case FcOpDouble: 9212c393a42Smrg v.type = FcTypeDouble; 9222c393a42Smrg v.u.d = e->u.dval; 9232c393a42Smrg break; 9242c393a42Smrg case FcOpString: 9252c393a42Smrg v.type = FcTypeString; 926a6844aabSmrg v.u.s = e->u.sval; 927a6844aabSmrg v = FcValueSave (v); 9282c393a42Smrg break; 9292c393a42Smrg case FcOpMatrix: 930c9710b42Smrg { 931c9710b42Smrg FcMatrix m; 932c9710b42Smrg FcValue xx, xy, yx, yy; 933c9710b42Smrg v.type = FcTypeMatrix; 934c9710b42Smrg xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); 935c9710b42Smrg xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); 936c9710b42Smrg yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); 937c9710b42Smrg yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); 938c9710b42Smrg if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && 939c9710b42Smrg yx.type == FcTypeDouble && yy.type == FcTypeDouble) 940c9710b42Smrg { 941c9710b42Smrg m.xx = xx.u.d; 942c9710b42Smrg m.xy = xy.u.d; 943c9710b42Smrg m.yx = yx.u.d; 944c9710b42Smrg m.yy = yy.u.d; 945c9710b42Smrg v.u.m = &m; 946c9710b42Smrg } 947c9710b42Smrg else 948c9710b42Smrg v.type = FcTypeVoid; 949c9710b42Smrg v = FcValueSave (v); 950c9710b42Smrg } 9512c393a42Smrg break; 9522c393a42Smrg case FcOpCharSet: 9532c393a42Smrg v.type = FcTypeCharSet; 9542c393a42Smrg v.u.c = e->u.cval; 9552c393a42Smrg v = FcValueSave (v); 9562c393a42Smrg break; 957ca08ab68Smrg case FcOpLangSet: 958ca08ab68Smrg v.type = FcTypeLangSet; 959ca08ab68Smrg v.u.l = e->u.lval; 960ca08ab68Smrg v = FcValueSave (v); 961ca08ab68Smrg break; 9622c393a42Smrg case FcOpBool: 9632c393a42Smrg v.type = FcTypeBool; 9642c393a42Smrg v.u.b = e->u.bval; 9652c393a42Smrg break; 9662c393a42Smrg case FcOpField: 967c9710b42Smrg if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) 968c9710b42Smrg { 969c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) 970c9710b42Smrg v.type = FcTypeVoid; 971c9710b42Smrg } 972c9710b42Smrg else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) 973c9710b42Smrg { 974c9710b42Smrg fprintf (stderr, 975c9710b42Smrg "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); 9762c393a42Smrg v.type = FcTypeVoid; 977c9710b42Smrg } 978c9710b42Smrg else 979c9710b42Smrg { 980c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) 981c9710b42Smrg v.type = FcTypeVoid; 982c9710b42Smrg } 9832c393a42Smrg v = FcValueSave (v); 9842c393a42Smrg break; 9852c393a42Smrg case FcOpConst: 9862c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 9872c393a42Smrg v.type = FcTypeInteger; 9882c393a42Smrg else 9892c393a42Smrg v.type = FcTypeVoid; 9902c393a42Smrg break; 9912c393a42Smrg case FcOpQuest: 992c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 9932c393a42Smrg if (vl.type == FcTypeBool) 9942c393a42Smrg { 9952c393a42Smrg if (vl.u.b) 996c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); 9972c393a42Smrg else 998c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right); 9992c393a42Smrg } 10002c393a42Smrg else 10012c393a42Smrg v.type = FcTypeVoid; 10022c393a42Smrg FcValueDestroy (vl); 10032c393a42Smrg break; 10042c393a42Smrg case FcOpEqual: 10052c393a42Smrg case FcOpNotEqual: 10062c393a42Smrg case FcOpLess: 10072c393a42Smrg case FcOpLessEqual: 10082c393a42Smrg case FcOpMore: 10092c393a42Smrg case FcOpMoreEqual: 10102c393a42Smrg case FcOpContains: 10112c393a42Smrg case FcOpNotContains: 10122c393a42Smrg case FcOpListing: 1013c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1014c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 10152c393a42Smrg v.type = FcTypeBool; 10162c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 10172c393a42Smrg FcValueDestroy (vl); 10182c393a42Smrg FcValueDestroy (vr); 10192c393a42Smrg break; 10202c393a42Smrg case FcOpOr: 10212c393a42Smrg case FcOpAnd: 10222c393a42Smrg case FcOpPlus: 10232c393a42Smrg case FcOpMinus: 10242c393a42Smrg case FcOpTimes: 10252c393a42Smrg case FcOpDivide: 1026c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1027c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 1028c9710b42Smrg vl = FcConfigPromote (vl, vr, NULL); 1029c9710b42Smrg vr = FcConfigPromote (vr, vl, NULL); 10302c393a42Smrg if (vl.type == vr.type) 10312c393a42Smrg { 1032c9710b42Smrg switch ((int) vl.type) { 10332c393a42Smrg case FcTypeDouble: 1034c9710b42Smrg switch ((int) op) { 1035ca08ab68Smrg case FcOpPlus: 10362c393a42Smrg v.type = FcTypeDouble; 1037ca08ab68Smrg v.u.d = vl.u.d + vr.u.d; 10382c393a42Smrg break; 10392c393a42Smrg case FcOpMinus: 10402c393a42Smrg v.type = FcTypeDouble; 1041ca08ab68Smrg v.u.d = vl.u.d - vr.u.d; 10422c393a42Smrg break; 10432c393a42Smrg case FcOpTimes: 10442c393a42Smrg v.type = FcTypeDouble; 1045ca08ab68Smrg v.u.d = vl.u.d * vr.u.d; 10462c393a42Smrg break; 10472c393a42Smrg case FcOpDivide: 10482c393a42Smrg v.type = FcTypeDouble; 1049ca08ab68Smrg v.u.d = vl.u.d / vr.u.d; 10502c393a42Smrg break; 10512c393a42Smrg default: 1052ca08ab68Smrg v.type = FcTypeVoid; 10532c393a42Smrg break; 10542c393a42Smrg } 10552c393a42Smrg if (v.type == FcTypeDouble && 10562c393a42Smrg v.u.d == (double) (int) v.u.d) 10572c393a42Smrg { 10582c393a42Smrg v.type = FcTypeInteger; 10592c393a42Smrg v.u.i = (int) v.u.d; 10602c393a42Smrg } 10612c393a42Smrg break; 10622c393a42Smrg case FcTypeBool: 1063c9710b42Smrg switch ((int) op) { 10642c393a42Smrg case FcOpOr: 10652c393a42Smrg v.type = FcTypeBool; 10662c393a42Smrg v.u.b = vl.u.b || vr.u.b; 10672c393a42Smrg break; 10682c393a42Smrg case FcOpAnd: 10692c393a42Smrg v.type = FcTypeBool; 10702c393a42Smrg v.u.b = vl.u.b && vr.u.b; 10712c393a42Smrg break; 10722c393a42Smrg default: 1073ca08ab68Smrg v.type = FcTypeVoid; 10742c393a42Smrg break; 10752c393a42Smrg } 10762c393a42Smrg break; 10772c393a42Smrg case FcTypeString: 1078c9710b42Smrg switch ((int) op) { 10792c393a42Smrg case FcOpPlus: 10802c393a42Smrg v.type = FcTypeString; 10812c393a42Smrg str = FcStrPlus (vl.u.s, vr.u.s); 1082c9710b42Smrg v.u.s = FcStrdup (str); 10832c393a42Smrg FcStrFree (str); 1084ca08ab68Smrg 10852c393a42Smrg if (!v.u.s) 10862c393a42Smrg v.type = FcTypeVoid; 10872c393a42Smrg break; 10882c393a42Smrg default: 10892c393a42Smrg v.type = FcTypeVoid; 10902c393a42Smrg break; 10912c393a42Smrg } 10922c393a42Smrg break; 10932c393a42Smrg case FcTypeMatrix: 1094c9710b42Smrg switch ((int) op) { 10952c393a42Smrg case FcOpTimes: 10962c393a42Smrg v.type = FcTypeMatrix; 10972c393a42Smrg m = malloc (sizeof (FcMatrix)); 10982c393a42Smrg if (m) 10992c393a42Smrg { 11002c393a42Smrg FcMatrixMultiply (m, vl.u.m, vr.u.m); 11012c393a42Smrg v.u.m = m; 11022c393a42Smrg } 11032c393a42Smrg else 11042c393a42Smrg { 11052c393a42Smrg v.type = FcTypeVoid; 11062c393a42Smrg } 11072c393a42Smrg break; 11082c393a42Smrg default: 11092c393a42Smrg v.type = FcTypeVoid; 11102c393a42Smrg break; 11112c393a42Smrg } 11122c393a42Smrg break; 1113ca08ab68Smrg case FcTypeCharSet: 1114c9710b42Smrg switch ((int) op) { 1115ca08ab68Smrg case FcOpPlus: 1116ca08ab68Smrg v.type = FcTypeCharSet; 1117ca08ab68Smrg v.u.c = FcCharSetUnion (vl.u.c, vr.u.c); 1118ca08ab68Smrg if (!v.u.c) 1119ca08ab68Smrg v.type = FcTypeVoid; 1120ca08ab68Smrg break; 1121ca08ab68Smrg case FcOpMinus: 1122ca08ab68Smrg v.type = FcTypeCharSet; 1123ca08ab68Smrg v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c); 1124ca08ab68Smrg if (!v.u.c) 1125ca08ab68Smrg v.type = FcTypeVoid; 1126ca08ab68Smrg break; 1127ca08ab68Smrg default: 1128ca08ab68Smrg v.type = FcTypeVoid; 1129ca08ab68Smrg break; 1130ca08ab68Smrg } 1131ca08ab68Smrg break; 1132ca08ab68Smrg case FcTypeLangSet: 1133c9710b42Smrg switch ((int) op) { 1134ca08ab68Smrg case FcOpPlus: 1135ca08ab68Smrg v.type = FcTypeLangSet; 1136ca08ab68Smrg v.u.l = FcLangSetUnion (vl.u.l, vr.u.l); 1137ca08ab68Smrg if (!v.u.l) 1138ca08ab68Smrg v.type = FcTypeVoid; 1139ca08ab68Smrg break; 1140ca08ab68Smrg case FcOpMinus: 1141ca08ab68Smrg v.type = FcTypeLangSet; 1142ca08ab68Smrg v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l); 1143ca08ab68Smrg if (!v.u.l) 1144ca08ab68Smrg v.type = FcTypeVoid; 1145ca08ab68Smrg break; 1146ca08ab68Smrg default: 1147ca08ab68Smrg v.type = FcTypeVoid; 1148ca08ab68Smrg break; 1149ca08ab68Smrg } 1150ca08ab68Smrg break; 11512c393a42Smrg default: 11522c393a42Smrg v.type = FcTypeVoid; 11532c393a42Smrg break; 11542c393a42Smrg } 11552c393a42Smrg } 11562c393a42Smrg else 11572c393a42Smrg v.type = FcTypeVoid; 11582c393a42Smrg FcValueDestroy (vl); 11592c393a42Smrg FcValueDestroy (vr); 11602c393a42Smrg break; 11612c393a42Smrg case FcOpNot: 1162c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1163c9710b42Smrg switch ((int) vl.type) { 11642c393a42Smrg case FcTypeBool: 11652c393a42Smrg v.type = FcTypeBool; 11662c393a42Smrg v.u.b = !vl.u.b; 11672c393a42Smrg break; 11682c393a42Smrg default: 11692c393a42Smrg v.type = FcTypeVoid; 11702c393a42Smrg break; 11712c393a42Smrg } 11722c393a42Smrg FcValueDestroy (vl); 11732c393a42Smrg break; 11742c393a42Smrg case FcOpFloor: 1175c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1176c9710b42Smrg switch ((int) vl.type) { 11772c393a42Smrg case FcTypeInteger: 11782c393a42Smrg v = vl; 11792c393a42Smrg break; 11802c393a42Smrg case FcTypeDouble: 11812c393a42Smrg v.type = FcTypeInteger; 11822c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 11832c393a42Smrg break; 11842c393a42Smrg default: 11852c393a42Smrg v.type = FcTypeVoid; 11862c393a42Smrg break; 11872c393a42Smrg } 11882c393a42Smrg FcValueDestroy (vl); 11892c393a42Smrg break; 11902c393a42Smrg case FcOpCeil: 1191c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1192c9710b42Smrg switch ((int) vl.type) { 11932c393a42Smrg case FcTypeInteger: 11942c393a42Smrg v = vl; 11952c393a42Smrg break; 11962c393a42Smrg case FcTypeDouble: 11972c393a42Smrg v.type = FcTypeInteger; 11982c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 11992c393a42Smrg break; 12002c393a42Smrg default: 12012c393a42Smrg v.type = FcTypeVoid; 12022c393a42Smrg break; 12032c393a42Smrg } 12042c393a42Smrg FcValueDestroy (vl); 12052c393a42Smrg break; 12062c393a42Smrg case FcOpRound: 1207c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1208c9710b42Smrg switch ((int) vl.type) { 12092c393a42Smrg case FcTypeInteger: 12102c393a42Smrg v = vl; 12112c393a42Smrg break; 12122c393a42Smrg case FcTypeDouble: 12132c393a42Smrg v.type = FcTypeInteger; 12142c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 12152c393a42Smrg break; 12162c393a42Smrg default: 12172c393a42Smrg v.type = FcTypeVoid; 12182c393a42Smrg break; 12192c393a42Smrg } 12202c393a42Smrg FcValueDestroy (vl); 12212c393a42Smrg break; 12222c393a42Smrg case FcOpTrunc: 1223c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1224c9710b42Smrg switch ((int) vl.type) { 12252c393a42Smrg case FcTypeInteger: 12262c393a42Smrg v = vl; 12272c393a42Smrg break; 12282c393a42Smrg case FcTypeDouble: 12292c393a42Smrg v.type = FcTypeInteger; 12302c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 12312c393a42Smrg break; 12322c393a42Smrg default: 12332c393a42Smrg v.type = FcTypeVoid; 12342c393a42Smrg break; 12352c393a42Smrg } 12362c393a42Smrg FcValueDestroy (vl); 12372c393a42Smrg break; 12382c393a42Smrg default: 12392c393a42Smrg v.type = FcTypeVoid; 12402c393a42Smrg break; 12412c393a42Smrg } 12422c393a42Smrg return v; 12432c393a42Smrg} 12442c393a42Smrg 12452c393a42Smrgstatic FcValueList * 12462c393a42SmrgFcConfigMatchValueList (FcPattern *p, 1247c9710b42Smrg FcPattern *p_pat, 1248c9710b42Smrg FcMatchKind kind, 12492c393a42Smrg FcTest *t, 12502c393a42Smrg FcValueList *values) 12512c393a42Smrg{ 12522c393a42Smrg FcValueList *ret = 0; 12532c393a42Smrg FcExpr *e = t->expr; 12542c393a42Smrg FcValue value; 12552c393a42Smrg FcValueList *v; 1256ca08ab68Smrg 12572c393a42Smrg while (e) 12582c393a42Smrg { 12592c393a42Smrg /* Compute the value of the match expression */ 1260ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 12612c393a42Smrg { 1262c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 12632c393a42Smrg e = e->u.tree.right; 12642c393a42Smrg } 12652c393a42Smrg else 12662c393a42Smrg { 1267c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e); 12682c393a42Smrg e = 0; 12692c393a42Smrg } 12702c393a42Smrg 12712c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 12722c393a42Smrg { 12732c393a42Smrg /* Compare the pattern value to the match expression value */ 12742c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 12752c393a42Smrg { 12762c393a42Smrg if (!ret) 12772c393a42Smrg ret = v; 12782c393a42Smrg } 12792c393a42Smrg else 12802c393a42Smrg { 12812c393a42Smrg if (t->qual == FcQualAll) 12822c393a42Smrg { 12832c393a42Smrg ret = 0; 12842c393a42Smrg break; 12852c393a42Smrg } 12862c393a42Smrg } 12872c393a42Smrg } 12882c393a42Smrg FcValueDestroy (value); 12892c393a42Smrg } 12902c393a42Smrg return ret; 12912c393a42Smrg} 12922c393a42Smrg 12932c393a42Smrgstatic FcValueList * 1294c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) 12952c393a42Smrg{ 12962c393a42Smrg FcValueList *l; 1297ca08ab68Smrg 12982c393a42Smrg if (!e) 12992c393a42Smrg return 0; 13002c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 13012c393a42Smrg if (!l) 13022c393a42Smrg return 0; 1303ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 13042c393a42Smrg { 1305c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1306c9710b42Smrg l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); 13072c393a42Smrg } 13082c393a42Smrg else 13092c393a42Smrg { 1310c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e); 13112c393a42Smrg l->next = NULL; 13122c393a42Smrg } 13132c393a42Smrg l->binding = binding; 13142c393a42Smrg if (l->value.type == FcTypeVoid) 13152c393a42Smrg { 13162c393a42Smrg FcValueList *next = FcValueListNext(l); 13172c393a42Smrg 13182c393a42Smrg free (l); 13192c393a42Smrg l = next; 13202c393a42Smrg } 13212c393a42Smrg 13222c393a42Smrg return l; 13232c393a42Smrg} 13242c393a42Smrg 13252c393a42Smrgstatic FcBool 13262c393a42SmrgFcConfigAdd (FcValueListPtr *head, 13272c393a42Smrg FcValueList *position, 13282c393a42Smrg FcBool append, 1329c9710b42Smrg FcValueList *new, 1330c9710b42Smrg FcObject object) 13312c393a42Smrg{ 1332c9710b42Smrg FcValueListPtr *prev, l, last, v; 13332c393a42Smrg FcValueBinding sameBinding; 1334ca08ab68Smrg 1335c9710b42Smrg /* 1336c9710b42Smrg * Make sure the stored type is valid for built-in objects 1337c9710b42Smrg */ 1338c9710b42Smrg for (l = new; l != NULL; l = FcValueListNext (l)) 1339c9710b42Smrg { 1340c9710b42Smrg if (!FcObjectValidType (object, l->value.type)) 1341c9710b42Smrg { 1342c9710b42Smrg fprintf (stderr, 1343c9710b42Smrg "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 1344c9710b42Smrg FcValuePrintFile (stderr, l->value); 1345c9710b42Smrg fprintf (stderr, "\n"); 1346c9710b42Smrg 1347c9710b42Smrg if (FcDebug () & FC_DBG_EDIT) 1348c9710b42Smrg { 1349c9710b42Smrg printf ("Not adding\n"); 1350c9710b42Smrg } 1351c9710b42Smrg 1352c9710b42Smrg return FcFalse; 1353c9710b42Smrg } 1354c9710b42Smrg } 1355c9710b42Smrg 13562c393a42Smrg if (position) 13572c393a42Smrg sameBinding = position->binding; 13582c393a42Smrg else 13592c393a42Smrg sameBinding = FcValueBindingWeak; 13602c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 13612c393a42Smrg if (v->binding == FcValueBindingSame) 13622c393a42Smrg v->binding = sameBinding; 13632c393a42Smrg if (append) 13642c393a42Smrg { 13652c393a42Smrg if (position) 13662c393a42Smrg prev = &position->next; 13672c393a42Smrg else 1368ca08ab68Smrg for (prev = head; *prev != NULL; 13692c393a42Smrg prev = &(*prev)->next) 13702c393a42Smrg ; 13712c393a42Smrg } 13722c393a42Smrg else 13732c393a42Smrg { 13742c393a42Smrg if (position) 13752c393a42Smrg { 1376ca08ab68Smrg for (prev = head; *prev != NULL; 13772c393a42Smrg prev = &(*prev)->next) 13782c393a42Smrg { 13792c393a42Smrg if (*prev == position) 13802c393a42Smrg break; 13812c393a42Smrg } 13822c393a42Smrg } 13832c393a42Smrg else 13842c393a42Smrg prev = head; 13852c393a42Smrg 13862c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13872c393a42Smrg { 13882c393a42Smrg if (*prev == NULL) 13892c393a42Smrg printf ("position not on list\n"); 13902c393a42Smrg } 13912c393a42Smrg } 13922c393a42Smrg 13932c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13942c393a42Smrg { 13952c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 1396ca08ab68Smrg FcValueListPrintWithPosition (*head, *prev); 13972c393a42Smrg printf ("\n"); 13982c393a42Smrg } 1399ca08ab68Smrg 14002c393a42Smrg if (new) 14012c393a42Smrg { 14022c393a42Smrg last = new; 14032c393a42Smrg while (last->next != NULL) 14042c393a42Smrg last = last->next; 1405ca08ab68Smrg 14062c393a42Smrg last->next = *prev; 14072c393a42Smrg *prev = new; 14082c393a42Smrg } 1409ca08ab68Smrg 14102c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14112c393a42Smrg { 14122c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 14132c393a42Smrg FcValueListPrint (*head); 14142c393a42Smrg printf ("\n"); 14152c393a42Smrg } 1416ca08ab68Smrg 14172c393a42Smrg return FcTrue; 14182c393a42Smrg} 14192c393a42Smrg 14202c393a42Smrgstatic void 14212c393a42SmrgFcConfigDel (FcValueListPtr *head, 14222c393a42Smrg FcValueList *position) 14232c393a42Smrg{ 14242c393a42Smrg FcValueListPtr *prev; 14252c393a42Smrg 14262c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 14272c393a42Smrg { 14282c393a42Smrg if (*prev == position) 14292c393a42Smrg { 14302c393a42Smrg *prev = position->next; 14312c393a42Smrg position->next = NULL; 14322c393a42Smrg FcValueListDestroy (position); 14332c393a42Smrg break; 14342c393a42Smrg } 14352c393a42Smrg } 14362c393a42Smrg} 14372c393a42Smrg 14382c393a42Smrgstatic void 14392c393a42SmrgFcConfigPatternAdd (FcPattern *p, 14402c393a42Smrg FcObject object, 14412c393a42Smrg FcValueList *list, 14422c393a42Smrg FcBool append) 14432c393a42Smrg{ 14442c393a42Smrg if (list) 14452c393a42Smrg { 14462c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1447ca08ab68Smrg 14482c393a42Smrg if (!e) 14492c393a42Smrg return; 1450c9710b42Smrg FcConfigAdd (&e->values, 0, append, list, object); 14512c393a42Smrg } 14522c393a42Smrg} 14532c393a42Smrg 14542c393a42Smrg/* 14552c393a42Smrg * Delete all values associated with a field 14562c393a42Smrg */ 14572c393a42Smrgstatic void 14582c393a42SmrgFcConfigPatternDel (FcPattern *p, 14592c393a42Smrg FcObject object) 14602c393a42Smrg{ 14612c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 14622c393a42Smrg if (!e) 14632c393a42Smrg return; 14642c393a42Smrg while (e->values != NULL) 14652c393a42Smrg FcConfigDel (&e->values, e->values); 14662c393a42Smrg} 14672c393a42Smrg 14682c393a42Smrgstatic void 14692c393a42SmrgFcConfigPatternCanon (FcPattern *p, 14702c393a42Smrg FcObject object) 14712c393a42Smrg{ 14722c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 14732c393a42Smrg if (!e) 14742c393a42Smrg return; 14752c393a42Smrg if (e->values == NULL) 14762c393a42Smrg FcPatternObjectDel (p, object); 14772c393a42Smrg} 14782c393a42Smrg 14792c393a42SmrgFcBool 14802c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 14812c393a42Smrg FcPattern *p, 14822c393a42Smrg FcPattern *p_pat, 14832c393a42Smrg FcMatchKind kind) 14842c393a42Smrg{ 1485c9710b42Smrg FcValue v; 14862c393a42Smrg FcSubst *s; 14872c393a42Smrg FcSubState *st; 14882c393a42Smrg int i; 14892c393a42Smrg FcTest *t; 14902c393a42Smrg FcEdit *e; 14912c393a42Smrg FcValueList *l; 14922c393a42Smrg FcPattern *m; 1493ca08ab68Smrg FcStrSet *strs; 14942c393a42Smrg 14952c393a42Smrg if (!config) 14962c393a42Smrg { 14972c393a42Smrg config = FcConfigGetCurrent (); 14982c393a42Smrg if (!config) 14992c393a42Smrg return FcFalse; 15002c393a42Smrg } 15012c393a42Smrg 15022c393a42Smrg switch (kind) { 15032c393a42Smrg case FcMatchPattern: 15042c393a42Smrg s = config->substPattern; 1505ca08ab68Smrg strs = FcGetDefaultLangs (); 1506ca08ab68Smrg if (strs) 1507ca08ab68Smrg { 1508ca08ab68Smrg FcStrList *l = FcStrListCreate (strs); 1509ca08ab68Smrg FcChar8 *lang; 1510ca08ab68Smrg FcValue v; 1511ca08ab68Smrg 1512ca08ab68Smrg FcStrSetDestroy (strs); 1513ca08ab68Smrg while (l && (lang = FcStrListNext (l))) 1514ca08ab68Smrg { 1515ca08ab68Smrg v.type = FcTypeString; 1516ca08ab68Smrg v.u.s = lang; 1517ca08ab68Smrg FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1518ca08ab68Smrg } 1519ca08ab68Smrg FcStrListDone (l); 1520ca08ab68Smrg } 1521c9710b42Smrg if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) 1522c9710b42Smrg { 1523c9710b42Smrg FcChar8 *prgname = FcGetPrgname (); 1524c9710b42Smrg if (prgname) 1525c9710b42Smrg FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); 1526c9710b42Smrg } 15272c393a42Smrg break; 15282c393a42Smrg case FcMatchFont: 15292c393a42Smrg s = config->substFont; 15302c393a42Smrg break; 15312c393a42Smrg case FcMatchScan: 15322c393a42Smrg s = config->substScan; 15332c393a42Smrg break; 15342c393a42Smrg default: 15352c393a42Smrg return FcFalse; 15362c393a42Smrg } 15372c393a42Smrg 15382c393a42Smrg st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); 15392c393a42Smrg if (!st && config->maxObjects) 15402c393a42Smrg return FcFalse; 15412c393a42Smrg 15422c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15432c393a42Smrg { 15442c393a42Smrg printf ("FcConfigSubstitute "); 15452c393a42Smrg FcPatternPrint (p); 15462c393a42Smrg } 15472c393a42Smrg for (; s; s = s->next) 15482c393a42Smrg { 15492c393a42Smrg /* 15502c393a42Smrg * Check the tests to see if 15512c393a42Smrg * they all match the pattern 15522c393a42Smrg */ 15532c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 15542c393a42Smrg { 15552c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15562c393a42Smrg { 15572c393a42Smrg printf ("FcConfigSubstitute test "); 15582c393a42Smrg FcTestPrint (t); 15592c393a42Smrg } 15602c393a42Smrg st[i].elt = 0; 15612c393a42Smrg if (kind == FcMatchFont && t->kind == FcMatchPattern) 15622c393a42Smrg m = p_pat; 15632c393a42Smrg else 15642c393a42Smrg m = p; 15652c393a42Smrg if (m) 15662c393a42Smrg st[i].elt = FcPatternObjectFindElt (m, t->object); 15672c393a42Smrg else 15682c393a42Smrg st[i].elt = 0; 15692c393a42Smrg /* 15702c393a42Smrg * If there's no such field in the font, 15712c393a42Smrg * then FcQualAll matches while FcQualAny does not 15722c393a42Smrg */ 15732c393a42Smrg if (!st[i].elt) 15742c393a42Smrg { 15752c393a42Smrg if (t->qual == FcQualAll) 15762c393a42Smrg { 15772c393a42Smrg st[i].value = 0; 15782c393a42Smrg continue; 15792c393a42Smrg } 15802c393a42Smrg else 15812c393a42Smrg break; 15822c393a42Smrg } 15832c393a42Smrg /* 15842c393a42Smrg * Check to see if there is a match, mark the location 15852c393a42Smrg * to apply match-relative edits 15862c393a42Smrg */ 1587c9710b42Smrg st[i].value = FcConfigMatchValueList (m, p_pat, kind, t, st[i].elt->values); 15882c393a42Smrg if (!st[i].value) 15892c393a42Smrg break; 15902c393a42Smrg if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) 15912c393a42Smrg break; 15922c393a42Smrg if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) 15932c393a42Smrg break; 15942c393a42Smrg } 15952c393a42Smrg if (t) 15962c393a42Smrg { 15972c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15982c393a42Smrg printf ("No match\n"); 15992c393a42Smrg continue; 16002c393a42Smrg } 16012c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 16022c393a42Smrg { 16032c393a42Smrg printf ("Substitute "); 16042c393a42Smrg FcSubstPrint (s); 16052c393a42Smrg } 16062c393a42Smrg for (e = s->edit; e; e = e->next) 16072c393a42Smrg { 16082c393a42Smrg /* 16092c393a42Smrg * Evaluate the list of expressions 16102c393a42Smrg */ 1611c9710b42Smrg l = FcConfigValues (p, p_pat,kind, e->expr, e->binding); 16122c393a42Smrg /* 16132c393a42Smrg * Locate any test associated with this field, skipping 16142c393a42Smrg * tests associated with the pattern when substituting in 16152c393a42Smrg * the font 16162c393a42Smrg */ 16172c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 16182c393a42Smrg { 16192c393a42Smrg if ((t->kind == FcMatchFont || kind == FcMatchPattern) && 16202c393a42Smrg t->object == e->object) 16212c393a42Smrg { 1622ca08ab68Smrg /* 16232c393a42Smrg * KLUDGE - the pattern may have been reallocated or 16242c393a42Smrg * things may have been inserted or deleted above 16252c393a42Smrg * this element by other edits. Go back and find 16262c393a42Smrg * the element again 16272c393a42Smrg */ 16282c393a42Smrg if (e != s->edit && st[i].elt) 16292c393a42Smrg st[i].elt = FcPatternObjectFindElt (p, t->object); 16302c393a42Smrg if (!st[i].elt) 16312c393a42Smrg t = 0; 16322c393a42Smrg break; 16332c393a42Smrg } 16342c393a42Smrg } 1635ca08ab68Smrg switch (FC_OP_GET_OP (e->op)) { 16362c393a42Smrg case FcOpAssign: 16372c393a42Smrg /* 16382c393a42Smrg * If there was a test, then replace the matched 16392c393a42Smrg * value with the new list of values 16402c393a42Smrg */ 16412c393a42Smrg if (t) 16422c393a42Smrg { 16432c393a42Smrg FcValueList *thisValue = st[i].value; 16442c393a42Smrg FcValueList *nextValue = thisValue; 1645ca08ab68Smrg 16462c393a42Smrg /* 16472c393a42Smrg * Append the new list of values after the current value 16482c393a42Smrg */ 1649c9710b42Smrg FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l, e->object); 16502c393a42Smrg /* 16512c393a42Smrg * Delete the marked value 16522c393a42Smrg */ 16532c393a42Smrg if (thisValue) 16542c393a42Smrg FcConfigDel (&st[i].elt->values, thisValue); 16552c393a42Smrg /* 16562c393a42Smrg * Adjust any pointers into the value list to ensure 16572c393a42Smrg * future edits occur at the same place 16582c393a42Smrg */ 16592c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 16602c393a42Smrg { 16612c393a42Smrg if (st[i].value == thisValue) 16622c393a42Smrg st[i].value = nextValue; 16632c393a42Smrg } 16642c393a42Smrg break; 16652c393a42Smrg } 16662c393a42Smrg /* fall through ... */ 16672c393a42Smrg case FcOpAssignReplace: 16682c393a42Smrg /* 16692c393a42Smrg * Delete all of the values and insert 16702c393a42Smrg * the new set 16712c393a42Smrg */ 16722c393a42Smrg FcConfigPatternDel (p, e->object); 16732c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcTrue); 16742c393a42Smrg /* 16752c393a42Smrg * Adjust any pointers into the value list as they no 16762c393a42Smrg * longer point to anything valid 16772c393a42Smrg */ 16782c393a42Smrg if (t) 16792c393a42Smrg { 16802c393a42Smrg FcPatternElt *thisElt = st[i].elt; 16812c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 16822c393a42Smrg { 16832c393a42Smrg if (st[i].elt == thisElt) 16842c393a42Smrg st[i].value = 0; 16852c393a42Smrg } 16862c393a42Smrg } 16872c393a42Smrg break; 16882c393a42Smrg case FcOpPrepend: 16892c393a42Smrg if (t) 16902c393a42Smrg { 1691c9710b42Smrg FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l, e->object); 16922c393a42Smrg break; 16932c393a42Smrg } 16942c393a42Smrg /* fall through ... */ 16952c393a42Smrg case FcOpPrependFirst: 16962c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcFalse); 16972c393a42Smrg break; 16982c393a42Smrg case FcOpAppend: 16992c393a42Smrg if (t) 17002c393a42Smrg { 1701c9710b42Smrg FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l, e->object); 17022c393a42Smrg break; 17032c393a42Smrg } 17042c393a42Smrg /* fall through ... */ 17052c393a42Smrg case FcOpAppendLast: 17062c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcTrue); 17072c393a42Smrg break; 1708c9710b42Smrg case FcOpDelete: 1709c9710b42Smrg if (t) 1710c9710b42Smrg { 1711c9710b42Smrg FcConfigDel (&st[i].elt->values, st[i].value); 1712c9710b42Smrg break; 1713c9710b42Smrg } 1714c9710b42Smrg /* fall through ... */ 1715c9710b42Smrg case FcOpDeleteAll: 1716c9710b42Smrg FcConfigPatternDel (p, e->object); 1717c9710b42Smrg break; 17182c393a42Smrg default: 17192c393a42Smrg FcValueListDestroy (l); 17202c393a42Smrg break; 17212c393a42Smrg } 17222c393a42Smrg } 17232c393a42Smrg /* 17242c393a42Smrg * Now go through the pattern and eliminate 17252c393a42Smrg * any properties without data 17262c393a42Smrg */ 17272c393a42Smrg for (e = s->edit; e; e = e->next) 17282c393a42Smrg FcConfigPatternCanon (p, e->object); 17292c393a42Smrg 17302c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 17312c393a42Smrg { 17322c393a42Smrg printf ("FcConfigSubstitute edit"); 17332c393a42Smrg FcPatternPrint (p); 17342c393a42Smrg } 17352c393a42Smrg } 17362c393a42Smrg free (st); 17372c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 17382c393a42Smrg { 17392c393a42Smrg printf ("FcConfigSubstitute done"); 17402c393a42Smrg FcPatternPrint (p); 17412c393a42Smrg } 17422c393a42Smrg return FcTrue; 17432c393a42Smrg} 17442c393a42Smrg 17452c393a42SmrgFcBool 17462c393a42SmrgFcConfigSubstitute (FcConfig *config, 17472c393a42Smrg FcPattern *p, 17482c393a42Smrg FcMatchKind kind) 17492c393a42Smrg{ 17502c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 17512c393a42Smrg} 17522c393a42Smrg 17532c393a42Smrg#if defined (_WIN32) 17542c393a42Smrg 1755c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ 17562c393a42Smrg 17572c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 17582c393a42Smrg 1759c9710b42SmrgBOOL WINAPI 1760c9710b42SmrgDllMain (HINSTANCE hinstDLL, 1761c9710b42Smrg DWORD fdwReason, 1762c9710b42Smrg LPVOID lpvReserved); 1763c9710b42Smrg 17642c393a42SmrgBOOL WINAPI 17652c393a42SmrgDllMain (HINSTANCE hinstDLL, 17662c393a42Smrg DWORD fdwReason, 17672c393a42Smrg LPVOID lpvReserved) 17682c393a42Smrg{ 17692c393a42Smrg FcChar8 *p; 17702c393a42Smrg 17712c393a42Smrg switch (fdwReason) { 17722c393a42Smrg case DLL_PROCESS_ATTACH: 1773ca08ab68Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 17742c393a42Smrg sizeof (fontconfig_path))) 17752c393a42Smrg break; 17762c393a42Smrg 17772c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 17782c393a42Smrg * assume it's a Unix-style installation tree, and use 17792c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 17802c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 17812c393a42Smrg */ 1782ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 17832c393a42Smrg if (p) 17842c393a42Smrg { 17852c393a42Smrg *p = '\0'; 1786ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1787ca08ab68Smrg if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1788ca08ab68Smrg FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 17892c393a42Smrg *p = '\0'; 1790ca08ab68Smrg strcat ((char *) fontconfig_path, "\\etc\\fonts"); 17912c393a42Smrg } 17922c393a42Smrg else 17932c393a42Smrg fontconfig_path[0] = '\0'; 1794ca08ab68Smrg 17952c393a42Smrg break; 17962c393a42Smrg } 17972c393a42Smrg 17982c393a42Smrg return TRUE; 17992c393a42Smrg} 18002c393a42Smrg 18012c393a42Smrg# endif /* !PIC */ 18022c393a42Smrg 18032c393a42Smrg#undef FONTCONFIG_PATH 18042c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 18052c393a42Smrg 18062c393a42Smrg#endif /* !_WIN32 */ 18072c393a42Smrg 18082c393a42Smrg#ifndef FONTCONFIG_FILE 18092c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 18102c393a42Smrg#endif 18112c393a42Smrg 18122c393a42Smrgstatic FcChar8 * 18132c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 18142c393a42Smrg{ 18152c393a42Smrg FcChar8 *path; 1816ca08ab68Smrg int size, osize; 18172c393a42Smrg 18182c393a42Smrg if (!dir) 18192c393a42Smrg dir = (FcChar8 *) ""; 1820ca08ab68Smrg 1821ca08ab68Smrg osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1822ca08ab68Smrg /* 1823ca08ab68Smrg * workaround valgrind warning because glibc takes advantage of how it knows memory is 1824ca08ab68Smrg * allocated to implement strlen by reading in groups of 4 1825ca08ab68Smrg */ 1826ca08ab68Smrg size = (osize + 3) & ~3; 1827ca08ab68Smrg 1828ca08ab68Smrg path = malloc (size); 18292c393a42Smrg if (!path) 18302c393a42Smrg return 0; 18312c393a42Smrg 18322c393a42Smrg strcpy ((char *) path, (const char *) dir); 18332c393a42Smrg /* make sure there's a single separator */ 18342c393a42Smrg#ifdef _WIN32 18352c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 18362c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 18372c393a42Smrg !(file[0] == '/' || 18382c393a42Smrg file[0] == '\\' || 18392c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 18402c393a42Smrg strcat ((char *) path, "\\"); 18412c393a42Smrg#else 18422c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 18432c393a42Smrg strcat ((char *) path, "/"); 1844c9710b42Smrg else 1845c9710b42Smrg osize--; 18462c393a42Smrg#endif 18472c393a42Smrg strcat ((char *) path, (char *) file); 18482c393a42Smrg 18492c393a42Smrg if (access ((char *) path, R_OK) == 0) 18502c393a42Smrg return path; 1851ca08ab68Smrg 18522c393a42Smrg FcStrFree (path); 1853ca08ab68Smrg 18542c393a42Smrg return 0; 18552c393a42Smrg} 18562c393a42Smrg 18572c393a42Smrgstatic FcChar8 ** 18582c393a42SmrgFcConfigGetPath (void) 18592c393a42Smrg{ 18602c393a42Smrg FcChar8 **path; 18612c393a42Smrg FcChar8 *env, *e, *colon; 18622c393a42Smrg FcChar8 *dir; 18632c393a42Smrg int npath; 18642c393a42Smrg int i; 18652c393a42Smrg 18662c393a42Smrg npath = 2; /* default dir + null */ 18672c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 18682c393a42Smrg if (env) 18692c393a42Smrg { 18702c393a42Smrg e = env; 18712c393a42Smrg npath++; 18722c393a42Smrg while (*e) 18732c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 18742c393a42Smrg npath++; 18752c393a42Smrg } 18762c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 18772c393a42Smrg if (!path) 18782c393a42Smrg goto bail0; 18792c393a42Smrg i = 0; 18802c393a42Smrg 18812c393a42Smrg if (env) 18822c393a42Smrg { 18832c393a42Smrg e = env; 1884ca08ab68Smrg while (*e) 18852c393a42Smrg { 18862c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 18872c393a42Smrg if (!colon) 18882c393a42Smrg colon = e + strlen ((char *) e); 18892c393a42Smrg path[i] = malloc (colon - e + 1); 18902c393a42Smrg if (!path[i]) 18912c393a42Smrg goto bail1; 18922c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 18932c393a42Smrg path[i][colon - e] = '\0'; 18942c393a42Smrg if (*colon) 18952c393a42Smrg e = colon + 1; 18962c393a42Smrg else 18972c393a42Smrg e = colon; 18982c393a42Smrg i++; 18992c393a42Smrg } 19002c393a42Smrg } 1901ca08ab68Smrg 19022c393a42Smrg#ifdef _WIN32 19032c393a42Smrg if (fontconfig_path[0] == '\0') 19042c393a42Smrg { 1905a6844aabSmrg char *p; 1906ca08ab68Smrg if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 19072c393a42Smrg goto bail1; 1908ca08ab68Smrg p = strrchr ((const char *) fontconfig_path, '\\'); 19092c393a42Smrg if (p) *p = '\0'; 1910ca08ab68Smrg strcat ((char *) fontconfig_path, "\\fonts"); 19112c393a42Smrg } 19122c393a42Smrg#endif 19132c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 19142c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 19152c393a42Smrg if (!path[i]) 19162c393a42Smrg goto bail1; 19172c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 19182c393a42Smrg return path; 19192c393a42Smrg 19202c393a42Smrgbail1: 19212c393a42Smrg for (i = 0; path[i]; i++) 19222c393a42Smrg free (path[i]); 19232c393a42Smrg free (path); 19242c393a42Smrgbail0: 19252c393a42Smrg return 0; 19262c393a42Smrg} 19272c393a42Smrg 19282c393a42Smrgstatic void 19292c393a42SmrgFcConfigFreePath (FcChar8 **path) 19302c393a42Smrg{ 19312c393a42Smrg FcChar8 **p; 19322c393a42Smrg 19332c393a42Smrg for (p = path; *p; p++) 19342c393a42Smrg free (*p); 19352c393a42Smrg free (path); 19362c393a42Smrg} 19372c393a42Smrg 1938c9710b42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */ 19392c393a42Smrg 19402c393a42SmrgFcChar8 * 19412c393a42SmrgFcConfigHome (void) 19422c393a42Smrg{ 19432c393a42Smrg if (_FcConfigHomeEnabled) 19442c393a42Smrg { 19452c393a42Smrg char *home = getenv ("HOME"); 19462c393a42Smrg 19472c393a42Smrg#ifdef _WIN32 19482c393a42Smrg if (home == NULL) 19492c393a42Smrg home = getenv ("USERPROFILE"); 19502c393a42Smrg#endif 19512c393a42Smrg 19522c393a42Smrg return (FcChar8 *) home; 19532c393a42Smrg } 19542c393a42Smrg return 0; 19552c393a42Smrg} 19562c393a42Smrg 1957ca08ab68SmrgFcChar8 * 1958ca08ab68SmrgFcConfigXdgCacheHome (void) 1959ca08ab68Smrg{ 1960ca08ab68Smrg const char *env = getenv ("XDG_CACHE_HOME"); 1961ca08ab68Smrg FcChar8 *ret = NULL; 1962ca08ab68Smrg 1963ca08ab68Smrg if (env) 1964ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 1965ca08ab68Smrg else 1966ca08ab68Smrg { 1967ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 1968ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 1969ca08ab68Smrg 1970ca08ab68Smrg ret = malloc (len + 7 + 1); 1971ca08ab68Smrg if (ret) 1972ca08ab68Smrg { 1973ca08ab68Smrg memcpy (ret, home, len); 1974ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 1975ca08ab68Smrg ret[len + 7] = 0; 1976ca08ab68Smrg } 1977ca08ab68Smrg } 1978ca08ab68Smrg 1979ca08ab68Smrg return ret; 1980ca08ab68Smrg} 1981ca08ab68Smrg 1982ca08ab68SmrgFcChar8 * 1983ca08ab68SmrgFcConfigXdgConfigHome (void) 1984ca08ab68Smrg{ 1985ca08ab68Smrg const char *env = getenv ("XDG_CONFIG_HOME"); 1986ca08ab68Smrg FcChar8 *ret = NULL; 1987ca08ab68Smrg 1988ca08ab68Smrg if (env) 1989ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 1990ca08ab68Smrg else 1991ca08ab68Smrg { 1992ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 1993ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 1994ca08ab68Smrg 1995ca08ab68Smrg ret = malloc (len + 8 + 1); 1996ca08ab68Smrg if (ret) 1997ca08ab68Smrg { 1998ca08ab68Smrg memcpy (ret, home, len); 1999ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 2000ca08ab68Smrg ret[len + 8] = 0; 2001ca08ab68Smrg } 2002ca08ab68Smrg } 2003ca08ab68Smrg 2004ca08ab68Smrg return ret; 2005ca08ab68Smrg} 2006ca08ab68Smrg 2007ca08ab68SmrgFcChar8 * 2008ca08ab68SmrgFcConfigXdgDataHome (void) 2009ca08ab68Smrg{ 2010ca08ab68Smrg const char *env = getenv ("XDG_DATA_HOME"); 2011ca08ab68Smrg FcChar8 *ret = NULL; 2012ca08ab68Smrg 2013ca08ab68Smrg if (env) 2014ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2015ca08ab68Smrg else 2016ca08ab68Smrg { 2017ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2018ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2019ca08ab68Smrg 2020ca08ab68Smrg ret = malloc (len + 13 + 1); 2021ca08ab68Smrg if (ret) 2022ca08ab68Smrg { 2023ca08ab68Smrg memcpy (ret, home, len); 2024ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 2025ca08ab68Smrg ret[len + 13] = 0; 2026ca08ab68Smrg } 2027ca08ab68Smrg } 2028ca08ab68Smrg 2029ca08ab68Smrg return ret; 2030ca08ab68Smrg} 2031ca08ab68Smrg 20322c393a42SmrgFcBool 20332c393a42SmrgFcConfigEnableHome (FcBool enable) 20342c393a42Smrg{ 20352c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 20362c393a42Smrg _FcConfigHomeEnabled = enable; 20372c393a42Smrg return prev; 20382c393a42Smrg} 20392c393a42Smrg 20402c393a42SmrgFcChar8 * 20412c393a42SmrgFcConfigFilename (const FcChar8 *url) 20422c393a42Smrg{ 20432c393a42Smrg FcChar8 *file, *dir, **path, **p; 20442c393a42Smrg 20452c393a42Smrg if (!url || !*url) 20462c393a42Smrg { 20472c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 20482c393a42Smrg if (!url) 20492c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 20502c393a42Smrg } 20512c393a42Smrg file = 0; 20522c393a42Smrg 20532c393a42Smrg#ifdef _WIN32 20542c393a42Smrg if (isalpha (*url) && 20552c393a42Smrg url[1] == ':' && 20562c393a42Smrg (url[2] == '/' || url[2] == '\\')) 20572c393a42Smrg goto absolute_path; 20582c393a42Smrg#endif 20592c393a42Smrg 20602c393a42Smrg switch (*url) { 20612c393a42Smrg case '~': 20622c393a42Smrg dir = FcConfigHome (); 20632c393a42Smrg if (dir) 20642c393a42Smrg file = FcConfigFileExists (dir, url + 1); 20652c393a42Smrg else 20662c393a42Smrg file = 0; 20672c393a42Smrg break; 20682c393a42Smrg#ifdef _WIN32 20692c393a42Smrg case '\\': 20702c393a42Smrg absolute_path: 20712c393a42Smrg#endif 20722c393a42Smrg case '/': 20732c393a42Smrg file = FcConfigFileExists (0, url); 20742c393a42Smrg break; 20752c393a42Smrg default: 20762c393a42Smrg path = FcConfigGetPath (); 20772c393a42Smrg if (!path) 2078ca08ab68Smrg return NULL; 20792c393a42Smrg for (p = path; *p; p++) 20802c393a42Smrg { 20812c393a42Smrg file = FcConfigFileExists (*p, url); 20822c393a42Smrg if (file) 20832c393a42Smrg break; 20842c393a42Smrg } 20852c393a42Smrg FcConfigFreePath (path); 20862c393a42Smrg break; 20872c393a42Smrg } 2088ca08ab68Smrg 20892c393a42Smrg return file; 20902c393a42Smrg} 20912c393a42Smrg 20922c393a42Smrg/* 20932c393a42Smrg * Manage the application-specific fonts 20942c393a42Smrg */ 20952c393a42Smrg 20962c393a42SmrgFcBool 20972c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 20982c393a42Smrg const FcChar8 *file) 20992c393a42Smrg{ 21002c393a42Smrg FcFontSet *set; 21012c393a42Smrg FcStrSet *subdirs; 21022c393a42Smrg FcStrList *sublist; 21032c393a42Smrg FcChar8 *subdir; 21042c393a42Smrg 21052c393a42Smrg if (!config) 21062c393a42Smrg { 21072c393a42Smrg config = FcConfigGetCurrent (); 21082c393a42Smrg if (!config) 21092c393a42Smrg return FcFalse; 21102c393a42Smrg } 21112c393a42Smrg 21122c393a42Smrg subdirs = FcStrSetCreate (); 21132c393a42Smrg if (!subdirs) 21142c393a42Smrg return FcFalse; 2115ca08ab68Smrg 21162c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 21172c393a42Smrg if (!set) 21182c393a42Smrg { 21192c393a42Smrg set = FcFontSetCreate (); 21202c393a42Smrg if (!set) 21212c393a42Smrg { 21222c393a42Smrg FcStrSetDestroy (subdirs); 21232c393a42Smrg return FcFalse; 21242c393a42Smrg } 21252c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 21262c393a42Smrg } 21272c393a42Smrg 21282c393a42Smrg if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 21292c393a42Smrg { 21302c393a42Smrg FcStrSetDestroy (subdirs); 21312c393a42Smrg return FcFalse; 21322c393a42Smrg } 21332c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 21342c393a42Smrg { 21352c393a42Smrg while ((subdir = FcStrListNext (sublist))) 21362c393a42Smrg { 21372c393a42Smrg FcConfigAppFontAddDir (config, subdir); 21382c393a42Smrg } 21392c393a42Smrg FcStrListDone (sublist); 21402c393a42Smrg } 21412c393a42Smrg FcStrSetDestroy (subdirs); 21422c393a42Smrg return FcTrue; 21432c393a42Smrg} 21442c393a42Smrg 21452c393a42SmrgFcBool 21462c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 21472c393a42Smrg const FcChar8 *dir) 21482c393a42Smrg{ 21492c393a42Smrg FcFontSet *set; 21502c393a42Smrg FcStrSet *dirs; 2151ca08ab68Smrg 21522c393a42Smrg if (!config) 21532c393a42Smrg { 21542c393a42Smrg config = FcConfigGetCurrent (); 21552c393a42Smrg if (!config) 21562c393a42Smrg return FcFalse; 21572c393a42Smrg } 21582c393a42Smrg 21592c393a42Smrg dirs = FcStrSetCreate (); 21602c393a42Smrg if (!dirs) 21612c393a42Smrg return FcFalse; 2162ca08ab68Smrg 21632c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 21642c393a42Smrg if (!set) 21652c393a42Smrg { 21662c393a42Smrg set = FcFontSetCreate (); 21672c393a42Smrg if (!set) 21682c393a42Smrg { 21692c393a42Smrg FcStrSetDestroy (dirs); 21702c393a42Smrg return FcFalse; 21712c393a42Smrg } 21722c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 21732c393a42Smrg } 2174ca08ab68Smrg 21752c393a42Smrg FcStrSetAddFilename (dirs, dir); 2176ca08ab68Smrg 21772c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 21782c393a42Smrg { 21792c393a42Smrg FcStrSetDestroy (dirs); 21802c393a42Smrg return FcFalse; 21812c393a42Smrg } 21822c393a42Smrg FcStrSetDestroy (dirs); 21832c393a42Smrg return FcTrue; 21842c393a42Smrg} 21852c393a42Smrg 21862c393a42Smrgvoid 21872c393a42SmrgFcConfigAppFontClear (FcConfig *config) 21882c393a42Smrg{ 21892c393a42Smrg if (!config) 21902c393a42Smrg { 21912c393a42Smrg config = FcConfigGetCurrent (); 21922c393a42Smrg if (!config) 21932c393a42Smrg return; 21942c393a42Smrg } 21952c393a42Smrg 21962c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 21972c393a42Smrg} 21982c393a42Smrg 21992c393a42Smrg/* 22002c393a42Smrg * Manage filename-based font source selectors 22012c393a42Smrg */ 22022c393a42Smrg 22032c393a42SmrgFcBool 22042c393a42SmrgFcConfigGlobAdd (FcConfig *config, 22052c393a42Smrg const FcChar8 *glob, 22062c393a42Smrg FcBool accept) 22072c393a42Smrg{ 22082c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 22092c393a42Smrg 22102c393a42Smrg return FcStrSetAdd (set, glob); 22112c393a42Smrg} 22122c393a42Smrg 22132c393a42Smrgstatic FcBool 22142c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 22152c393a42Smrg const FcChar8 *string) 22162c393a42Smrg{ 22172c393a42Smrg int i; 22182c393a42Smrg 22192c393a42Smrg for (i = 0; i < globs->num; i++) 2220c9710b42Smrg if (FcStrGlobMatch (globs->strs[i], string)) 22212c393a42Smrg return FcTrue; 22222c393a42Smrg return FcFalse; 22232c393a42Smrg} 22242c393a42Smrg 22252c393a42SmrgFcBool 22262c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 22272c393a42Smrg const FcChar8 *filename) 22282c393a42Smrg{ 22292c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 22302c393a42Smrg return FcTrue; 22312c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 22322c393a42Smrg return FcFalse; 22332c393a42Smrg return FcTrue; 22342c393a42Smrg} 22352c393a42Smrg 22362c393a42Smrg/* 22372c393a42Smrg * Manage font-pattern based font source selectors 22382c393a42Smrg */ 22392c393a42Smrg 22402c393a42SmrgFcBool 22412c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 22422c393a42Smrg FcPattern *pattern, 22432c393a42Smrg FcBool accept) 22442c393a42Smrg{ 22452c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 22462c393a42Smrg 22472c393a42Smrg return FcFontSetAdd (set, pattern); 22482c393a42Smrg} 22492c393a42Smrg 22502c393a42Smrgstatic FcBool 22512c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 22522c393a42Smrg const FcPattern *font) 22532c393a42Smrg{ 22542c393a42Smrg int i; 2255ca08ab68Smrg 22562c393a42Smrg for (i = 0; i < patterns->nfont; i++) 22572c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 22582c393a42Smrg return FcTrue; 22592c393a42Smrg return FcFalse; 22602c393a42Smrg} 22612c393a42Smrg 22622c393a42SmrgFcBool 22632c393a42SmrgFcConfigAcceptFont (FcConfig *config, 22642c393a42Smrg const FcPattern *font) 22652c393a42Smrg{ 22662c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 22672c393a42Smrg return FcTrue; 22682c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 22692c393a42Smrg return FcFalse; 22702c393a42Smrg return FcTrue; 22712c393a42Smrg} 2272c9710b42Smrg 2273c9710b42Smrgconst FcChar8 * 2274c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config) 2275c9710b42Smrg{ 2276c9710b42Smrg if (!config) 2277c9710b42Smrg { 2278c9710b42Smrg config = FcConfigGetCurrent (); 2279c9710b42Smrg if (!config) 2280c9710b42Smrg return NULL; 2281c9710b42Smrg } 2282c9710b42Smrg 2283c9710b42Smrg return config->sysRoot; 2284c9710b42Smrg} 2285c9710b42Smrg 2286c9710b42Smrgvoid 2287c9710b42SmrgFcConfigSetSysRoot (FcConfig *config, 2288c9710b42Smrg const FcChar8 *sysroot) 2289c9710b42Smrg{ 2290c9710b42Smrg FcChar8 *s; 2291c9710b42Smrg FcBool init = FcFalse; 2292c9710b42Smrg 2293c9710b42Smrg if (!config) 2294c9710b42Smrg { 2295c9710b42Smrg /* We can't use FcConfigGetCurrent() here to ensure 2296c9710b42Smrg * the sysroot is set prior to initialize FcConfig, 2297c9710b42Smrg * to avoid loading caches from non-sysroot dirs. 2298c9710b42Smrg * So postpone the initialization later. 2299c9710b42Smrg */ 2300c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 2301c9710b42Smrg if (!config) 2302c9710b42Smrg { 2303c9710b42Smrg config = FcConfigCreate (); 2304c9710b42Smrg if (!config) 2305c9710b42Smrg return; 2306c9710b42Smrg init = FcTrue; 2307c9710b42Smrg } 2308c9710b42Smrg } 2309c9710b42Smrg 2310c9710b42Smrg s = FcStrCopyFilename (sysroot); 2311c9710b42Smrg if (!s) 2312c9710b42Smrg return; 2313c9710b42Smrg 2314c9710b42Smrg if (config->sysRoot) 2315c9710b42Smrg FcStrFree (config->sysRoot); 2316c9710b42Smrg 2317c9710b42Smrg config->sysRoot = s; 2318c9710b42Smrg if (init) 2319c9710b42Smrg { 2320c9710b42Smrg config = FcInitLoadOwnConfigAndFonts (config); 2321c9710b42Smrg FcConfigSetCurrent (config); 2322c9710b42Smrg } 2323c9710b42Smrg} 2324c9710b42Smrg 23252c393a42Smrg#define __fccfg__ 23262c393a42Smrg#include "fcaliastail.h" 23272c393a42Smrg#undef __fccfg__ 2328