fccfg.c revision 2c393a42
12c393a42Smrg/* 22c393a42Smrg * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $ 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 102c393a42Smrg * documentation, and that the name of Keith Packard not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 122c393a42Smrg * specific, written prior permission. Keith Packard makes no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 162c393a42Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 182c393a42Smrg * EVENT SHALL KEITH PACKARD 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 252c393a42Smrg#include "fcint.h" 262c393a42Smrg#include <dirent.h> 272c393a42Smrg#include <sys/types.h> 282c393a42Smrg 292c393a42Smrg#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT)) 302c393a42Smrg#define STRICT 312c393a42Smrg#include <windows.h> 322c393a42Smrg#undef STRICT 332c393a42Smrg#endif 342c393a42Smrg 352c393a42Smrg#if defined (_WIN32) && !defined (R_OK) 362c393a42Smrg#define R_OK 4 372c393a42Smrg#endif 382c393a42Smrg 392c393a42SmrgFcConfig *_fcConfig; 402c393a42Smrg 412c393a42SmrgFcConfig * 422c393a42SmrgFcConfigCreate (void) 432c393a42Smrg{ 442c393a42Smrg FcSetName set; 452c393a42Smrg FcConfig *config; 462c393a42Smrg 472c393a42Smrg config = malloc (sizeof (FcConfig)); 482c393a42Smrg if (!config) 492c393a42Smrg goto bail0; 502c393a42Smrg FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig)); 512c393a42Smrg 522c393a42Smrg config->configDirs = FcStrSetCreate (); 532c393a42Smrg if (!config->configDirs) 542c393a42Smrg goto bail1; 552c393a42Smrg 562c393a42Smrg config->configFiles = FcStrSetCreate (); 572c393a42Smrg if (!config->configFiles) 582c393a42Smrg goto bail2; 592c393a42Smrg 602c393a42Smrg config->fontDirs = FcStrSetCreate (); 612c393a42Smrg if (!config->fontDirs) 622c393a42Smrg goto bail3; 632c393a42Smrg 642c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 652c393a42Smrg if (!config->acceptGlobs) 662c393a42Smrg goto bail4; 672c393a42Smrg 682c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 692c393a42Smrg if (!config->rejectGlobs) 702c393a42Smrg goto bail5; 712c393a42Smrg 722c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 732c393a42Smrg if (!config->acceptPatterns) 742c393a42Smrg goto bail6; 752c393a42Smrg 762c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 772c393a42Smrg if (!config->rejectPatterns) 782c393a42Smrg goto bail7; 792c393a42Smrg 802c393a42Smrg config->cacheDirs = FcStrSetCreate (); 812c393a42Smrg if (!config->cacheDirs) 822c393a42Smrg goto bail8; 832c393a42Smrg 842c393a42Smrg config->blanks = 0; 852c393a42Smrg 862c393a42Smrg config->substPattern = 0; 872c393a42Smrg config->substFont = 0; 882c393a42Smrg config->substScan = 0; 892c393a42Smrg config->maxObjects = 0; 902c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 912c393a42Smrg config->fonts[set] = 0; 922c393a42Smrg 932c393a42Smrg config->rescanTime = time(0); 942c393a42Smrg config->rescanInterval = 30; 952c393a42Smrg 962c393a42Smrg return config; 972c393a42Smrg 982c393a42Smrgbail8: 992c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 1002c393a42Smrgbail7: 1012c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 1022c393a42Smrgbail6: 1032c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 1042c393a42Smrgbail5: 1052c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 1062c393a42Smrgbail4: 1072c393a42Smrg FcStrSetDestroy (config->fontDirs); 1082c393a42Smrgbail3: 1092c393a42Smrg FcStrSetDestroy (config->configFiles); 1102c393a42Smrgbail2: 1112c393a42Smrg FcStrSetDestroy (config->configDirs); 1122c393a42Smrgbail1: 1132c393a42Smrg free (config); 1142c393a42Smrg FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); 1152c393a42Smrgbail0: 1162c393a42Smrg return 0; 1172c393a42Smrg} 1182c393a42Smrg 1192c393a42Smrgstatic FcFileTime 1202c393a42SmrgFcConfigNewestFile (FcStrSet *files) 1212c393a42Smrg{ 1222c393a42Smrg FcStrList *list = FcStrListCreate (files); 1232c393a42Smrg FcFileTime newest = { 0, FcFalse }; 1242c393a42Smrg FcChar8 *file; 1252c393a42Smrg struct stat statb; 1262c393a42Smrg 1272c393a42Smrg if (list) 1282c393a42Smrg { 1292c393a42Smrg while ((file = FcStrListNext (list))) 1302c393a42Smrg if (stat ((char *) file, &statb) == 0) 1312c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 1322c393a42Smrg { 1332c393a42Smrg newest.set = FcTrue; 1342c393a42Smrg newest.time = statb.st_mtime; 1352c393a42Smrg } 1362c393a42Smrg FcStrListDone (list); 1372c393a42Smrg } 1382c393a42Smrg return newest; 1392c393a42Smrg} 1402c393a42Smrg 1412c393a42SmrgFcBool 1422c393a42SmrgFcConfigUptoDate (FcConfig *config) 1432c393a42Smrg{ 1442c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 1452c393a42Smrg time_t now = time(0); 1462c393a42Smrg if (!config) 1472c393a42Smrg { 1482c393a42Smrg config = FcConfigGetCurrent (); 1492c393a42Smrg if (!config) 1502c393a42Smrg return FcFalse; 1512c393a42Smrg } 1522c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 1532c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 1542c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 1552c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 1562c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 1572c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 1582c393a42Smrg { 1592c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 1602c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 1612c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 1622c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 1632c393a42Smrg { 1642c393a42Smrg fprintf (stderr, 1652c393a42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n"); 1662c393a42Smrg config->rescanTime = now; 1672c393a42Smrg return FcTrue; 1682c393a42Smrg } 1692c393a42Smrg else 1702c393a42Smrg return FcFalse; 1712c393a42Smrg } 1722c393a42Smrg config->rescanTime = now; 1732c393a42Smrg return FcTrue; 1742c393a42Smrg} 1752c393a42Smrg 1762c393a42Smrgstatic void 1772c393a42SmrgFcSubstDestroy (FcSubst *s) 1782c393a42Smrg{ 1792c393a42Smrg FcSubst *n; 1802c393a42Smrg 1812c393a42Smrg while (s) 1822c393a42Smrg { 1832c393a42Smrg n = s->next; 1842c393a42Smrg if (s->test) 1852c393a42Smrg FcTestDestroy (s->test); 1862c393a42Smrg if (s->edit) 1872c393a42Smrg FcEditDestroy (s->edit); 1882c393a42Smrg free (s); 1892c393a42Smrg FcMemFree (FC_MEM_SUBST, sizeof (FcSubst)); 1902c393a42Smrg s = n; 1912c393a42Smrg } 1922c393a42Smrg} 1932c393a42Smrg 1942c393a42Smrgvoid 1952c393a42SmrgFcConfigDestroy (FcConfig *config) 1962c393a42Smrg{ 1972c393a42Smrg FcSetName set; 1982c393a42Smrg 1992c393a42Smrg if (config == _fcConfig) 2002c393a42Smrg _fcConfig = 0; 2012c393a42Smrg 2022c393a42Smrg FcStrSetDestroy (config->configDirs); 2032c393a42Smrg FcStrSetDestroy (config->fontDirs); 2042c393a42Smrg FcStrSetDestroy (config->cacheDirs); 2052c393a42Smrg FcStrSetDestroy (config->configFiles); 2062c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 2072c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 2082c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 2092c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 2102c393a42Smrg 2112c393a42Smrg if (config->blanks) 2122c393a42Smrg FcBlanksDestroy (config->blanks); 2132c393a42Smrg 2142c393a42Smrg FcSubstDestroy (config->substPattern); 2152c393a42Smrg FcSubstDestroy (config->substFont); 2162c393a42Smrg FcSubstDestroy (config->substScan); 2172c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 2182c393a42Smrg if (config->fonts[set]) 2192c393a42Smrg FcFontSetDestroy (config->fonts[set]); 2202c393a42Smrg 2212c393a42Smrg free (config); 2222c393a42Smrg FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); 2232c393a42Smrg} 2242c393a42Smrg 2252c393a42Smrg/* 2262c393a42Smrg * Add cache to configuration, adding fonts and directories 2272c393a42Smrg */ 2282c393a42Smrg 2292c393a42SmrgFcBool 2302c393a42SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 2312c393a42Smrg FcSetName set, FcStrSet *dirSet) 2322c393a42Smrg{ 2332c393a42Smrg FcFontSet *fs; 2342c393a42Smrg intptr_t *dirs; 2352c393a42Smrg int i; 2362c393a42Smrg 2372c393a42Smrg /* 2382c393a42Smrg * Add fonts 2392c393a42Smrg */ 2402c393a42Smrg fs = FcCacheSet (cache); 2412c393a42Smrg if (fs) 2422c393a42Smrg { 2432c393a42Smrg int nref = 0; 2442c393a42Smrg 2452c393a42Smrg for (i = 0; i < fs->nfont; i++) 2462c393a42Smrg { 2472c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 2482c393a42Smrg FcChar8 *font_file; 2492c393a42Smrg 2502c393a42Smrg /* 2512c393a42Smrg * Check to see if font is banned by filename 2522c393a42Smrg */ 2532c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 2542c393a42Smrg 0, &font_file) == FcResultMatch && 2552c393a42Smrg !FcConfigAcceptFilename (config, font_file)) 2562c393a42Smrg { 2572c393a42Smrg continue; 2582c393a42Smrg } 2592c393a42Smrg 2602c393a42Smrg /* 2612c393a42Smrg * Check to see if font is banned by pattern 2622c393a42Smrg */ 2632c393a42Smrg if (!FcConfigAcceptFont (config, font)) 2642c393a42Smrg continue; 2652c393a42Smrg 2662c393a42Smrg nref++; 2672c393a42Smrg FcFontSetAdd (config->fonts[set], font); 2682c393a42Smrg } 2692c393a42Smrg FcDirCacheReference (cache, nref); 2702c393a42Smrg } 2712c393a42Smrg 2722c393a42Smrg /* 2732c393a42Smrg * Add directories 2742c393a42Smrg */ 2752c393a42Smrg dirs = FcCacheDirs (cache); 2762c393a42Smrg if (dirs) 2772c393a42Smrg { 2782c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 2792c393a42Smrg { 2802c393a42Smrg FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); 2812c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 2822c393a42Smrg FcStrSetAddFilename (dirSet, dir); 2832c393a42Smrg } 2842c393a42Smrg } 2852c393a42Smrg return FcTrue; 2862c393a42Smrg} 2872c393a42Smrg 2882c393a42Smrgstatic FcBool 2892c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 2902c393a42Smrg{ 2912c393a42Smrg FcStrList *dirlist; 2922c393a42Smrg FcChar8 *dir; 2932c393a42Smrg FcCache *cache; 2942c393a42Smrg 2952c393a42Smrg dirlist = FcStrListCreate (dirSet); 2962c393a42Smrg if (!dirlist) 2972c393a42Smrg return FcFalse; 2982c393a42Smrg 2992c393a42Smrg while ((dir = FcStrListNext (dirlist))) 3002c393a42Smrg { 3012c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 3022c393a42Smrg printf ("adding fonts from%s\n", dir); 3032c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 3042c393a42Smrg if (!cache) 3052c393a42Smrg continue; 3062c393a42Smrg FcConfigAddCache (config, cache, set, dirSet); 3072c393a42Smrg FcDirCacheUnload (cache); 3082c393a42Smrg } 3092c393a42Smrg FcStrListDone (dirlist); 3102c393a42Smrg return FcTrue; 3112c393a42Smrg} 3122c393a42Smrg 3132c393a42Smrg/* 3142c393a42Smrg * Scan the current list of directories in the configuration 3152c393a42Smrg * and build the set of available fonts. 3162c393a42Smrg */ 3172c393a42Smrg 3182c393a42SmrgFcBool 3192c393a42SmrgFcConfigBuildFonts (FcConfig *config) 3202c393a42Smrg{ 3212c393a42Smrg FcFontSet *fonts; 3222c393a42Smrg 3232c393a42Smrg if (!config) 3242c393a42Smrg { 3252c393a42Smrg config = FcConfigGetCurrent (); 3262c393a42Smrg if (!config) 3272c393a42Smrg return FcFalse; 3282c393a42Smrg } 3292c393a42Smrg 3302c393a42Smrg fonts = FcFontSetCreate (); 3312c393a42Smrg if (!fonts) 3322c393a42Smrg return FcFalse; 3332c393a42Smrg 3342c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 3352c393a42Smrg 3362c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 3372c393a42Smrg return FcFalse; 3382c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 3392c393a42Smrg FcFontSetPrint (fonts); 3402c393a42Smrg return FcTrue; 3412c393a42Smrg} 3422c393a42Smrg 3432c393a42SmrgFcBool 3442c393a42SmrgFcConfigSetCurrent (FcConfig *config) 3452c393a42Smrg{ 3462c393a42Smrg if (config == _fcConfig) 3472c393a42Smrg return FcTrue; 3482c393a42Smrg 3492c393a42Smrg if (!config->fonts) 3502c393a42Smrg if (!FcConfigBuildFonts (config)) 3512c393a42Smrg return FcFalse; 3522c393a42Smrg 3532c393a42Smrg if (_fcConfig) 3542c393a42Smrg FcConfigDestroy (_fcConfig); 3552c393a42Smrg _fcConfig = config; 3562c393a42Smrg return FcTrue; 3572c393a42Smrg} 3582c393a42Smrg 3592c393a42SmrgFcConfig * 3602c393a42SmrgFcConfigGetCurrent (void) 3612c393a42Smrg{ 3622c393a42Smrg if (!_fcConfig) 3632c393a42Smrg if (!FcInit ()) 3642c393a42Smrg return 0; 3652c393a42Smrg return _fcConfig; 3662c393a42Smrg} 3672c393a42Smrg 3682c393a42SmrgFcBool 3692c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 3702c393a42Smrg const FcChar8 *d) 3712c393a42Smrg{ 3722c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 3732c393a42Smrg} 3742c393a42Smrg 3752c393a42SmrgFcStrList * 3762c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 3772c393a42Smrg{ 3782c393a42Smrg if (!config) 3792c393a42Smrg { 3802c393a42Smrg config = FcConfigGetCurrent (); 3812c393a42Smrg if (!config) 3822c393a42Smrg return 0; 3832c393a42Smrg } 3842c393a42Smrg return FcStrListCreate (config->configDirs); 3852c393a42Smrg} 3862c393a42Smrg 3872c393a42SmrgFcBool 3882c393a42SmrgFcConfigAddFontDir (FcConfig *config, 3892c393a42Smrg const FcChar8 *d) 3902c393a42Smrg{ 3912c393a42Smrg return FcStrSetAddFilename (config->fontDirs, d); 3922c393a42Smrg} 3932c393a42Smrg 3942c393a42SmrgFcBool 3952c393a42SmrgFcConfigAddDir (FcConfig *config, 3962c393a42Smrg const FcChar8 *d) 3972c393a42Smrg{ 3982c393a42Smrg return (FcConfigAddConfigDir (config, d) && 3992c393a42Smrg FcConfigAddFontDir (config, d)); 4002c393a42Smrg} 4012c393a42Smrg 4022c393a42SmrgFcStrList * 4032c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 4042c393a42Smrg{ 4052c393a42Smrg if (!config) 4062c393a42Smrg { 4072c393a42Smrg config = FcConfigGetCurrent (); 4082c393a42Smrg if (!config) 4092c393a42Smrg return 0; 4102c393a42Smrg } 4112c393a42Smrg return FcStrListCreate (config->fontDirs); 4122c393a42Smrg} 4132c393a42Smrg 4142c393a42SmrgFcBool 4152c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 4162c393a42Smrg const FcChar8 *d) 4172c393a42Smrg{ 4182c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 4192c393a42Smrg} 4202c393a42Smrg 4212c393a42SmrgFcStrList * 4222c393a42SmrgFcConfigGetCacheDirs (FcConfig *config) 4232c393a42Smrg{ 4242c393a42Smrg if (!config) 4252c393a42Smrg { 4262c393a42Smrg config = FcConfigGetCurrent (); 4272c393a42Smrg if (!config) 4282c393a42Smrg return 0; 4292c393a42Smrg } 4302c393a42Smrg return FcStrListCreate (config->cacheDirs); 4312c393a42Smrg} 4322c393a42Smrg 4332c393a42SmrgFcBool 4342c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 4352c393a42Smrg const FcChar8 *f) 4362c393a42Smrg{ 4372c393a42Smrg FcBool ret; 4382c393a42Smrg FcChar8 *file = FcConfigFilename (f); 4392c393a42Smrg 4402c393a42Smrg if (!file) 4412c393a42Smrg return FcFalse; 4422c393a42Smrg 4432c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 4442c393a42Smrg FcStrFree (file); 4452c393a42Smrg return ret; 4462c393a42Smrg} 4472c393a42Smrg 4482c393a42SmrgFcStrList * 4492c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 4502c393a42Smrg{ 4512c393a42Smrg if (!config) 4522c393a42Smrg { 4532c393a42Smrg config = FcConfigGetCurrent (); 4542c393a42Smrg if (!config) 4552c393a42Smrg return 0; 4562c393a42Smrg } 4572c393a42Smrg return FcStrListCreate (config->configFiles); 4582c393a42Smrg} 4592c393a42Smrg 4602c393a42SmrgFcChar8 * 4612c393a42SmrgFcConfigGetCache (FcConfig *config) 4622c393a42Smrg{ 4632c393a42Smrg return NULL; 4642c393a42Smrg} 4652c393a42Smrg 4662c393a42SmrgFcFontSet * 4672c393a42SmrgFcConfigGetFonts (FcConfig *config, 4682c393a42Smrg FcSetName set) 4692c393a42Smrg{ 4702c393a42Smrg if (!config) 4712c393a42Smrg { 4722c393a42Smrg config = FcConfigGetCurrent (); 4732c393a42Smrg if (!config) 4742c393a42Smrg return 0; 4752c393a42Smrg } 4762c393a42Smrg return config->fonts[set]; 4772c393a42Smrg} 4782c393a42Smrg 4792c393a42Smrgvoid 4802c393a42SmrgFcConfigSetFonts (FcConfig *config, 4812c393a42Smrg FcFontSet *fonts, 4822c393a42Smrg FcSetName set) 4832c393a42Smrg{ 4842c393a42Smrg if (config->fonts[set]) 4852c393a42Smrg FcFontSetDestroy (config->fonts[set]); 4862c393a42Smrg config->fonts[set] = fonts; 4872c393a42Smrg} 4882c393a42Smrg 4892c393a42SmrgFcBlanks * 4902c393a42SmrgFcConfigGetBlanks (FcConfig *config) 4912c393a42Smrg{ 4922c393a42Smrg if (!config) 4932c393a42Smrg { 4942c393a42Smrg config = FcConfigGetCurrent (); 4952c393a42Smrg if (!config) 4962c393a42Smrg return 0; 4972c393a42Smrg } 4982c393a42Smrg return config->blanks; 4992c393a42Smrg} 5002c393a42Smrg 5012c393a42SmrgFcBool 5022c393a42SmrgFcConfigAddBlank (FcConfig *config, 5032c393a42Smrg FcChar32 blank) 5042c393a42Smrg{ 5052c393a42Smrg FcBlanks *b, *freeme = 0; 5062c393a42Smrg 5072c393a42Smrg b = config->blanks; 5082c393a42Smrg if (!b) 5092c393a42Smrg { 5102c393a42Smrg freeme = b = FcBlanksCreate (); 5112c393a42Smrg if (!b) 5122c393a42Smrg return FcFalse; 5132c393a42Smrg } 5142c393a42Smrg if (!FcBlanksAdd (b, blank)) 5152c393a42Smrg { 5162c393a42Smrg if (freeme) 5172c393a42Smrg FcBlanksDestroy (freeme); 5182c393a42Smrg return FcFalse; 5192c393a42Smrg } 5202c393a42Smrg config->blanks = b; 5212c393a42Smrg return FcTrue; 5222c393a42Smrg} 5232c393a42Smrg 5242c393a42Smrgint 5252c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 5262c393a42Smrg{ 5272c393a42Smrg if (!config) 5282c393a42Smrg { 5292c393a42Smrg config = FcConfigGetCurrent (); 5302c393a42Smrg if (!config) 5312c393a42Smrg return 0; 5322c393a42Smrg } 5332c393a42Smrg return config->rescanInterval; 5342c393a42Smrg} 5352c393a42Smrg 5362c393a42SmrgFcBool 5372c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 5382c393a42Smrg{ 5392c393a42Smrg if (!config) 5402c393a42Smrg { 5412c393a42Smrg config = FcConfigGetCurrent (); 5422c393a42Smrg if (!config) 5432c393a42Smrg return FcFalse; 5442c393a42Smrg } 5452c393a42Smrg config->rescanInterval = rescanInterval; 5462c393a42Smrg return FcTrue; 5472c393a42Smrg} 5482c393a42Smrg 5492c393a42Smrg/* 5502c393a42Smrg * A couple of typos escaped into the library 5512c393a42Smrg */ 5522c393a42Smrgint 5532c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 5542c393a42Smrg{ 5552c393a42Smrg return FcConfigGetRescanInterval (config); 5562c393a42Smrg} 5572c393a42Smrg 5582c393a42SmrgFcBool 5592c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 5602c393a42Smrg{ 5612c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 5622c393a42Smrg} 5632c393a42Smrg 5642c393a42Smrg 5652c393a42SmrgFcBool 5662c393a42SmrgFcConfigAddEdit (FcConfig *config, 5672c393a42Smrg FcTest *test, 5682c393a42Smrg FcEdit *edit, 5692c393a42Smrg FcMatchKind kind) 5702c393a42Smrg{ 5712c393a42Smrg FcSubst *subst, **prev; 5722c393a42Smrg FcTest *t; 5732c393a42Smrg int num; 5742c393a42Smrg 5752c393a42Smrg switch (kind) { 5762c393a42Smrg case FcMatchPattern: 5772c393a42Smrg prev = &config->substPattern; 5782c393a42Smrg break; 5792c393a42Smrg case FcMatchFont: 5802c393a42Smrg prev = &config->substFont; 5812c393a42Smrg break; 5822c393a42Smrg case FcMatchScan: 5832c393a42Smrg prev = &config->substScan; 5842c393a42Smrg break; 5852c393a42Smrg default: 5862c393a42Smrg return FcFalse; 5872c393a42Smrg } 5882c393a42Smrg subst = (FcSubst *) malloc (sizeof (FcSubst)); 5892c393a42Smrg if (!subst) 5902c393a42Smrg return FcFalse; 5912c393a42Smrg FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst)); 5922c393a42Smrg for (; *prev; prev = &(*prev)->next); 5932c393a42Smrg *prev = subst; 5942c393a42Smrg subst->next = 0; 5952c393a42Smrg subst->test = test; 5962c393a42Smrg subst->edit = edit; 5972c393a42Smrg num = 0; 5982c393a42Smrg for (t = test; t; t = t->next) 5992c393a42Smrg { 6002c393a42Smrg if (t->kind == FcMatchDefault) 6012c393a42Smrg t->kind = kind; 6022c393a42Smrg num++; 6032c393a42Smrg } 6042c393a42Smrg if (config->maxObjects < num) 6052c393a42Smrg config->maxObjects = num; 6062c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 6072c393a42Smrg { 6082c393a42Smrg printf ("Add Subst "); 6092c393a42Smrg FcSubstPrint (subst); 6102c393a42Smrg } 6112c393a42Smrg return FcTrue; 6122c393a42Smrg} 6132c393a42Smrg 6142c393a42Smrgtypedef struct _FcSubState { 6152c393a42Smrg FcPatternElt *elt; 6162c393a42Smrg FcValueList *value; 6172c393a42Smrg} FcSubState; 6182c393a42Smrg 6192c393a42Smrgstatic FcValue 6202c393a42SmrgFcConfigPromote (FcValue v, FcValue u) 6212c393a42Smrg{ 6222c393a42Smrg if (v.type == FcTypeInteger) 6232c393a42Smrg { 6242c393a42Smrg v.type = FcTypeDouble; 6252c393a42Smrg v.u.d = (double) v.u.i; 6262c393a42Smrg } 6272c393a42Smrg else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 6282c393a42Smrg { 6292c393a42Smrg v.u.m = &FcIdentityMatrix; 6302c393a42Smrg v.type = FcTypeMatrix; 6312c393a42Smrg } 6322c393a42Smrg else if (v.type == FcTypeString && u.type == FcTypeLangSet) 6332c393a42Smrg { 6342c393a42Smrg v.u.l = FcLangSetPromote (v.u.s); 6352c393a42Smrg v.type = FcTypeLangSet; 6362c393a42Smrg } 6372c393a42Smrg return v; 6382c393a42Smrg} 6392c393a42Smrg 6402c393a42SmrgFcBool 6412c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 6422c393a42Smrg FcOp op, 6432c393a42Smrg const FcValue *right_o) 6442c393a42Smrg{ 6452c393a42Smrg FcValue left = FcValueCanonicalize(left_o); 6462c393a42Smrg FcValue right = FcValueCanonicalize(right_o); 6472c393a42Smrg FcBool ret = FcFalse; 6482c393a42Smrg 6492c393a42Smrg left = FcConfigPromote (left, right); 6502c393a42Smrg right = FcConfigPromote (right, left); 6512c393a42Smrg if (left.type == right.type) 6522c393a42Smrg { 6532c393a42Smrg switch (left.type) { 6542c393a42Smrg case FcTypeInteger: 6552c393a42Smrg break; /* FcConfigPromote prevents this from happening */ 6562c393a42Smrg case FcTypeDouble: 6572c393a42Smrg switch (op) { 6582c393a42Smrg case FcOpEqual: 6592c393a42Smrg case FcOpContains: 6602c393a42Smrg case FcOpListing: 6612c393a42Smrg ret = left.u.d == right.u.d; 6622c393a42Smrg break; 6632c393a42Smrg case FcOpNotEqual: 6642c393a42Smrg case FcOpNotContains: 6652c393a42Smrg ret = left.u.d != right.u.d; 6662c393a42Smrg break; 6672c393a42Smrg case FcOpLess: 6682c393a42Smrg ret = left.u.d < right.u.d; 6692c393a42Smrg break; 6702c393a42Smrg case FcOpLessEqual: 6712c393a42Smrg ret = left.u.d <= right.u.d; 6722c393a42Smrg break; 6732c393a42Smrg case FcOpMore: 6742c393a42Smrg ret = left.u.d > right.u.d; 6752c393a42Smrg break; 6762c393a42Smrg case FcOpMoreEqual: 6772c393a42Smrg ret = left.u.d >= right.u.d; 6782c393a42Smrg break; 6792c393a42Smrg default: 6802c393a42Smrg break; 6812c393a42Smrg } 6822c393a42Smrg break; 6832c393a42Smrg case FcTypeBool: 6842c393a42Smrg switch (op) { 6852c393a42Smrg case FcOpEqual: 6862c393a42Smrg case FcOpContains: 6872c393a42Smrg case FcOpListing: 6882c393a42Smrg ret = left.u.b == right.u.b; 6892c393a42Smrg break; 6902c393a42Smrg case FcOpNotEqual: 6912c393a42Smrg case FcOpNotContains: 6922c393a42Smrg ret = left.u.b != right.u.b; 6932c393a42Smrg break; 6942c393a42Smrg default: 6952c393a42Smrg break; 6962c393a42Smrg } 6972c393a42Smrg break; 6982c393a42Smrg case FcTypeString: 6992c393a42Smrg switch (op) { 7002c393a42Smrg case FcOpEqual: 7012c393a42Smrg case FcOpListing: 7022c393a42Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 7032c393a42Smrg break; 7042c393a42Smrg case FcOpContains: 7052c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 7062c393a42Smrg break; 7072c393a42Smrg case FcOpNotEqual: 7082c393a42Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 7092c393a42Smrg break; 7102c393a42Smrg case FcOpNotContains: 7112c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 7122c393a42Smrg break; 7132c393a42Smrg default: 7142c393a42Smrg break; 7152c393a42Smrg } 7162c393a42Smrg break; 7172c393a42Smrg case FcTypeMatrix: 7182c393a42Smrg switch (op) { 7192c393a42Smrg case FcOpEqual: 7202c393a42Smrg case FcOpContains: 7212c393a42Smrg case FcOpListing: 7222c393a42Smrg ret = FcMatrixEqual (left.u.m, right.u.m); 7232c393a42Smrg break; 7242c393a42Smrg case FcOpNotEqual: 7252c393a42Smrg case FcOpNotContains: 7262c393a42Smrg ret = !FcMatrixEqual (left.u.m, right.u.m); 7272c393a42Smrg break; 7282c393a42Smrg default: 7292c393a42Smrg break; 7302c393a42Smrg } 7312c393a42Smrg break; 7322c393a42Smrg case FcTypeCharSet: 7332c393a42Smrg switch (op) { 7342c393a42Smrg case FcOpContains: 7352c393a42Smrg case FcOpListing: 7362c393a42Smrg /* left contains right if right is a subset of left */ 7372c393a42Smrg ret = FcCharSetIsSubset (right.u.c, left.u.c); 7382c393a42Smrg break; 7392c393a42Smrg case FcOpNotContains: 7402c393a42Smrg /* left contains right if right is a subset of left */ 7412c393a42Smrg ret = !FcCharSetIsSubset (right.u.c, left.u.c); 7422c393a42Smrg break; 7432c393a42Smrg case FcOpEqual: 7442c393a42Smrg ret = FcCharSetEqual (left.u.c, right.u.c); 7452c393a42Smrg break; 7462c393a42Smrg case FcOpNotEqual: 7472c393a42Smrg ret = !FcCharSetEqual (left.u.c, right.u.c); 7482c393a42Smrg break; 7492c393a42Smrg default: 7502c393a42Smrg break; 7512c393a42Smrg } 7522c393a42Smrg break; 7532c393a42Smrg case FcTypeLangSet: 7542c393a42Smrg switch (op) { 7552c393a42Smrg case FcOpContains: 7562c393a42Smrg case FcOpListing: 7572c393a42Smrg ret = FcLangSetContains (left.u.l, right.u.l); 7582c393a42Smrg break; 7592c393a42Smrg case FcOpNotContains: 7602c393a42Smrg ret = !FcLangSetContains (left.u.l, right.u.l); 7612c393a42Smrg break; 7622c393a42Smrg case FcOpEqual: 7632c393a42Smrg ret = FcLangSetEqual (left.u.l, right.u.l); 7642c393a42Smrg break; 7652c393a42Smrg case FcOpNotEqual: 7662c393a42Smrg ret = !FcLangSetEqual (left.u.l, right.u.l); 7672c393a42Smrg break; 7682c393a42Smrg default: 7692c393a42Smrg break; 7702c393a42Smrg } 7712c393a42Smrg break; 7722c393a42Smrg case FcTypeVoid: 7732c393a42Smrg switch (op) { 7742c393a42Smrg case FcOpEqual: 7752c393a42Smrg case FcOpContains: 7762c393a42Smrg case FcOpListing: 7772c393a42Smrg ret = FcTrue; 7782c393a42Smrg break; 7792c393a42Smrg default: 7802c393a42Smrg break; 7812c393a42Smrg } 7822c393a42Smrg break; 7832c393a42Smrg case FcTypeFTFace: 7842c393a42Smrg switch (op) { 7852c393a42Smrg case FcOpEqual: 7862c393a42Smrg case FcOpContains: 7872c393a42Smrg case FcOpListing: 7882c393a42Smrg ret = left.u.f == right.u.f; 7892c393a42Smrg break; 7902c393a42Smrg case FcOpNotEqual: 7912c393a42Smrg case FcOpNotContains: 7922c393a42Smrg ret = left.u.f != right.u.f; 7932c393a42Smrg break; 7942c393a42Smrg default: 7952c393a42Smrg break; 7962c393a42Smrg } 7972c393a42Smrg break; 7982c393a42Smrg } 7992c393a42Smrg } 8002c393a42Smrg else 8012c393a42Smrg { 8022c393a42Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 8032c393a42Smrg ret = FcTrue; 8042c393a42Smrg } 8052c393a42Smrg return ret; 8062c393a42Smrg} 8072c393a42Smrg 8082c393a42Smrg 8092c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 8102c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 8112c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 8122c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 8132c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 8142c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 8152c393a42Smrg 8162c393a42Smrgstatic FcValue 8172c393a42SmrgFcConfigEvaluate (FcPattern *p, FcExpr *e) 8182c393a42Smrg{ 8192c393a42Smrg FcValue v, vl, vr; 8202c393a42Smrg FcResult r; 8212c393a42Smrg FcMatrix *m; 8222c393a42Smrg FcChar8 *str; 8232c393a42Smrg 8242c393a42Smrg switch (e->op) { 8252c393a42Smrg case FcOpInteger: 8262c393a42Smrg v.type = FcTypeInteger; 8272c393a42Smrg v.u.i = e->u.ival; 8282c393a42Smrg break; 8292c393a42Smrg case FcOpDouble: 8302c393a42Smrg v.type = FcTypeDouble; 8312c393a42Smrg v.u.d = e->u.dval; 8322c393a42Smrg break; 8332c393a42Smrg case FcOpString: 8342c393a42Smrg v.type = FcTypeString; 8352c393a42Smrg v.u.s = FcStrStaticName(e->u.sval); 8362c393a42Smrg break; 8372c393a42Smrg case FcOpMatrix: 8382c393a42Smrg v.type = FcTypeMatrix; 8392c393a42Smrg v.u.m = e->u.mval; 8402c393a42Smrg v = FcValueSave (v); 8412c393a42Smrg break; 8422c393a42Smrg case FcOpCharSet: 8432c393a42Smrg v.type = FcTypeCharSet; 8442c393a42Smrg v.u.c = e->u.cval; 8452c393a42Smrg v = FcValueSave (v); 8462c393a42Smrg break; 8472c393a42Smrg case FcOpBool: 8482c393a42Smrg v.type = FcTypeBool; 8492c393a42Smrg v.u.b = e->u.bval; 8502c393a42Smrg break; 8512c393a42Smrg case FcOpField: 8522c393a42Smrg r = FcPatternObjectGet (p, e->u.object, 0, &v); 8532c393a42Smrg if (r != FcResultMatch) 8542c393a42Smrg v.type = FcTypeVoid; 8552c393a42Smrg v = FcValueSave (v); 8562c393a42Smrg break; 8572c393a42Smrg case FcOpConst: 8582c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 8592c393a42Smrg v.type = FcTypeInteger; 8602c393a42Smrg else 8612c393a42Smrg v.type = FcTypeVoid; 8622c393a42Smrg break; 8632c393a42Smrg case FcOpQuest: 8642c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 8652c393a42Smrg if (vl.type == FcTypeBool) 8662c393a42Smrg { 8672c393a42Smrg if (vl.u.b) 8682c393a42Smrg v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); 8692c393a42Smrg else 8702c393a42Smrg v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); 8712c393a42Smrg } 8722c393a42Smrg else 8732c393a42Smrg v.type = FcTypeVoid; 8742c393a42Smrg FcValueDestroy (vl); 8752c393a42Smrg break; 8762c393a42Smrg case FcOpEqual: 8772c393a42Smrg case FcOpNotEqual: 8782c393a42Smrg case FcOpLess: 8792c393a42Smrg case FcOpLessEqual: 8802c393a42Smrg case FcOpMore: 8812c393a42Smrg case FcOpMoreEqual: 8822c393a42Smrg case FcOpContains: 8832c393a42Smrg case FcOpNotContains: 8842c393a42Smrg case FcOpListing: 8852c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 8862c393a42Smrg vr = FcConfigEvaluate (p, e->u.tree.right); 8872c393a42Smrg v.type = FcTypeBool; 8882c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 8892c393a42Smrg FcValueDestroy (vl); 8902c393a42Smrg FcValueDestroy (vr); 8912c393a42Smrg break; 8922c393a42Smrg case FcOpOr: 8932c393a42Smrg case FcOpAnd: 8942c393a42Smrg case FcOpPlus: 8952c393a42Smrg case FcOpMinus: 8962c393a42Smrg case FcOpTimes: 8972c393a42Smrg case FcOpDivide: 8982c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 8992c393a42Smrg vr = FcConfigEvaluate (p, e->u.tree.right); 9002c393a42Smrg vl = FcConfigPromote (vl, vr); 9012c393a42Smrg vr = FcConfigPromote (vr, vl); 9022c393a42Smrg if (vl.type == vr.type) 9032c393a42Smrg { 9042c393a42Smrg switch (vl.type) { 9052c393a42Smrg case FcTypeDouble: 9062c393a42Smrg switch (e->op) { 9072c393a42Smrg case FcOpPlus: 9082c393a42Smrg v.type = FcTypeDouble; 9092c393a42Smrg v.u.d = vl.u.d + vr.u.d; 9102c393a42Smrg break; 9112c393a42Smrg case FcOpMinus: 9122c393a42Smrg v.type = FcTypeDouble; 9132c393a42Smrg v.u.d = vl.u.d - vr.u.d; 9142c393a42Smrg break; 9152c393a42Smrg case FcOpTimes: 9162c393a42Smrg v.type = FcTypeDouble; 9172c393a42Smrg v.u.d = vl.u.d * vr.u.d; 9182c393a42Smrg break; 9192c393a42Smrg case FcOpDivide: 9202c393a42Smrg v.type = FcTypeDouble; 9212c393a42Smrg v.u.d = vl.u.d / vr.u.d; 9222c393a42Smrg break; 9232c393a42Smrg default: 9242c393a42Smrg v.type = FcTypeVoid; 9252c393a42Smrg break; 9262c393a42Smrg } 9272c393a42Smrg if (v.type == FcTypeDouble && 9282c393a42Smrg v.u.d == (double) (int) v.u.d) 9292c393a42Smrg { 9302c393a42Smrg v.type = FcTypeInteger; 9312c393a42Smrg v.u.i = (int) v.u.d; 9322c393a42Smrg } 9332c393a42Smrg break; 9342c393a42Smrg case FcTypeBool: 9352c393a42Smrg switch (e->op) { 9362c393a42Smrg case FcOpOr: 9372c393a42Smrg v.type = FcTypeBool; 9382c393a42Smrg v.u.b = vl.u.b || vr.u.b; 9392c393a42Smrg break; 9402c393a42Smrg case FcOpAnd: 9412c393a42Smrg v.type = FcTypeBool; 9422c393a42Smrg v.u.b = vl.u.b && vr.u.b; 9432c393a42Smrg break; 9442c393a42Smrg default: 9452c393a42Smrg v.type = FcTypeVoid; 9462c393a42Smrg break; 9472c393a42Smrg } 9482c393a42Smrg break; 9492c393a42Smrg case FcTypeString: 9502c393a42Smrg switch (e->op) { 9512c393a42Smrg case FcOpPlus: 9522c393a42Smrg v.type = FcTypeString; 9532c393a42Smrg str = FcStrPlus (vl.u.s, vr.u.s); 9542c393a42Smrg v.u.s = FcStrStaticName (str); 9552c393a42Smrg FcStrFree (str); 9562c393a42Smrg 9572c393a42Smrg if (!v.u.s) 9582c393a42Smrg v.type = FcTypeVoid; 9592c393a42Smrg break; 9602c393a42Smrg default: 9612c393a42Smrg v.type = FcTypeVoid; 9622c393a42Smrg break; 9632c393a42Smrg } 9642c393a42Smrg break; 9652c393a42Smrg case FcTypeMatrix: 9662c393a42Smrg switch (e->op) { 9672c393a42Smrg case FcOpTimes: 9682c393a42Smrg v.type = FcTypeMatrix; 9692c393a42Smrg m = malloc (sizeof (FcMatrix)); 9702c393a42Smrg if (m) 9712c393a42Smrg { 9722c393a42Smrg FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); 9732c393a42Smrg FcMatrixMultiply (m, vl.u.m, vr.u.m); 9742c393a42Smrg v.u.m = m; 9752c393a42Smrg } 9762c393a42Smrg else 9772c393a42Smrg { 9782c393a42Smrg v.type = FcTypeVoid; 9792c393a42Smrg } 9802c393a42Smrg break; 9812c393a42Smrg default: 9822c393a42Smrg v.type = FcTypeVoid; 9832c393a42Smrg break; 9842c393a42Smrg } 9852c393a42Smrg break; 9862c393a42Smrg default: 9872c393a42Smrg v.type = FcTypeVoid; 9882c393a42Smrg break; 9892c393a42Smrg } 9902c393a42Smrg } 9912c393a42Smrg else 9922c393a42Smrg v.type = FcTypeVoid; 9932c393a42Smrg FcValueDestroy (vl); 9942c393a42Smrg FcValueDestroy (vr); 9952c393a42Smrg break; 9962c393a42Smrg case FcOpNot: 9972c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 9982c393a42Smrg switch (vl.type) { 9992c393a42Smrg case FcTypeBool: 10002c393a42Smrg v.type = FcTypeBool; 10012c393a42Smrg v.u.b = !vl.u.b; 10022c393a42Smrg break; 10032c393a42Smrg default: 10042c393a42Smrg v.type = FcTypeVoid; 10052c393a42Smrg break; 10062c393a42Smrg } 10072c393a42Smrg FcValueDestroy (vl); 10082c393a42Smrg break; 10092c393a42Smrg case FcOpFloor: 10102c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 10112c393a42Smrg switch (vl.type) { 10122c393a42Smrg case FcTypeInteger: 10132c393a42Smrg v = vl; 10142c393a42Smrg break; 10152c393a42Smrg case FcTypeDouble: 10162c393a42Smrg v.type = FcTypeInteger; 10172c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 10182c393a42Smrg break; 10192c393a42Smrg default: 10202c393a42Smrg v.type = FcTypeVoid; 10212c393a42Smrg break; 10222c393a42Smrg } 10232c393a42Smrg FcValueDestroy (vl); 10242c393a42Smrg break; 10252c393a42Smrg case FcOpCeil: 10262c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 10272c393a42Smrg switch (vl.type) { 10282c393a42Smrg case FcTypeInteger: 10292c393a42Smrg v = vl; 10302c393a42Smrg break; 10312c393a42Smrg case FcTypeDouble: 10322c393a42Smrg v.type = FcTypeInteger; 10332c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 10342c393a42Smrg break; 10352c393a42Smrg default: 10362c393a42Smrg v.type = FcTypeVoid; 10372c393a42Smrg break; 10382c393a42Smrg } 10392c393a42Smrg FcValueDestroy (vl); 10402c393a42Smrg break; 10412c393a42Smrg case FcOpRound: 10422c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 10432c393a42Smrg switch (vl.type) { 10442c393a42Smrg case FcTypeInteger: 10452c393a42Smrg v = vl; 10462c393a42Smrg break; 10472c393a42Smrg case FcTypeDouble: 10482c393a42Smrg v.type = FcTypeInteger; 10492c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 10502c393a42Smrg break; 10512c393a42Smrg default: 10522c393a42Smrg v.type = FcTypeVoid; 10532c393a42Smrg break; 10542c393a42Smrg } 10552c393a42Smrg FcValueDestroy (vl); 10562c393a42Smrg break; 10572c393a42Smrg case FcOpTrunc: 10582c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 10592c393a42Smrg switch (vl.type) { 10602c393a42Smrg case FcTypeInteger: 10612c393a42Smrg v = vl; 10622c393a42Smrg break; 10632c393a42Smrg case FcTypeDouble: 10642c393a42Smrg v.type = FcTypeInteger; 10652c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 10662c393a42Smrg break; 10672c393a42Smrg default: 10682c393a42Smrg v.type = FcTypeVoid; 10692c393a42Smrg break; 10702c393a42Smrg } 10712c393a42Smrg FcValueDestroy (vl); 10722c393a42Smrg break; 10732c393a42Smrg default: 10742c393a42Smrg v.type = FcTypeVoid; 10752c393a42Smrg break; 10762c393a42Smrg } 10772c393a42Smrg return v; 10782c393a42Smrg} 10792c393a42Smrg 10802c393a42Smrgstatic FcValueList * 10812c393a42SmrgFcConfigMatchValueList (FcPattern *p, 10822c393a42Smrg FcTest *t, 10832c393a42Smrg FcValueList *values) 10842c393a42Smrg{ 10852c393a42Smrg FcValueList *ret = 0; 10862c393a42Smrg FcExpr *e = t->expr; 10872c393a42Smrg FcValue value; 10882c393a42Smrg FcValueList *v; 10892c393a42Smrg 10902c393a42Smrg while (e) 10912c393a42Smrg { 10922c393a42Smrg /* Compute the value of the match expression */ 10932c393a42Smrg if (e->op == FcOpComma) 10942c393a42Smrg { 10952c393a42Smrg value = FcConfigEvaluate (p, e->u.tree.left); 10962c393a42Smrg e = e->u.tree.right; 10972c393a42Smrg } 10982c393a42Smrg else 10992c393a42Smrg { 11002c393a42Smrg value = FcConfigEvaluate (p, e); 11012c393a42Smrg e = 0; 11022c393a42Smrg } 11032c393a42Smrg 11042c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 11052c393a42Smrg { 11062c393a42Smrg /* Compare the pattern value to the match expression value */ 11072c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 11082c393a42Smrg { 11092c393a42Smrg if (!ret) 11102c393a42Smrg ret = v; 11112c393a42Smrg } 11122c393a42Smrg else 11132c393a42Smrg { 11142c393a42Smrg if (t->qual == FcQualAll) 11152c393a42Smrg { 11162c393a42Smrg ret = 0; 11172c393a42Smrg break; 11182c393a42Smrg } 11192c393a42Smrg } 11202c393a42Smrg } 11212c393a42Smrg FcValueDestroy (value); 11222c393a42Smrg } 11232c393a42Smrg return ret; 11242c393a42Smrg} 11252c393a42Smrg 11262c393a42Smrgstatic FcValueList * 11272c393a42SmrgFcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding) 11282c393a42Smrg{ 11292c393a42Smrg FcValueList *l; 11302c393a42Smrg 11312c393a42Smrg if (!e) 11322c393a42Smrg return 0; 11332c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 11342c393a42Smrg if (!l) 11352c393a42Smrg return 0; 11362c393a42Smrg FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); 11372c393a42Smrg if (e->op == FcOpComma) 11382c393a42Smrg { 11392c393a42Smrg l->value = FcConfigEvaluate (p, e->u.tree.left); 11402c393a42Smrg l->next = FcConfigValues (p, e->u.tree.right, binding); 11412c393a42Smrg } 11422c393a42Smrg else 11432c393a42Smrg { 11442c393a42Smrg l->value = FcConfigEvaluate (p, e); 11452c393a42Smrg l->next = NULL; 11462c393a42Smrg } 11472c393a42Smrg l->binding = binding; 11482c393a42Smrg if (l->value.type == FcTypeVoid) 11492c393a42Smrg { 11502c393a42Smrg FcValueList *next = FcValueListNext(l); 11512c393a42Smrg 11522c393a42Smrg FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); 11532c393a42Smrg free (l); 11542c393a42Smrg l = next; 11552c393a42Smrg } 11562c393a42Smrg 11572c393a42Smrg return l; 11582c393a42Smrg} 11592c393a42Smrg 11602c393a42Smrgstatic FcBool 11612c393a42SmrgFcConfigAdd (FcValueListPtr *head, 11622c393a42Smrg FcValueList *position, 11632c393a42Smrg FcBool append, 11642c393a42Smrg FcValueList *new) 11652c393a42Smrg{ 11662c393a42Smrg FcValueListPtr *prev, last, v; 11672c393a42Smrg FcValueBinding sameBinding; 11682c393a42Smrg 11692c393a42Smrg if (position) 11702c393a42Smrg sameBinding = position->binding; 11712c393a42Smrg else 11722c393a42Smrg sameBinding = FcValueBindingWeak; 11732c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 11742c393a42Smrg if (v->binding == FcValueBindingSame) 11752c393a42Smrg v->binding = sameBinding; 11762c393a42Smrg if (append) 11772c393a42Smrg { 11782c393a42Smrg if (position) 11792c393a42Smrg prev = &position->next; 11802c393a42Smrg else 11812c393a42Smrg for (prev = head; *prev != NULL; 11822c393a42Smrg prev = &(*prev)->next) 11832c393a42Smrg ; 11842c393a42Smrg } 11852c393a42Smrg else 11862c393a42Smrg { 11872c393a42Smrg if (position) 11882c393a42Smrg { 11892c393a42Smrg for (prev = head; *prev != NULL; 11902c393a42Smrg prev = &(*prev)->next) 11912c393a42Smrg { 11922c393a42Smrg if (*prev == position) 11932c393a42Smrg break; 11942c393a42Smrg } 11952c393a42Smrg } 11962c393a42Smrg else 11972c393a42Smrg prev = head; 11982c393a42Smrg 11992c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 12002c393a42Smrg { 12012c393a42Smrg if (*prev == NULL) 12022c393a42Smrg printf ("position not on list\n"); 12032c393a42Smrg } 12042c393a42Smrg } 12052c393a42Smrg 12062c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 12072c393a42Smrg { 12082c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 12092c393a42Smrg FcValueListPrint (*head); 12102c393a42Smrg printf ("\n"); 12112c393a42Smrg } 12122c393a42Smrg 12132c393a42Smrg if (new) 12142c393a42Smrg { 12152c393a42Smrg last = new; 12162c393a42Smrg while (last->next != NULL) 12172c393a42Smrg last = last->next; 12182c393a42Smrg 12192c393a42Smrg last->next = *prev; 12202c393a42Smrg *prev = new; 12212c393a42Smrg } 12222c393a42Smrg 12232c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 12242c393a42Smrg { 12252c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 12262c393a42Smrg FcValueListPrint (*head); 12272c393a42Smrg printf ("\n"); 12282c393a42Smrg } 12292c393a42Smrg 12302c393a42Smrg return FcTrue; 12312c393a42Smrg} 12322c393a42Smrg 12332c393a42Smrgstatic void 12342c393a42SmrgFcConfigDel (FcValueListPtr *head, 12352c393a42Smrg FcValueList *position) 12362c393a42Smrg{ 12372c393a42Smrg FcValueListPtr *prev; 12382c393a42Smrg 12392c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 12402c393a42Smrg { 12412c393a42Smrg if (*prev == position) 12422c393a42Smrg { 12432c393a42Smrg *prev = position->next; 12442c393a42Smrg position->next = NULL; 12452c393a42Smrg FcValueListDestroy (position); 12462c393a42Smrg break; 12472c393a42Smrg } 12482c393a42Smrg } 12492c393a42Smrg} 12502c393a42Smrg 12512c393a42Smrgstatic void 12522c393a42SmrgFcConfigPatternAdd (FcPattern *p, 12532c393a42Smrg FcObject object, 12542c393a42Smrg FcValueList *list, 12552c393a42Smrg FcBool append) 12562c393a42Smrg{ 12572c393a42Smrg if (list) 12582c393a42Smrg { 12592c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 12602c393a42Smrg 12612c393a42Smrg if (!e) 12622c393a42Smrg return; 12632c393a42Smrg FcConfigAdd (&e->values, 0, append, list); 12642c393a42Smrg } 12652c393a42Smrg} 12662c393a42Smrg 12672c393a42Smrg/* 12682c393a42Smrg * Delete all values associated with a field 12692c393a42Smrg */ 12702c393a42Smrgstatic void 12712c393a42SmrgFcConfigPatternDel (FcPattern *p, 12722c393a42Smrg FcObject object) 12732c393a42Smrg{ 12742c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 12752c393a42Smrg if (!e) 12762c393a42Smrg return; 12772c393a42Smrg while (e->values != NULL) 12782c393a42Smrg FcConfigDel (&e->values, e->values); 12792c393a42Smrg} 12802c393a42Smrg 12812c393a42Smrgstatic void 12822c393a42SmrgFcConfigPatternCanon (FcPattern *p, 12832c393a42Smrg FcObject object) 12842c393a42Smrg{ 12852c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 12862c393a42Smrg if (!e) 12872c393a42Smrg return; 12882c393a42Smrg if (e->values == NULL) 12892c393a42Smrg FcPatternObjectDel (p, object); 12902c393a42Smrg} 12912c393a42Smrg 12922c393a42SmrgFcBool 12932c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 12942c393a42Smrg FcPattern *p, 12952c393a42Smrg FcPattern *p_pat, 12962c393a42Smrg FcMatchKind kind) 12972c393a42Smrg{ 12982c393a42Smrg FcSubst *s; 12992c393a42Smrg FcSubState *st; 13002c393a42Smrg int i; 13012c393a42Smrg FcTest *t; 13022c393a42Smrg FcEdit *e; 13032c393a42Smrg FcValueList *l; 13042c393a42Smrg FcPattern *m; 13052c393a42Smrg 13062c393a42Smrg if (!config) 13072c393a42Smrg { 13082c393a42Smrg config = FcConfigGetCurrent (); 13092c393a42Smrg if (!config) 13102c393a42Smrg return FcFalse; 13112c393a42Smrg } 13122c393a42Smrg 13132c393a42Smrg switch (kind) { 13142c393a42Smrg case FcMatchPattern: 13152c393a42Smrg s = config->substPattern; 13162c393a42Smrg break; 13172c393a42Smrg case FcMatchFont: 13182c393a42Smrg s = config->substFont; 13192c393a42Smrg break; 13202c393a42Smrg case FcMatchScan: 13212c393a42Smrg s = config->substScan; 13222c393a42Smrg break; 13232c393a42Smrg default: 13242c393a42Smrg return FcFalse; 13252c393a42Smrg } 13262c393a42Smrg 13272c393a42Smrg st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); 13282c393a42Smrg if (!st && config->maxObjects) 13292c393a42Smrg return FcFalse; 13302c393a42Smrg FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 13312c393a42Smrg 13322c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13332c393a42Smrg { 13342c393a42Smrg printf ("FcConfigSubstitute "); 13352c393a42Smrg FcPatternPrint (p); 13362c393a42Smrg } 13372c393a42Smrg for (; s; s = s->next) 13382c393a42Smrg { 13392c393a42Smrg /* 13402c393a42Smrg * Check the tests to see if 13412c393a42Smrg * they all match the pattern 13422c393a42Smrg */ 13432c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 13442c393a42Smrg { 13452c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13462c393a42Smrg { 13472c393a42Smrg printf ("FcConfigSubstitute test "); 13482c393a42Smrg FcTestPrint (t); 13492c393a42Smrg } 13502c393a42Smrg st[i].elt = 0; 13512c393a42Smrg if (kind == FcMatchFont && t->kind == FcMatchPattern) 13522c393a42Smrg m = p_pat; 13532c393a42Smrg else 13542c393a42Smrg m = p; 13552c393a42Smrg if (m) 13562c393a42Smrg st[i].elt = FcPatternObjectFindElt (m, t->object); 13572c393a42Smrg else 13582c393a42Smrg st[i].elt = 0; 13592c393a42Smrg /* 13602c393a42Smrg * If there's no such field in the font, 13612c393a42Smrg * then FcQualAll matches while FcQualAny does not 13622c393a42Smrg */ 13632c393a42Smrg if (!st[i].elt) 13642c393a42Smrg { 13652c393a42Smrg if (t->qual == FcQualAll) 13662c393a42Smrg { 13672c393a42Smrg st[i].value = 0; 13682c393a42Smrg continue; 13692c393a42Smrg } 13702c393a42Smrg else 13712c393a42Smrg break; 13722c393a42Smrg } 13732c393a42Smrg /* 13742c393a42Smrg * Check to see if there is a match, mark the location 13752c393a42Smrg * to apply match-relative edits 13762c393a42Smrg */ 13772c393a42Smrg st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values); 13782c393a42Smrg if (!st[i].value) 13792c393a42Smrg break; 13802c393a42Smrg if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) 13812c393a42Smrg break; 13822c393a42Smrg if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) 13832c393a42Smrg break; 13842c393a42Smrg } 13852c393a42Smrg if (t) 13862c393a42Smrg { 13872c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13882c393a42Smrg printf ("No match\n"); 13892c393a42Smrg continue; 13902c393a42Smrg } 13912c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13922c393a42Smrg { 13932c393a42Smrg printf ("Substitute "); 13942c393a42Smrg FcSubstPrint (s); 13952c393a42Smrg } 13962c393a42Smrg for (e = s->edit; e; e = e->next) 13972c393a42Smrg { 13982c393a42Smrg /* 13992c393a42Smrg * Evaluate the list of expressions 14002c393a42Smrg */ 14012c393a42Smrg l = FcConfigValues (p, e->expr, e->binding); 14022c393a42Smrg /* 14032c393a42Smrg * Locate any test associated with this field, skipping 14042c393a42Smrg * tests associated with the pattern when substituting in 14052c393a42Smrg * the font 14062c393a42Smrg */ 14072c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 14082c393a42Smrg { 14092c393a42Smrg if ((t->kind == FcMatchFont || kind == FcMatchPattern) && 14102c393a42Smrg t->object == e->object) 14112c393a42Smrg { 14122c393a42Smrg /* 14132c393a42Smrg * KLUDGE - the pattern may have been reallocated or 14142c393a42Smrg * things may have been inserted or deleted above 14152c393a42Smrg * this element by other edits. Go back and find 14162c393a42Smrg * the element again 14172c393a42Smrg */ 14182c393a42Smrg if (e != s->edit && st[i].elt) 14192c393a42Smrg st[i].elt = FcPatternObjectFindElt (p, t->object); 14202c393a42Smrg if (!st[i].elt) 14212c393a42Smrg t = 0; 14222c393a42Smrg break; 14232c393a42Smrg } 14242c393a42Smrg } 14252c393a42Smrg switch (e->op) { 14262c393a42Smrg case FcOpAssign: 14272c393a42Smrg /* 14282c393a42Smrg * If there was a test, then replace the matched 14292c393a42Smrg * value with the new list of values 14302c393a42Smrg */ 14312c393a42Smrg if (t) 14322c393a42Smrg { 14332c393a42Smrg FcValueList *thisValue = st[i].value; 14342c393a42Smrg FcValueList *nextValue = thisValue; 14352c393a42Smrg 14362c393a42Smrg /* 14372c393a42Smrg * Append the new list of values after the current value 14382c393a42Smrg */ 14392c393a42Smrg FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l); 14402c393a42Smrg /* 14412c393a42Smrg * Delete the marked value 14422c393a42Smrg */ 14432c393a42Smrg if (thisValue) 14442c393a42Smrg FcConfigDel (&st[i].elt->values, thisValue); 14452c393a42Smrg /* 14462c393a42Smrg * Adjust any pointers into the value list to ensure 14472c393a42Smrg * future edits occur at the same place 14482c393a42Smrg */ 14492c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 14502c393a42Smrg { 14512c393a42Smrg if (st[i].value == thisValue) 14522c393a42Smrg st[i].value = nextValue; 14532c393a42Smrg } 14542c393a42Smrg break; 14552c393a42Smrg } 14562c393a42Smrg /* fall through ... */ 14572c393a42Smrg case FcOpAssignReplace: 14582c393a42Smrg /* 14592c393a42Smrg * Delete all of the values and insert 14602c393a42Smrg * the new set 14612c393a42Smrg */ 14622c393a42Smrg FcConfigPatternDel (p, e->object); 14632c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcTrue); 14642c393a42Smrg /* 14652c393a42Smrg * Adjust any pointers into the value list as they no 14662c393a42Smrg * longer point to anything valid 14672c393a42Smrg */ 14682c393a42Smrg if (t) 14692c393a42Smrg { 14702c393a42Smrg FcPatternElt *thisElt = st[i].elt; 14712c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 14722c393a42Smrg { 14732c393a42Smrg if (st[i].elt == thisElt) 14742c393a42Smrg st[i].value = 0; 14752c393a42Smrg } 14762c393a42Smrg } 14772c393a42Smrg break; 14782c393a42Smrg case FcOpPrepend: 14792c393a42Smrg if (t) 14802c393a42Smrg { 14812c393a42Smrg FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l); 14822c393a42Smrg break; 14832c393a42Smrg } 14842c393a42Smrg /* fall through ... */ 14852c393a42Smrg case FcOpPrependFirst: 14862c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcFalse); 14872c393a42Smrg break; 14882c393a42Smrg case FcOpAppend: 14892c393a42Smrg if (t) 14902c393a42Smrg { 14912c393a42Smrg FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l); 14922c393a42Smrg break; 14932c393a42Smrg } 14942c393a42Smrg /* fall through ... */ 14952c393a42Smrg case FcOpAppendLast: 14962c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcTrue); 14972c393a42Smrg break; 14982c393a42Smrg default: 14992c393a42Smrg FcValueListDestroy (l); 15002c393a42Smrg break; 15012c393a42Smrg } 15022c393a42Smrg } 15032c393a42Smrg /* 15042c393a42Smrg * Now go through the pattern and eliminate 15052c393a42Smrg * any properties without data 15062c393a42Smrg */ 15072c393a42Smrg for (e = s->edit; e; e = e->next) 15082c393a42Smrg FcConfigPatternCanon (p, e->object); 15092c393a42Smrg 15102c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15112c393a42Smrg { 15122c393a42Smrg printf ("FcConfigSubstitute edit"); 15132c393a42Smrg FcPatternPrint (p); 15142c393a42Smrg } 15152c393a42Smrg } 15162c393a42Smrg FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 15172c393a42Smrg free (st); 15182c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15192c393a42Smrg { 15202c393a42Smrg printf ("FcConfigSubstitute done"); 15212c393a42Smrg FcPatternPrint (p); 15222c393a42Smrg } 15232c393a42Smrg return FcTrue; 15242c393a42Smrg} 15252c393a42Smrg 15262c393a42SmrgFcBool 15272c393a42SmrgFcConfigSubstitute (FcConfig *config, 15282c393a42Smrg FcPattern *p, 15292c393a42Smrg FcMatchKind kind) 15302c393a42Smrg{ 15312c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 15322c393a42Smrg} 15332c393a42Smrg 15342c393a42Smrg#if defined (_WIN32) 15352c393a42Smrg 15362c393a42Smrg# define WIN32_LEAN_AND_MEAN 15372c393a42Smrg# define WIN32_EXTRA_LEAN 15382c393a42Smrg# include <windows.h> 15392c393a42Smrg 15402c393a42Smrgstatic FcChar8 fontconfig_path[1000] = ""; 15412c393a42Smrg 15422c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 15432c393a42Smrg 15442c393a42SmrgBOOL WINAPI 15452c393a42SmrgDllMain (HINSTANCE hinstDLL, 15462c393a42Smrg DWORD fdwReason, 15472c393a42Smrg LPVOID lpvReserved) 15482c393a42Smrg{ 15492c393a42Smrg FcChar8 *p; 15502c393a42Smrg 15512c393a42Smrg switch (fdwReason) { 15522c393a42Smrg case DLL_PROCESS_ATTACH: 15532c393a42Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path, 15542c393a42Smrg sizeof (fontconfig_path))) 15552c393a42Smrg break; 15562c393a42Smrg 15572c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 15582c393a42Smrg * assume it's a Unix-style installation tree, and use 15592c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 15602c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 15612c393a42Smrg */ 15622c393a42Smrg p = strrchr (fontconfig_path, '\\'); 15632c393a42Smrg if (p) 15642c393a42Smrg { 15652c393a42Smrg *p = '\0'; 15662c393a42Smrg p = strrchr (fontconfig_path, '\\'); 15672c393a42Smrg if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 || 15682c393a42Smrg FcStrCmpIgnoreCase (p + 1, "lib") == 0)) 15692c393a42Smrg *p = '\0'; 15702c393a42Smrg strcat (fontconfig_path, "\\etc\\fonts"); 15712c393a42Smrg } 15722c393a42Smrg else 15732c393a42Smrg fontconfig_path[0] = '\0'; 15742c393a42Smrg 15752c393a42Smrg break; 15762c393a42Smrg } 15772c393a42Smrg 15782c393a42Smrg return TRUE; 15792c393a42Smrg} 15802c393a42Smrg 15812c393a42Smrg# endif /* !PIC */ 15822c393a42Smrg 15832c393a42Smrg#undef FONTCONFIG_PATH 15842c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 15852c393a42Smrg 15862c393a42Smrg#endif /* !_WIN32 */ 15872c393a42Smrg 15882c393a42Smrg#ifndef FONTCONFIG_FILE 15892c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 15902c393a42Smrg#endif 15912c393a42Smrg 15922c393a42Smrgstatic FcChar8 * 15932c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 15942c393a42Smrg{ 15952c393a42Smrg FcChar8 *path; 15962c393a42Smrg 15972c393a42Smrg if (!dir) 15982c393a42Smrg dir = (FcChar8 *) ""; 15992c393a42Smrg path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1); 16002c393a42Smrg if (!path) 16012c393a42Smrg return 0; 16022c393a42Smrg 16032c393a42Smrg strcpy ((char *) path, (const char *) dir); 16042c393a42Smrg /* make sure there's a single separator */ 16052c393a42Smrg#ifdef _WIN32 16062c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 16072c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 16082c393a42Smrg !(file[0] == '/' || 16092c393a42Smrg file[0] == '\\' || 16102c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 16112c393a42Smrg strcat ((char *) path, "\\"); 16122c393a42Smrg#else 16132c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 16142c393a42Smrg strcat ((char *) path, "/"); 16152c393a42Smrg#endif 16162c393a42Smrg strcat ((char *) path, (char *) file); 16172c393a42Smrg 16182c393a42Smrg FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1); 16192c393a42Smrg if (access ((char *) path, R_OK) == 0) 16202c393a42Smrg return path; 16212c393a42Smrg 16222c393a42Smrg FcStrFree (path); 16232c393a42Smrg return 0; 16242c393a42Smrg} 16252c393a42Smrg 16262c393a42Smrgstatic FcChar8 ** 16272c393a42SmrgFcConfigGetPath (void) 16282c393a42Smrg{ 16292c393a42Smrg FcChar8 **path; 16302c393a42Smrg FcChar8 *env, *e, *colon; 16312c393a42Smrg FcChar8 *dir; 16322c393a42Smrg int npath; 16332c393a42Smrg int i; 16342c393a42Smrg 16352c393a42Smrg npath = 2; /* default dir + null */ 16362c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 16372c393a42Smrg if (env) 16382c393a42Smrg { 16392c393a42Smrg e = env; 16402c393a42Smrg npath++; 16412c393a42Smrg while (*e) 16422c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 16432c393a42Smrg npath++; 16442c393a42Smrg } 16452c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 16462c393a42Smrg if (!path) 16472c393a42Smrg goto bail0; 16482c393a42Smrg i = 0; 16492c393a42Smrg 16502c393a42Smrg if (env) 16512c393a42Smrg { 16522c393a42Smrg e = env; 16532c393a42Smrg while (*e) 16542c393a42Smrg { 16552c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 16562c393a42Smrg if (!colon) 16572c393a42Smrg colon = e + strlen ((char *) e); 16582c393a42Smrg path[i] = malloc (colon - e + 1); 16592c393a42Smrg if (!path[i]) 16602c393a42Smrg goto bail1; 16612c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 16622c393a42Smrg path[i][colon - e] = '\0'; 16632c393a42Smrg if (*colon) 16642c393a42Smrg e = colon + 1; 16652c393a42Smrg else 16662c393a42Smrg e = colon; 16672c393a42Smrg i++; 16682c393a42Smrg } 16692c393a42Smrg } 16702c393a42Smrg 16712c393a42Smrg#ifdef _WIN32 16722c393a42Smrg if (fontconfig_path[0] == '\0') 16732c393a42Smrg { 16742c393a42Smrg if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path))) 16752c393a42Smrg goto bail1; 16762c393a42Smrg char *p = strrchr (fontconfig_path, '\\'); 16772c393a42Smrg if (p) *p = '\0'; 16782c393a42Smrg strcat (fontconfig_path, "\\fonts"); 16792c393a42Smrg } 16802c393a42Smrg#endif 16812c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 16822c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 16832c393a42Smrg if (!path[i]) 16842c393a42Smrg goto bail1; 16852c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 16862c393a42Smrg return path; 16872c393a42Smrg 16882c393a42Smrgbail1: 16892c393a42Smrg for (i = 0; path[i]; i++) 16902c393a42Smrg free (path[i]); 16912c393a42Smrg free (path); 16922c393a42Smrgbail0: 16932c393a42Smrg return 0; 16942c393a42Smrg} 16952c393a42Smrg 16962c393a42Smrgstatic void 16972c393a42SmrgFcConfigFreePath (FcChar8 **path) 16982c393a42Smrg{ 16992c393a42Smrg FcChar8 **p; 17002c393a42Smrg 17012c393a42Smrg for (p = path; *p; p++) 17022c393a42Smrg free (*p); 17032c393a42Smrg free (path); 17042c393a42Smrg} 17052c393a42Smrg 17062c393a42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; 17072c393a42Smrg 17082c393a42SmrgFcChar8 * 17092c393a42SmrgFcConfigHome (void) 17102c393a42Smrg{ 17112c393a42Smrg if (_FcConfigHomeEnabled) 17122c393a42Smrg { 17132c393a42Smrg char *home = getenv ("HOME"); 17142c393a42Smrg 17152c393a42Smrg#ifdef _WIN32 17162c393a42Smrg if (home == NULL) 17172c393a42Smrg home = getenv ("USERPROFILE"); 17182c393a42Smrg#endif 17192c393a42Smrg 17202c393a42Smrg return (FcChar8 *) home; 17212c393a42Smrg } 17222c393a42Smrg return 0; 17232c393a42Smrg} 17242c393a42Smrg 17252c393a42SmrgFcBool 17262c393a42SmrgFcConfigEnableHome (FcBool enable) 17272c393a42Smrg{ 17282c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 17292c393a42Smrg _FcConfigHomeEnabled = enable; 17302c393a42Smrg return prev; 17312c393a42Smrg} 17322c393a42Smrg 17332c393a42SmrgFcChar8 * 17342c393a42SmrgFcConfigFilename (const FcChar8 *url) 17352c393a42Smrg{ 17362c393a42Smrg FcChar8 *file, *dir, **path, **p; 17372c393a42Smrg 17382c393a42Smrg if (!url || !*url) 17392c393a42Smrg { 17402c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 17412c393a42Smrg if (!url) 17422c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 17432c393a42Smrg } 17442c393a42Smrg file = 0; 17452c393a42Smrg 17462c393a42Smrg#ifdef _WIN32 17472c393a42Smrg if (isalpha (*url) && 17482c393a42Smrg url[1] == ':' && 17492c393a42Smrg (url[2] == '/' || url[2] == '\\')) 17502c393a42Smrg goto absolute_path; 17512c393a42Smrg#endif 17522c393a42Smrg 17532c393a42Smrg switch (*url) { 17542c393a42Smrg case '~': 17552c393a42Smrg dir = FcConfigHome (); 17562c393a42Smrg if (dir) 17572c393a42Smrg file = FcConfigFileExists (dir, url + 1); 17582c393a42Smrg else 17592c393a42Smrg file = 0; 17602c393a42Smrg break; 17612c393a42Smrg#ifdef _WIN32 17622c393a42Smrg case '\\': 17632c393a42Smrg absolute_path: 17642c393a42Smrg#endif 17652c393a42Smrg case '/': 17662c393a42Smrg file = FcConfigFileExists (0, url); 17672c393a42Smrg break; 17682c393a42Smrg default: 17692c393a42Smrg path = FcConfigGetPath (); 17702c393a42Smrg if (!path) 17712c393a42Smrg return 0; 17722c393a42Smrg for (p = path; *p; p++) 17732c393a42Smrg { 17742c393a42Smrg file = FcConfigFileExists (*p, url); 17752c393a42Smrg if (file) 17762c393a42Smrg break; 17772c393a42Smrg } 17782c393a42Smrg FcConfigFreePath (path); 17792c393a42Smrg break; 17802c393a42Smrg } 17812c393a42Smrg return file; 17822c393a42Smrg} 17832c393a42Smrg 17842c393a42Smrg/* 17852c393a42Smrg * Manage the application-specific fonts 17862c393a42Smrg */ 17872c393a42Smrg 17882c393a42SmrgFcBool 17892c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 17902c393a42Smrg const FcChar8 *file) 17912c393a42Smrg{ 17922c393a42Smrg FcFontSet *set; 17932c393a42Smrg FcStrSet *subdirs; 17942c393a42Smrg FcStrList *sublist; 17952c393a42Smrg FcChar8 *subdir; 17962c393a42Smrg 17972c393a42Smrg if (!config) 17982c393a42Smrg { 17992c393a42Smrg config = FcConfigGetCurrent (); 18002c393a42Smrg if (!config) 18012c393a42Smrg return FcFalse; 18022c393a42Smrg } 18032c393a42Smrg 18042c393a42Smrg subdirs = FcStrSetCreate (); 18052c393a42Smrg if (!subdirs) 18062c393a42Smrg return FcFalse; 18072c393a42Smrg 18082c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 18092c393a42Smrg if (!set) 18102c393a42Smrg { 18112c393a42Smrg set = FcFontSetCreate (); 18122c393a42Smrg if (!set) 18132c393a42Smrg { 18142c393a42Smrg FcStrSetDestroy (subdirs); 18152c393a42Smrg return FcFalse; 18162c393a42Smrg } 18172c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 18182c393a42Smrg } 18192c393a42Smrg 18202c393a42Smrg if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 18212c393a42Smrg { 18222c393a42Smrg FcStrSetDestroy (subdirs); 18232c393a42Smrg return FcFalse; 18242c393a42Smrg } 18252c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 18262c393a42Smrg { 18272c393a42Smrg while ((subdir = FcStrListNext (sublist))) 18282c393a42Smrg { 18292c393a42Smrg FcConfigAppFontAddDir (config, subdir); 18302c393a42Smrg } 18312c393a42Smrg FcStrListDone (sublist); 18322c393a42Smrg } 18332c393a42Smrg FcStrSetDestroy (subdirs); 18342c393a42Smrg return FcTrue; 18352c393a42Smrg} 18362c393a42Smrg 18372c393a42SmrgFcBool 18382c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 18392c393a42Smrg const FcChar8 *dir) 18402c393a42Smrg{ 18412c393a42Smrg FcFontSet *set; 18422c393a42Smrg FcStrSet *dirs; 18432c393a42Smrg 18442c393a42Smrg if (!config) 18452c393a42Smrg { 18462c393a42Smrg config = FcConfigGetCurrent (); 18472c393a42Smrg if (!config) 18482c393a42Smrg return FcFalse; 18492c393a42Smrg } 18502c393a42Smrg 18512c393a42Smrg dirs = FcStrSetCreate (); 18522c393a42Smrg if (!dirs) 18532c393a42Smrg return FcFalse; 18542c393a42Smrg 18552c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 18562c393a42Smrg if (!set) 18572c393a42Smrg { 18582c393a42Smrg set = FcFontSetCreate (); 18592c393a42Smrg if (!set) 18602c393a42Smrg { 18612c393a42Smrg FcStrSetDestroy (dirs); 18622c393a42Smrg return FcFalse; 18632c393a42Smrg } 18642c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 18652c393a42Smrg } 18662c393a42Smrg 18672c393a42Smrg FcStrSetAddFilename (dirs, dir); 18682c393a42Smrg 18692c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 18702c393a42Smrg { 18712c393a42Smrg FcStrSetDestroy (dirs); 18722c393a42Smrg return FcFalse; 18732c393a42Smrg } 18742c393a42Smrg FcStrSetDestroy (dirs); 18752c393a42Smrg return FcTrue; 18762c393a42Smrg} 18772c393a42Smrg 18782c393a42Smrgvoid 18792c393a42SmrgFcConfigAppFontClear (FcConfig *config) 18802c393a42Smrg{ 18812c393a42Smrg if (!config) 18822c393a42Smrg { 18832c393a42Smrg config = FcConfigGetCurrent (); 18842c393a42Smrg if (!config) 18852c393a42Smrg return; 18862c393a42Smrg } 18872c393a42Smrg 18882c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 18892c393a42Smrg} 18902c393a42Smrg 18912c393a42Smrg/* 18922c393a42Smrg * Manage filename-based font source selectors 18932c393a42Smrg */ 18942c393a42Smrg 18952c393a42SmrgFcBool 18962c393a42SmrgFcConfigGlobAdd (FcConfig *config, 18972c393a42Smrg const FcChar8 *glob, 18982c393a42Smrg FcBool accept) 18992c393a42Smrg{ 19002c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 19012c393a42Smrg 19022c393a42Smrg return FcStrSetAdd (set, glob); 19032c393a42Smrg} 19042c393a42Smrg 19052c393a42Smrgstatic FcBool 19062c393a42SmrgFcConfigGlobMatch (const FcChar8 *glob, 19072c393a42Smrg const FcChar8 *string) 19082c393a42Smrg{ 19092c393a42Smrg FcChar8 c; 19102c393a42Smrg 19112c393a42Smrg while ((c = *glob++)) 19122c393a42Smrg { 19132c393a42Smrg switch (c) { 19142c393a42Smrg case '*': 19152c393a42Smrg /* short circuit common case */ 19162c393a42Smrg if (!*glob) 19172c393a42Smrg return FcTrue; 19182c393a42Smrg /* short circuit another common case */ 19192c393a42Smrg if (strchr ((char *) glob, '*') == 0) 19202c393a42Smrg string += strlen ((char *) string) - strlen ((char *) glob); 19212c393a42Smrg while (*string) 19222c393a42Smrg { 19232c393a42Smrg if (FcConfigGlobMatch (glob, string)) 19242c393a42Smrg return FcTrue; 19252c393a42Smrg string++; 19262c393a42Smrg } 19272c393a42Smrg return FcFalse; 19282c393a42Smrg case '?': 19292c393a42Smrg if (*string++ == '\0') 19302c393a42Smrg return FcFalse; 19312c393a42Smrg break; 19322c393a42Smrg default: 19332c393a42Smrg if (*string++ != c) 19342c393a42Smrg return FcFalse; 19352c393a42Smrg break; 19362c393a42Smrg } 19372c393a42Smrg } 19382c393a42Smrg return *string == '\0'; 19392c393a42Smrg} 19402c393a42Smrg 19412c393a42Smrgstatic FcBool 19422c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 19432c393a42Smrg const FcChar8 *string) 19442c393a42Smrg{ 19452c393a42Smrg int i; 19462c393a42Smrg 19472c393a42Smrg for (i = 0; i < globs->num; i++) 19482c393a42Smrg if (FcConfigGlobMatch (globs->strs[i], string)) 19492c393a42Smrg return FcTrue; 19502c393a42Smrg return FcFalse; 19512c393a42Smrg} 19522c393a42Smrg 19532c393a42SmrgFcBool 19542c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 19552c393a42Smrg const FcChar8 *filename) 19562c393a42Smrg{ 19572c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 19582c393a42Smrg return FcTrue; 19592c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 19602c393a42Smrg return FcFalse; 19612c393a42Smrg return FcTrue; 19622c393a42Smrg} 19632c393a42Smrg 19642c393a42Smrg/* 19652c393a42Smrg * Manage font-pattern based font source selectors 19662c393a42Smrg */ 19672c393a42Smrg 19682c393a42SmrgFcBool 19692c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 19702c393a42Smrg FcPattern *pattern, 19712c393a42Smrg FcBool accept) 19722c393a42Smrg{ 19732c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 19742c393a42Smrg 19752c393a42Smrg return FcFontSetAdd (set, pattern); 19762c393a42Smrg} 19772c393a42Smrg 19782c393a42Smrgstatic FcBool 19792c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 19802c393a42Smrg const FcPattern *font) 19812c393a42Smrg{ 19822c393a42Smrg int i; 19832c393a42Smrg 19842c393a42Smrg for (i = 0; i < patterns->nfont; i++) 19852c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 19862c393a42Smrg return FcTrue; 19872c393a42Smrg return FcFalse; 19882c393a42Smrg} 19892c393a42Smrg 19902c393a42SmrgFcBool 19912c393a42SmrgFcConfigAcceptFont (FcConfig *config, 19922c393a42Smrg const FcPattern *font) 19932c393a42Smrg{ 19942c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 19952c393a42Smrg return FcTrue; 19962c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 19972c393a42Smrg return FcFalse; 19982c393a42Smrg return FcTrue; 19992c393a42Smrg} 20002c393a42Smrg#define __fccfg__ 20012c393a42Smrg#include "fcaliastail.h" 20022c393a42Smrg#undef __fccfg__ 2003