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