fontconfig/src/fccfg.c

2431 lines
50 KiB
C
Raw Permalink Normal View History

2002-02-15 00:34:13 +01:00
/*
2008-08-12 22:34:24 +02:00
* fontconfig/src/fccfg.c
2002-02-15 00:34:13 +01:00
*
2004-12-07 02:14:46 +01:00
* Copyright © 2000 Keith Packard
2002-02-15 00:34:13 +01:00
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the author(s) not be used in
2002-02-15 00:34:13 +01:00
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. The authors make no
2002-02-15 00:34:13 +01:00
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2002-02-15 00:34:13 +01:00
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2002-02-15 00:34:13 +01:00
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
2012-10-07 23:02:50 +02:00
/* Objects MT-safe for readonly access. */
#include "fcint.h"
#include <dirent.h>
#include <sys/types.h>
#include "../fc-blanks/fcblanks.h"
2002-02-15 00:34:13 +01:00
#if defined (_WIN32) && !defined (R_OK)
#define R_OK 4
#endif
2012-10-07 23:02:50 +02:00
static FcConfig *_fcConfig; /* MT-safe */
2012-10-07 23:02:50 +02:00
static FcConfig *
FcConfigEnsure (void)
{
FcConfig *config;
2012-10-07 23:02:50 +02:00
retry:
config = fc_atomic_ptr_get (&_fcConfig);
if (!config)
2012-10-07 23:02:50 +02:00
{
config = FcInitLoadConfigAndFonts ();
if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
FcConfigDestroy (config);
goto retry;
}
}
return config;
}
FcBool
FcConfigInit (void)
{
return FcConfigEnsure () ? FcTrue : FcFalse;
}
void
FcConfigFini (void)
{
2012-10-07 23:02:50 +02:00
FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
FcConfigDestroy (cfg);
}
2002-02-15 00:34:13 +01:00
FcConfig *
FcConfigCreate (void)
{
FcSetName set;
FcConfig *config;
config = malloc (sizeof (FcConfig));
if (!config)
goto bail0;
2010-04-12 18:18:50 +02:00
config->configDirs = FcStrSetCreate ();
if (!config->configDirs)
2002-02-15 00:34:13 +01:00
goto bail1;
2010-04-12 18:18:50 +02:00
config->configFiles = FcStrSetCreate ();
2002-02-15 00:34:13 +01:00
if (!config->configFiles)
goto bail2;
2010-04-12 18:18:50 +02:00
config->fontDirs = FcStrSetCreate ();
if (!config->fontDirs)
goto bail3;
2010-04-12 18:18:50 +02:00
config->acceptGlobs = FcStrSetCreate ();
if (!config->acceptGlobs)
goto bail4;
config->rejectGlobs = FcStrSetCreate ();
if (!config->rejectGlobs)
goto bail5;
config->acceptPatterns = FcFontSetCreate ();
if (!config->acceptPatterns)
goto bail6;
2010-04-12 18:18:50 +02:00
config->rejectPatterns = FcFontSetCreate ();
if (!config->rejectPatterns)
goto bail7;
config->cacheDirs = FcStrSetCreate ();
if (!config->cacheDirs)
goto bail8;
2010-04-12 18:18:50 +02:00
config->blanks = &fcBlanks;
2002-02-15 00:34:13 +01:00
config->substPattern = 0;
config->substFont = 0;
config->substScan = 0;
2002-02-15 00:34:13 +01:00
config->maxObjects = 0;
for (set = FcSetSystem; set <= FcSetApplication; set++)
config->fonts[set] = 0;
config->rescanTime = time(0);
2010-04-12 18:18:50 +02:00
config->rescanInterval = 30;
2008-08-23 00:08:07 +02:00
config->expr_pool = NULL;
config->sysRoot = NULL;
FcRefInit (&config->ref, 1);
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
return config;
bail8:
FcFontSetDestroy (config->rejectPatterns);
bail7:
FcFontSetDestroy (config->acceptPatterns);
bail6:
FcStrSetDestroy (config->rejectGlobs);
bail5:
FcStrSetDestroy (config->acceptGlobs);
bail4:
FcStrSetDestroy (config->fontDirs);
2002-02-15 00:34:13 +01:00
bail3:
FcStrSetDestroy (config->configFiles);
2002-02-15 00:34:13 +01:00
bail2:
FcStrSetDestroy (config->configDirs);
2002-02-15 00:34:13 +01:00
bail1:
free (config);
bail0:
return 0;
}
static FcFileTime
FcConfigNewestFile (FcStrSet *files)
{
FcStrList *list = FcStrListCreate (files);
FcFileTime newest = { 0, FcFalse };
FcChar8 *file;
struct stat statb;
if (list)
{
while ((file = FcStrListNext (list)))
if (FcStat (file, &statb) == 0)
if (!newest.set || statb.st_mtime - newest.time > 0)
{
newest.set = FcTrue;
newest.time = statb.st_mtime;
}
FcStrListDone (list);
}
return newest;
}
FcBool
FcConfigUptoDate (FcConfig *config)
{
FcFileTime config_time, config_dir_time, font_time;
time_t now = time(0);
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
}
config_time = FcConfigNewestFile (config->configFiles);
config_dir_time = FcConfigNewestFile (config->configDirs);
font_time = FcConfigNewestFile (config->fontDirs);
if ((config_time.set && config_time.time - config->rescanTime > 0) ||
(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
(font_time.set && (font_time.time - config->rescanTime) > 0))
{
/* We need to check for potential clock problems here (OLPC ticket #6046) */
if ((config_time.set && (config_time.time - now) > 0) ||
(config_dir_time.set && (config_dir_time.time - now) > 0) ||
(font_time.set && (font_time.time - now) > 0))
{
fprintf (stderr,
"Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
config->rescanTime = now;
return FcTrue;
}
else
return FcFalse;
}
config->rescanTime = now;
return FcTrue;
}
2002-02-15 00:34:13 +01:00
static void
FcSubstDestroy (FcSubst *s)
{
FcSubst *n;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
while (s)
{
n = s->next;
if (s->rule)
FcRuleDestroy (s->rule);
free (s);
2002-02-15 00:34:13 +01:00
s = n;
}
}
FcExpr *
FcConfigAllocExpr (FcConfig *config)
{
if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
{
FcExprPage *new_page;
new_page = malloc (sizeof (FcExprPage));
if (!new_page)
return 0;
new_page->next_page = config->expr_pool;
new_page->next = new_page->exprs;
config->expr_pool = new_page;
}
return config->expr_pool->next++;
}
2008-08-23 00:08:07 +02:00
FcConfig *
FcConfigReference (FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
FcRefInc (&config->ref);
2008-08-23 00:08:07 +02:00
return config;
}
2002-02-15 00:34:13 +01:00
void
FcConfigDestroy (FcConfig *config)
{
FcSetName set;
FcExprPage *page;
2002-02-15 00:34:13 +01:00
if (FcRefDec (&config->ref) != 1)
2008-08-23 00:08:07 +02:00
return;
2013-01-03 00:35:56 +01:00
(void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
FcStrSetDestroy (config->configDirs);
FcStrSetDestroy (config->fontDirs);
FcStrSetDestroy (config->cacheDirs);
FcStrSetDestroy (config->configFiles);
FcStrSetDestroy (config->acceptGlobs);
FcStrSetDestroy (config->rejectGlobs);
FcFontSetDestroy (config->acceptPatterns);
FcFontSetDestroy (config->rejectPatterns);
if (config->blanks)
FcBlanksDestroy (config->blanks);
2002-02-15 00:34:13 +01:00
FcSubstDestroy (config->substPattern);
FcSubstDestroy (config->substFont);
FcSubstDestroy (config->substScan);
2002-02-15 00:34:13 +01:00
for (set = FcSetSystem; set <= FcSetApplication; set++)
if (config->fonts[set])
FcFontSetDestroy (config->fonts[set]);
page = config->expr_pool;
while (page)
{
FcExprPage *next = page->next_page;
free (page);
page = next;
}
if (config->sysRoot)
FcStrFree (config->sysRoot);
free (config);
2002-02-15 00:34:13 +01:00
}
/*
* Add cache to configuration, adding fonts and directories
2002-02-15 00:34:13 +01:00
*/
FcBool
2010-04-12 18:18:50 +02:00
FcConfigAddCache (FcConfig *config, FcCache *cache,
FcSetName set, FcStrSet *dirSet)
2002-02-15 00:34:13 +01:00
{
FcFontSet *fs;
intptr_t *dirs;
int i;
2002-02-15 00:34:13 +01:00
/*
* Add fonts
*/
fs = FcCacheSet (cache);
if (fs)
{
int nref = 0;
for (i = 0; i < fs->nfont; i++)
{
FcPattern *font = FcFontSetFont (fs, i);
FcChar8 *font_file;
/*
* Check to see if font is banned by filename
*/
if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
0, &font_file) == FcResultMatch &&
!FcConfigAcceptFilename (config, font_file))
{
continue;
}
/*
* Check to see if font is banned by pattern
*/
if (!FcConfigAcceptFont (config, font))
continue;
if (FcFontSetAdd (config->fonts[set], font))
nref++;
}
FcDirCacheReference (cache, nref);
}
/*
* Add directories
*/
dirs = FcCacheDirs (cache);
if (dirs)
2002-02-15 00:34:13 +01:00
{
for (i = 0; i < cache->dirs_count; i++)
{
FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
if (FcConfigAcceptFilename (config, dir))
FcStrSetAddFilename (dirSet, dir);
}
}
return FcTrue;
}
static FcBool
FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
{
FcStrList *dirlist;
FcChar8 *dir;
FcCache *cache;
2010-04-12 18:18:50 +02:00
dirlist = FcStrListCreate (dirSet);
if (!dirlist)
return FcFalse;
while ((dir = FcStrListNext (dirlist)))
{
if (FcDebug () & FC_DBG_FONTSET)
printf ("adding fonts from %s\n", dir);
cache = FcDirCacheRead (dir, FcFalse, config);
if (!cache)
continue;
FcConfigAddCache (config, cache, set, dirSet);
FcDirCacheUnload (cache);
}
FcStrListDone (dirlist);
return FcTrue;
}
/*
* Scan the current list of directories in the configuration
* and build the set of available fonts.
*/
2005-11-29 01:21:05 +01:00
FcBool
FcConfigBuildFonts (FcConfig *config)
{
FcFontSet *fonts;
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
2002-02-15 00:34:13 +01:00
}
fonts = FcFontSetCreate ();
if (!fonts)
return FcFalse;
2010-04-12 18:18:50 +02:00
FcConfigSetFonts (config, fonts, FcSetSystem);
2010-04-12 18:18:50 +02:00
if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
return FcFalse;
2002-02-15 00:34:13 +01:00
if (FcDebug () & FC_DBG_FONTSET)
FcFontSetPrint (fonts);
return FcTrue;
}
FcBool
FcConfigSetCurrent (FcConfig *config)
{
2012-10-07 23:02:50 +02:00
FcConfig *cfg;
retry:
cfg = fc_atomic_ptr_get (&_fcConfig);
if (config == cfg)
return FcTrue;
if (config && !config->fonts[FcSetSystem])
2002-02-15 00:34:13 +01:00
if (!FcConfigBuildFonts (config))
return FcFalse;
2012-10-07 23:02:50 +02:00
if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
goto retry;
FcConfigReference (config);
2012-10-07 23:02:50 +02:00
if (cfg)
FcConfigDestroy (cfg);
2002-02-15 00:34:13 +01:00
return FcTrue;
}
FcConfig *
FcConfigGetCurrent (void)
{
2012-10-07 23:02:50 +02:00
return FcConfigEnsure ();
2002-02-15 00:34:13 +01:00
}
FcBool
FcConfigAddConfigDir (FcConfig *config,
const FcChar8 *d)
2002-02-15 00:34:13 +01:00
{
return FcStrSetAddFilename (config->configDirs, d);
}
2002-02-15 00:34:13 +01:00
FcStrList *
FcConfigGetConfigDirs (FcConfig *config)
{
if (!config)
2002-02-15 00:34:13 +01:00
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
2002-02-15 00:34:13 +01:00
}
return FcStrListCreate (config->configDirs);
}
FcBool
FcConfigAddFontDir (FcConfig *config,
const FcChar8 *d)
{
return FcStrSetAddFilename (config->fontDirs, d);
2002-02-15 00:34:13 +01:00
}
FcBool
FcConfigAddDir (FcConfig *config,
const FcChar8 *d)
{
2010-04-12 18:18:50 +02:00
return (FcConfigAddConfigDir (config, d) &&
FcConfigAddFontDir (config, d));
}
FcStrList *
FcConfigGetFontDirs (FcConfig *config)
2002-02-15 00:34:13 +01:00
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
return FcStrListCreate (config->fontDirs);
2002-02-15 00:34:13 +01:00
}
FcBool
FcConfigAddCacheDir (FcConfig *config,
const FcChar8 *d)
{
return FcStrSetAddFilename (config->cacheDirs, d);
}
FcStrList *
FcConfigGetCacheDirs (const FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
return FcStrListCreate (config->cacheDirs);
}
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
FcBool
FcConfigAddConfigFile (FcConfig *config,
const FcChar8 *f)
2002-02-15 00:34:13 +01:00
{
FcBool ret;
FcChar8 *file = FcConfigFilename (f);
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (!file)
return FcFalse;
2010-04-12 18:18:50 +02:00
ret = FcStrSetAdd (config->configFiles, file);
FcStrFree (file);
return ret;
2002-02-15 00:34:13 +01:00
}
FcStrList *
2002-02-15 00:34:13 +01:00
FcConfigGetConfigFiles (FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
return FcStrListCreate (config->configFiles);
2002-02-15 00:34:13 +01:00
}
FcChar8 *
2012-12-30 04:32:56 +01:00
FcConfigGetCache (FcConfig *config FC_UNUSED)
2002-02-15 00:34:13 +01:00
{
return NULL;
2002-02-15 00:34:13 +01:00
}
FcFontSet *
FcConfigGetFonts (FcConfig *config,
FcSetName set)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
return config->fonts[set];
}
void
FcConfigSetFonts (FcConfig *config,
FcFontSet *fonts,
FcSetName set)
{
if (config->fonts[set])
FcFontSetDestroy (config->fonts[set]);
config->fonts[set] = fonts;
}
FcBlanks *
FcConfigGetBlanks (FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
return config->blanks;
}
FcBool
FcConfigAddBlank (FcConfig *config,
FcChar32 blank)
{
FcBlanks *b, *freeme = 0;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
b = config->blanks;
if (!b)
{
freeme = b = FcBlanksCreate ();
2002-02-15 00:34:13 +01:00
if (!b)
return FcFalse;
}
if (!FcBlanksAdd (b, blank))
{
if (freeme)
FcBlanksDestroy (freeme);
2002-02-15 00:34:13 +01:00
return FcFalse;
}
2002-02-15 00:34:13 +01:00
config->blanks = b;
return FcTrue;
}
int
FcConfigGetRescanInterval (FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return 0;
}
return config->rescanInterval;
}
FcBool
FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
}
config->rescanInterval = rescanInterval;
return FcTrue;
}
/*
* A couple of typos escaped into the library
*/
int
FcConfigGetRescanInverval (FcConfig *config)
{
return FcConfigGetRescanInterval (config);
}
FcBool
FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
{
return FcConfigSetRescanInterval (config, rescanInterval);
}
2002-02-15 00:34:13 +01:00
FcBool
FcConfigAddRule (FcConfig *config,
FcRule *rule,
2002-02-15 00:34:13 +01:00
FcMatchKind kind)
{
FcSubst *subst, **prev;
FcRule *r;
int n = 0;
2002-02-15 00:34:13 +01:00
if (!rule)
return FcFalse;
switch (kind) {
case FcMatchPattern:
prev = &config->substPattern;
break;
case FcMatchFont:
prev = &config->substFont;
break;
case FcMatchScan:
prev = &config->substScan;
break;
default:
return FcFalse;
}
2002-02-15 00:34:13 +01:00
subst = (FcSubst *) malloc (sizeof (FcSubst));
if (!subst)
return FcFalse;
for (; *prev; prev = &(*prev)->next);
*prev = subst;
subst->next = NULL;
subst->rule = rule;
for (r = rule; r; r = r->next)
{
2013-08-05 13:04:13 +02:00
switch (r->type)
{
2013-08-05 13:04:13 +02:00
case FcRuleTest:
if (r->u.test &&
r->u.test->kind == FcMatchDefault)
r->u.test->kind = kind;
if (n < r->u.test->object)
n = r->u.test->object;
2013-08-05 13:04:13 +02:00
break;
case FcRuleEdit:
if (n < r->u.edit->object)
n = r->u.edit->object;
2013-08-05 13:04:13 +02:00
break;
default:
break;
}
}
n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
if (config->maxObjects < n)
config->maxObjects = n;
if (FcDebug () & FC_DBG_EDIT)
{
printf ("Add Subst ");
FcSubstPrint (subst);
}
2002-02-15 00:34:13 +01:00
return FcTrue;
}
static FcValue
FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
2002-02-15 00:34:13 +01:00
{
if (v.type == FcTypeInteger)
{
v.type = FcTypeDouble;
v.u.d = (double) v.u.i;
}
else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
{
v.u.m = &FcIdentityMatrix;
v.type = FcTypeMatrix;
2002-02-15 00:34:13 +01:00
}
else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
{
v.u.l = FcLangSetPromote (v.u.s, buf);
v.type = FcTypeLangSet;
}
else if (v.type == FcTypeVoid && u.type == FcTypeLangSet)
{
v.u.l = FcLangSetPromote (NULL, buf);
v.type = FcTypeLangSet;
}
else if (v.type == FcTypeVoid && u.type == FcTypeCharSet)
{
v.u.c = FcCharSetPromote (buf);
v.type = FcTypeCharSet;
}
if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
{
v.u.r = FcRangePromote (v.u.d, buf);
v.type = FcTypeRange;
}
2002-02-15 00:34:13 +01:00
return v;
}
FcBool
FcConfigCompareValue (const FcValue *left_o,
unsigned int op_,
const FcValue *right_o)
2002-02-15 00:34:13 +01:00
{
FcValue left = FcValueCanonicalize(left_o);
FcValue right = FcValueCanonicalize(right_o);
FcBool ret = FcFalse;
FcOp op = FC_OP_GET_OP (op_);
int flags = FC_OP_GET_FLAGS (op_);
FcValuePromotionBuffer buf1, buf2;
2010-04-12 18:18:50 +02:00
left = FcConfigPromote (left, right, &buf1);
right = FcConfigPromote (right, left, &buf2);
2010-04-12 18:18:50 +02:00
if (left.type == right.type)
2002-02-15 00:34:13 +01:00
{
switch (left.type) {
case FcTypeUnknown:
break; /* No way to guess how to compare for this object */
2002-02-15 00:34:13 +01:00
case FcTypeInteger:
break; /* FcConfigPromote prevents this from happening */
case FcTypeDouble:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = left.u.d == right.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.d != right.u.d;
2002-02-15 00:34:13 +01:00
break;
2010-04-12 18:18:50 +02:00
case FcOpLess:
ret = left.u.d < right.u.d;
2002-02-15 00:34:13 +01:00
break;
2010-04-12 18:18:50 +02:00
case FcOpLessEqual:
ret = left.u.d <= right.u.d;
2002-02-15 00:34:13 +01:00
break;
2010-04-12 18:18:50 +02:00
case FcOpMore:
ret = left.u.d > right.u.d;
2002-02-15 00:34:13 +01:00
break;
2010-04-12 18:18:50 +02:00
case FcOpMoreEqual:
ret = left.u.d >= right.u.d;
2002-02-15 00:34:13 +01:00
break;
default:
break;
}
break;
case FcTypeBool:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2010-04-12 18:18:50 +02:00
case FcOpEqual:
2002-02-15 00:34:13 +01:00
case FcOpContains:
case FcOpListing:
ret = left.u.b == right.u.b;
2002-02-15 00:34:13 +01:00
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.b != right.u.b;
2002-02-15 00:34:13 +01:00
break;
default:
break;
}
break;
case FcTypeString:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2010-04-12 18:18:50 +02:00
case FcOpEqual:
case FcOpListing:
if (flags & FcOpFlagIgnoreBlanks)
ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
else
ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
2002-02-15 00:34:13 +01:00
break;
case FcOpContains:
ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
break;
case FcOpNotEqual:
if (flags & FcOpFlagIgnoreBlanks)
ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
else
ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
break;
case FcOpNotContains:
ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
break;
2002-02-15 00:34:13 +01:00
default:
break;
}
break;
case FcTypeMatrix:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = FcMatrixEqual (left.u.m, right.u.m);
2002-02-15 00:34:13 +01:00
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = !FcMatrixEqual (left.u.m, right.u.m);
2002-02-15 00:34:13 +01:00
break;
default:
break;
}
break;
case FcTypeCharSet:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpContains:
case FcOpListing:
/* left contains right if right is a subset of left */
ret = FcCharSetIsSubset (right.u.c, left.u.c);
2002-02-15 00:34:13 +01:00
break;
case FcOpNotContains:
/* left contains right if right is a subset of left */
ret = !FcCharSetIsSubset (right.u.c, left.u.c);
break;
2002-02-15 00:34:13 +01:00
case FcOpEqual:
ret = FcCharSetEqual (left.u.c, right.u.c);
2002-02-15 00:34:13 +01:00
break;
case FcOpNotEqual:
ret = !FcCharSetEqual (left.u.c, right.u.c);
2002-02-15 00:34:13 +01:00
break;
default:
break;
}
break;
case FcTypeLangSet:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
case FcOpContains:
case FcOpListing:
ret = FcLangSetContains (left.u.l, right.u.l);
break;
case FcOpNotContains:
ret = !FcLangSetContains (left.u.l, right.u.l);
break;
case FcOpEqual:
ret = FcLangSetEqual (left.u.l, right.u.l);
break;
case FcOpNotEqual:
ret = !FcLangSetEqual (left.u.l, right.u.l);
break;
default:
break;
}
break;
2002-02-15 00:34:13 +01:00
case FcTypeVoid:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpEqual:
case FcOpContains:
case FcOpListing:
2002-02-15 00:34:13 +01:00
ret = FcTrue;
break;
default:
break;
}
break;
case FcTypeFTFace:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = left.u.f == right.u.f;
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.f != right.u.f;
break;
default:
break;
}
break;
case FcTypeRange:
ret = FcRangeCompare (op, left.u.r, right.u.r);
break;
2002-02-15 00:34:13 +01:00
}
}
else
{
if (op == FcOpNotEqual || op == FcOpNotContains)
2002-02-15 00:34:13 +01:00
ret = FcTrue;
}
return ret;
}
#define _FcDoubleFloor(d) ((int) (d))
#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
2002-02-15 00:34:13 +01:00
static FcValue
FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
2002-02-15 00:34:13 +01:00
{
FcValue v, vl, vr, vle, vre;
2002-02-15 00:34:13 +01:00
FcMatrix *m;
FcChar8 *str;
FcOp op = FC_OP_GET_OP (e->op);
FcValuePromotionBuffer buf1, buf2;
2010-04-12 18:18:50 +02:00
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpInteger:
v.type = FcTypeInteger;
v.u.i = e->u.ival;
break;
case FcOpDouble:
v.type = FcTypeDouble;
v.u.d = e->u.dval;
break;
case FcOpString:
v.type = FcTypeString;
2009-06-05 22:49:07 +02:00
v.u.s = e->u.sval;
v = FcValueSave (v);
2002-02-15 00:34:13 +01:00
break;
case FcOpMatrix:
{
FcMatrix m;
FcValue xx, xy, yx, yy;
2012-12-30 04:11:09 +01:00
v.type = FcTypeMatrix;
xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
yx.type == FcTypeDouble && yy.type == FcTypeDouble)
{
m.xx = xx.u.d;
m.xy = xy.u.d;
m.yx = yx.u.d;
m.yy = yy.u.d;
v.u.m = &m;
}
else
v.type = FcTypeVoid;
v = FcValueSave (v);
}
2002-02-15 00:34:13 +01:00
break;
case FcOpCharSet:
v.type = FcTypeCharSet;
v.u.c = e->u.cval;
2002-02-15 00:34:13 +01:00
v = FcValueSave (v);
break;
case FcOpLangSet:
v.type = FcTypeLangSet;
v.u.l = e->u.lval;
v = FcValueSave (v);
break;
case FcOpRange:
v.type = FcTypeRange;
v.u.r = e->u.rval;
v = FcValueSave (v);
break;
2002-02-15 00:34:13 +01:00
case FcOpBool:
v.type = FcTypeBool;
v.u.b = e->u.bval;
break;
case FcOpField:
if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
{
if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
v.type = FcTypeVoid;
}
else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
{
fprintf (stderr,
"Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
2002-02-15 00:34:13 +01:00
v.type = FcTypeVoid;
}
else
{
if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
v.type = FcTypeVoid;
}
v = FcValueSave (v);
2002-02-15 00:34:13 +01:00
break;
case FcOpConst:
if (FcNameConstant (e->u.constant, &v.u.i))
v.type = FcTypeInteger;
else
v.type = FcTypeVoid;
break;
case FcOpQuest:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
2002-02-15 00:34:13 +01:00
if (vl.type == FcTypeBool)
{
if (vl.u.b)
v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
2002-02-15 00:34:13 +01:00
else
v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
2002-02-15 00:34:13 +01:00
}
else
v.type = FcTypeVoid;
FcValueDestroy (vl);
break;
case FcOpEqual:
2002-02-15 00:34:13 +01:00
case FcOpNotEqual:
case FcOpLess:
case FcOpLessEqual:
case FcOpMore:
case FcOpMoreEqual:
case FcOpContains:
case FcOpNotContains:
case FcOpListing:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
v.type = FcTypeBool;
v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
FcValueDestroy (vl);
FcValueDestroy (vr);
break;
case FcOpOr:
case FcOpAnd:
2002-02-15 00:34:13 +01:00
case FcOpPlus:
case FcOpMinus:
case FcOpTimes:
case FcOpDivide:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
vle = FcConfigPromote (vl, vr, &buf1);
vre = FcConfigPromote (vr, vle, &buf2);
if (vle.type == vre.type)
2002-02-15 00:34:13 +01:00
{
switch ((int) vle.type) {
2002-02-15 00:34:13 +01:00
case FcTypeDouble:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2010-04-12 18:18:50 +02:00
case FcOpPlus:
2002-02-15 00:34:13 +01:00
v.type = FcTypeDouble;
v.u.d = vle.u.d + vre.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpMinus:
v.type = FcTypeDouble;
v.u.d = vle.u.d - vre.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpTimes:
v.type = FcTypeDouble;
v.u.d = vle.u.d * vre.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpDivide:
v.type = FcTypeDouble;
v.u.d = vle.u.d / vre.u.d;
2002-02-15 00:34:13 +01:00
break;
default:
2010-04-12 18:18:50 +02:00
v.type = FcTypeVoid;
2002-02-15 00:34:13 +01:00
break;
}
if (v.type == FcTypeDouble &&
v.u.d == (double) (int) v.u.d)
{
v.type = FcTypeInteger;
v.u.i = (int) v.u.d;
}
break;
case FcTypeBool:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpOr:
v.type = FcTypeBool;
v.u.b = vle.u.b || vre.u.b;
2002-02-15 00:34:13 +01:00
break;
case FcOpAnd:
v.type = FcTypeBool;
v.u.b = vle.u.b && vre.u.b;
2002-02-15 00:34:13 +01:00
break;
default:
2010-04-12 18:18:50 +02:00
v.type = FcTypeVoid;
2002-02-15 00:34:13 +01:00
break;
}
break;
case FcTypeString:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpPlus:
v.type = FcTypeString;
str = FcStrPlus (vle.u.s, vre.u.s);
2013-01-02 09:06:15 +01:00
v.u.s = FcStrdup (str);
FcStrFree (str);
2010-04-12 18:18:50 +02:00
if (!v.u.s)
2002-02-15 00:34:13 +01:00
v.type = FcTypeVoid;
break;
default:
v.type = FcTypeVoid;
break;
}
break;
2002-02-15 00:34:13 +01:00
case FcTypeMatrix:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
2002-02-15 00:34:13 +01:00
case FcOpTimes:
v.type = FcTypeMatrix;
m = malloc (sizeof (FcMatrix));
if (m)
{
FcMatrixMultiply (m, vle.u.m, vre.u.m);
v.u.m = m;
2002-02-15 00:34:13 +01:00
}
else
{
v.type = FcTypeVoid;
}
break;
default:
v.type = FcTypeVoid;
break;
}
break;
case FcTypeCharSet:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
case FcOpPlus:
v.type = FcTypeCharSet;
v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
if (!v.u.c)
v.type = FcTypeVoid;
break;
case FcOpMinus:
v.type = FcTypeCharSet;
v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
if (!v.u.c)
v.type = FcTypeVoid;
break;
default:
v.type = FcTypeVoid;
break;
}
break;
case FcTypeLangSet:
2012-12-30 04:11:09 +01:00
switch ((int) op) {
case FcOpPlus:
v.type = FcTypeLangSet;
v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
if (!v.u.l)
v.type = FcTypeVoid;
break;
case FcOpMinus:
v.type = FcTypeLangSet;
v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
if (!v.u.l)
v.type = FcTypeVoid;
break;
default:
v.type = FcTypeVoid;
break;
}
break;
2002-02-15 00:34:13 +01:00
default:
v.type = FcTypeVoid;
break;
}
}
else
v.type = FcTypeVoid;
FcValueDestroy (vl);
FcValueDestroy (vr);
break;
case FcOpNot:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
2012-12-30 04:11:09 +01:00
switch ((int) vl.type) {
2002-02-15 00:34:13 +01:00
case FcTypeBool:
v.type = FcTypeBool;
v.u.b = !vl.u.b;
break;
default:
v.type = FcTypeVoid;
break;
}
FcValueDestroy (vl);
break;
case FcOpFloor:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
2012-12-30 04:11:09 +01:00
switch ((int) vl.type) {
case FcTypeInteger:
v = vl;
break;
case FcTypeDouble:
v.type = FcTypeInteger;
v.u.i = FcDoubleFloor (vl.u.d);
break;
default:
v.type = FcTypeVoid;
break;
}
FcValueDestroy (vl);
break;
case FcOpCeil:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
2012-12-30 04:11:09 +01:00
switch ((int) vl.type) {
case FcTypeInteger:
v = vl;
break;
case FcTypeDouble:
v.type = FcTypeInteger;
v.u.i = FcDoubleCeil (vl.u.d);
break;
default:
v.type = FcTypeVoid;
break;
}
FcValueDestroy (vl);
break;
case FcOpRound:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
2012-12-30 04:11:09 +01:00
switch ((int) vl.type) {
case FcTypeInteger:
v = vl;
break;
case FcTypeDouble:
v.type = FcTypeInteger;
v.u.i = FcDoubleRound (vl.u.d);
break;
default:
v.type = FcTypeVoid;
break;
}
FcValueDestroy (vl);
break;
case FcOpTrunc:
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
2012-12-30 04:11:09 +01:00
switch ((int) vl.type) {
case FcTypeInteger:
v = vl;
break;
case FcTypeDouble:
v.type = FcTypeInteger;
v.u.i = FcDoubleTrunc (vl.u.d);
break;
default:
v.type = FcTypeVoid;
break;
}
FcValueDestroy (vl);
break;
2002-02-15 00:34:13 +01:00
default:
v.type = FcTypeVoid;
break;
}
return v;
}
static FcValueList *
FcConfigMatchValueList (FcPattern *p,
FcPattern *p_pat,
FcMatchKind kind,
2002-02-15 00:34:13 +01:00
FcTest *t,
FcValueList *values)
2002-02-15 00:34:13 +01:00
{
FcValueList *ret = 0;
FcExpr *e = t->expr;
FcValue value;
FcValueList *v;
2010-04-12 18:18:50 +02:00
while (e)
2002-02-15 00:34:13 +01:00
{
/* Compute the value of the match expression */
if (FC_OP_GET_OP (e->op) == FcOpComma)
2002-02-15 00:34:13 +01:00
{
value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
e = e->u.tree.right;
2002-02-15 00:34:13 +01:00
}
else
{
value = FcConfigEvaluate (p, p_pat, kind, e);
e = 0;
}
for (v = values; v; v = FcValueListNext(v))
{
/* Compare the pattern value to the match expression value */
if (FcConfigCompareValue (&v->value, t->op, &value))
2002-02-15 00:34:13 +01:00
{
if (!ret)
ret = v;
}
else
{
if (t->qual == FcQualAll)
{
ret = 0;
break;
}
2002-02-15 00:34:13 +01:00
}
}
FcValueDestroy (value);
2002-02-15 00:34:13 +01:00
}
return ret;
}
static FcValueList *
FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
2002-02-15 00:34:13 +01:00
{
FcValueList *l;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (!e)
return 0;
l = (FcValueList *) malloc (sizeof (FcValueList));
if (!l)
return 0;
if (FC_OP_GET_OP (e->op) == FcOpComma)
2002-02-15 00:34:13 +01:00
{
l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
2002-02-15 00:34:13 +01:00
}
else
{
l->value = FcConfigEvaluate (p, p_pat, kind, e);
l->next = NULL;
2002-02-15 00:34:13 +01:00
}
2002-07-31 03:36:37 +02:00
l->binding = binding;
if (l->value.type == FcTypeVoid)
2002-02-15 00:34:13 +01:00
{
FcValueList *next = FcValueListNext(l);
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
free (l);
l = next;
2002-02-15 00:34:13 +01:00
}
2002-02-15 00:34:13 +01:00
return l;
}
static FcBool
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
FcConfigAdd (FcValueListPtr *head,
2002-02-15 00:34:13 +01:00
FcValueList *position,
FcBool append,
FcValueList *new,
FcObject object)
2002-02-15 00:34:13 +01:00
{
FcValueListPtr *prev, l, last, v;
FcValueBinding sameBinding;
2010-04-12 18:18:50 +02:00
/*
* Make sure the stored type is valid for built-in objects
*/
for (l = new; l != NULL; l = FcValueListNext (l))
{
if (!FcObjectValidType (object, l->value.type))
{
fprintf (stderr,
"Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
FcValuePrintFile (stderr, l->value);
fprintf (stderr, "\n");
if (FcDebug () & FC_DBG_EDIT)
{
printf ("Not adding\n");
}
return FcFalse;
}
}
if (position)
sameBinding = position->binding;
else
sameBinding = FcValueBindingWeak;
for (v = new; v != NULL; v = FcValueListNext(v))
if (v->binding == FcValueBindingSame)
v->binding = sameBinding;
2002-02-15 00:34:13 +01:00
if (append)
{
if (position)
prev = &position->next;
else
2010-04-12 18:18:50 +02:00
for (prev = head; *prev != NULL;
prev = &(*prev)->next)
2002-02-15 00:34:13 +01:00
;
}
else
{
if (position)
{
2010-04-12 18:18:50 +02:00
for (prev = head; *prev != NULL;
prev = &(*prev)->next)
2002-02-15 00:34:13 +01:00
{
if (*prev == position)
2002-02-15 00:34:13 +01:00
break;
}
}
else
prev = head;
if (FcDebug () & FC_DBG_EDIT)
{
if (*prev == NULL)
2002-02-15 00:34:13 +01:00
printf ("position not on list\n");
}
}
if (FcDebug () & FC_DBG_EDIT)
{
printf ("%s list before ", append ? "Append" : "Prepend");
FcValueListPrintWithPosition (*head, *prev);
2002-02-15 00:34:13 +01:00
printf ("\n");
}
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (new)
{
last = new;
while (last->next != NULL)
last = last->next;
2010-04-12 18:18:50 +02:00
last->next = *prev;
*prev = new;
2002-02-15 00:34:13 +01:00
}
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (FcDebug () & FC_DBG_EDIT)
{
printf ("%s list after ", append ? "Append" : "Prepend");
FcValueListPrint (*head);
printf ("\n");
}
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
return FcTrue;
}
static void
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
FcConfigDel (FcValueListPtr *head,
2002-02-15 00:34:13 +01:00
FcValueList *position)
{
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
FcValueListPtr *prev;
2002-02-15 00:34:13 +01:00
for (prev = head; *prev != NULL; prev = &(*prev)->next)
2002-02-15 00:34:13 +01:00
{
if (*prev == position)
2002-02-15 00:34:13 +01:00
{
*prev = position->next;
position->next = NULL;
FcValueListDestroy (position);
2002-02-15 00:34:13 +01:00
break;
}
}
}
static void
FcConfigPatternAdd (FcPattern *p,
FcObject object,
2002-02-15 00:34:13 +01:00
FcValueList *list,
FcBool append)
{
if (list)
{
FcPatternElt *e = FcPatternObjectInsertElt (p, object);
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (!e)
return;
FcConfigAdd (&e->values, 0, append, list, object);
2002-02-15 00:34:13 +01:00
}
}
/*
* Delete all values associated with a field
*/
static void
FcConfigPatternDel (FcPattern *p,
FcObject object)
2002-02-15 00:34:13 +01:00
{
FcPatternElt *e = FcPatternObjectFindElt (p, object);
2002-02-15 00:34:13 +01:00
if (!e)
return;
while (e->values != NULL)
FcConfigDel (&e->values, e->values);
2002-02-15 00:34:13 +01:00
}
static void
FcConfigPatternCanon (FcPattern *p,
FcObject object)
2002-02-15 00:34:13 +01:00
{
FcPatternElt *e = FcPatternObjectFindElt (p, object);
2002-02-15 00:34:13 +01:00
if (!e)
return;
if (e->values == NULL)
FcPatternObjectDel (p, object);
2002-02-15 00:34:13 +01:00
}
FcBool
FcConfigSubstituteWithPat (FcConfig *config,
FcPattern *p,
FcPattern *p_pat,
FcMatchKind kind)
2002-02-15 00:34:13 +01:00
{
FcValue v;
2002-02-15 00:34:13 +01:00
FcSubst *s;
FcRule *r;
FcValueList *l, **value = NULL, *vl;
FcPattern *m;
FcStrSet *strs;
FcObject object = FC_INVALID_OBJECT;
FcPatternElt **elt = NULL, *e;
2013-08-05 13:04:13 +02:00
int i, nobjs;
FcBool retval = FcTrue;
2013-08-31 03:43:13 +02:00
FcTest **tst = NULL;
2013-08-05 13:04:13 +02:00
2002-02-15 00:34:13 +01:00
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
}
switch (kind) {
case FcMatchPattern:
s = config->substPattern;
strs = FcGetDefaultLangs ();
if (strs)
{
FcStrList *l = FcStrListCreate (strs);
FcChar8 *lang;
FcValue v;
FcLangSet *lsund = FcLangSetCreate ();
FcLangSetAdd (lsund, (const FcChar8 *)"und");
FcStrSetDestroy (strs);
while (l && (lang = FcStrListNext (l)))
{
FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
if (e)
{
FcValueListPtr ll;
for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
{
FcValue vv = FcValueCanonicalize (&ll->value);
if (vv.type == FcTypeLangSet)
{
FcLangSet *ls = FcLangSetCreate ();
FcBool b;
FcLangSetAdd (ls, lang);
b = FcLangSetContains (vv.u.l, ls);
FcLangSetDestroy (ls);
if (b)
goto bail_lang;
if (FcLangSetContains (vv.u.l, lsund))
goto bail_lang;
}
else
{
if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
goto bail_lang;
if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
goto bail_lang;
}
}
}
v.type = FcTypeString;
v.u.s = lang;
FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
}
bail_lang:
FcStrListDone (l);
FcLangSetDestroy (lsund);
}
if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
{
FcChar8 *prgname = FcGetPrgname ();
if (prgname)
FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
}
break;
case FcMatchFont:
s = config->substFont;
break;
case FcMatchScan:
s = config->substScan;
break;
default:
return FcFalse;
}
2013-08-05 13:04:13 +02:00
nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs);
if (!value)
{
retval = FcFalse;
goto bail1;
}
elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs);
if (!elt)
{
retval = FcFalse;
goto bail1;
}
2013-08-31 03:43:13 +02:00
tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs);
if (!tst)
{
retval = FcFalse;
goto bail1;
}
2013-08-05 13:04:13 +02:00
2002-02-15 00:34:13 +01:00
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute ");
FcPatternPrint (p);
}
for (; s; s = s->next)
{
r = s->rule;
2013-08-05 13:04:13 +02:00
for (i = 0; i < nobjs; i++)
{
elt[i] = NULL;
value[i] = NULL;
2013-08-31 03:43:13 +02:00
tst[i] = NULL;
2013-08-05 13:04:13 +02:00
}
for (; r; r = r->next)
2002-02-15 00:34:13 +01:00
{
switch (r->type) {
case FcRuleUnknown:
/* shouldn't be reached */
break;
case FcRuleTest:
2013-08-05 13:04:13 +02:00
object = FC_OBJ_ID (r->u.test->object);
/*
* Check the tests to see if
* they all match the pattern
*/
if (FcDebug () & FC_DBG_EDIT)
2002-02-15 00:34:13 +01:00
{
printf ("FcConfigSubstitute test ");
FcTestPrint (r->u.test);
2002-02-15 00:34:13 +01:00
}
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
m = p_pat;
2002-02-15 00:34:13 +01:00
else
m = p;
if (m)
e = FcPatternObjectFindElt (m, r->u.test->object);
else
e = NULL;
/* different 'kind' won't be the target of edit */
if (!elt[object] && kind == r->u.test->kind)
2013-08-31 03:43:13 +02:00
{
elt[object] = e;
2013-08-31 03:43:13 +02:00
tst[object] = r->u.test;
}
/*
* If there's no such field in the font,
* then FcQualAll matches while FcQualAny does not
*/
if (!e)
{
if (r->u.test->qual == FcQualAll)
{
2013-08-05 13:04:13 +02:00
value[object] = NULL;
continue;
}
else
{
if (FcDebug () & FC_DBG_EDIT)
printf ("No match\n");
goto bail;
}
}
2002-02-15 00:34:13 +01:00
/*
* Check to see if there is a match, mark the location
* to apply match-relative edits
2002-02-15 00:34:13 +01:00
*/
vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
/* different 'kind' won't be the target of edit */
if (!value[object] && kind == r->u.test->kind)
value[object] = vl;
if (!vl ||
(r->u.test->qual == FcQualFirst && vl != e->values) ||
(r->u.test->qual == FcQualNotFirst && vl == e->values))
2002-02-15 00:34:13 +01:00
{
if (FcDebug () & FC_DBG_EDIT)
printf ("No match\n");
goto bail;
}
break;
case FcRuleEdit:
2013-08-05 13:04:13 +02:00
object = FC_OBJ_ID (r->u.edit->object);
if (FcDebug () & FC_DBG_EDIT)
{
printf ("Substitute ");
FcEditPrint (r->u.edit);
printf ("\n\n");
}
/*
* Evaluate the list of expressions
*/
l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding);
2013-08-31 03:43:13 +02:00
if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
switch (FC_OP_GET_OP (r->u.edit->op)) {
case FcOpAssign:
2002-02-15 00:34:13 +01:00
/*
* If there was a test, then replace the matched
* value with the new list of values
2002-02-15 00:34:13 +01:00
*/
2013-08-05 13:04:13 +02:00
if (value[object])
{
2013-08-05 13:04:13 +02:00
FcValueList *thisValue = value[object];
FcValueList *nextValue = l;
/*
* Append the new list of values after the current value
*/
2013-08-05 13:04:13 +02:00
FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
/*
* Delete the marked value
*/
if (thisValue)
2013-08-05 13:04:13 +02:00
FcConfigDel (&elt[object]->values, thisValue);
/*
* Adjust a pointer into the value list to ensure
* future edits occur at the same place
*/
2013-08-05 13:04:13 +02:00
value[object] = nextValue;
break;
}
/* fall through ... */
case FcOpAssignReplace:
/*
* Delete all of the values and insert
* the new set
*/
FcConfigPatternDel (p, r->u.edit->object);
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
2002-02-15 00:34:13 +01:00
/*
* Adjust a pointer into the value list as they no
* longer point to anything valid
2002-02-15 00:34:13 +01:00
*/
2013-08-05 13:04:13 +02:00
value[object] = NULL;
break;
case FcOpPrepend:
2013-08-05 13:04:13 +02:00
if (value[object])
2002-02-15 00:34:13 +01:00
{
2013-08-05 13:04:13 +02:00
FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
break;
2002-02-15 00:34:13 +01:00
}
/* fall through ... */
case FcOpPrependFirst:
FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
2002-02-15 00:34:13 +01:00
break;
case FcOpAppend:
2013-08-05 13:04:13 +02:00
if (value[object])
2002-02-15 00:34:13 +01:00
{
2013-08-05 13:04:13 +02:00
FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
break;
2002-02-15 00:34:13 +01:00
}
/* fall through ... */
case FcOpAppendLast:
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
2002-02-15 00:34:13 +01:00
break;
case FcOpDelete:
2013-08-05 13:04:13 +02:00
if (value[object])
{
2013-08-05 13:04:13 +02:00
FcConfigDel (&elt[object]->values, value[object]);
break;
}
/* fall through ... */
case FcOpDeleteAll:
FcConfigPatternDel (p, r->u.edit->object);
break;
default:
FcValueListDestroy (l);
2002-02-15 00:34:13 +01:00
break;
}
/*
* Now go through the pattern and eliminate
* any properties without data
*/
FcConfigPatternCanon (p, r->u.edit->object);
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute edit");
FcPatternPrint (p);
}
2002-02-15 00:34:13 +01:00
break;
}
}
bail:;
2002-02-15 00:34:13 +01:00
}
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute done");
FcPatternPrint (p);
}
2013-08-05 13:04:13 +02:00
bail1:
if (elt)
free (elt);
if (value)
free (value);
2013-08-31 03:43:13 +02:00
if (tst)
free (tst);
2013-08-05 13:04:13 +02:00
return retval;
2002-02-15 00:34:13 +01:00
}
FcBool
FcConfigSubstitute (FcConfig *config,
FcPattern *p,
FcMatchKind kind)
{
return FcConfigSubstituteWithPat (config, p, 0, kind);
}
#if defined (_WIN32)
2012-10-07 23:46:12 +02:00
static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
FcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
# if (defined (PIC) || defined (DLL_EXPORT))
2013-01-03 00:35:56 +01:00
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved);
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
FcChar8 *p;
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
2012-06-13 13:01:30 +02:00
if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
sizeof (fontconfig_path)))
break;
/* If the fontconfig DLL is in a "bin" or "lib" subfolder,
* assume it's a Unix-style installation tree, and use
* "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
* folder where the DLL is as FONTCONFIG_PATH.
*/
2012-06-13 13:01:30 +02:00
p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
if (p)
{
*p = '\0';
2012-06-13 13:01:30 +02:00
p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
*p = '\0';
strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
2012-06-13 13:01:30 +02:00
strcat ((char *) fontconfig_path, "\\etc\\fonts");
}
else
fontconfig_path[0] = '\0';
2010-04-12 18:18:50 +02:00
break;
}
return TRUE;
}
# endif /* !PIC */
#undef FONTCONFIG_PATH
#define FONTCONFIG_PATH fontconfig_path
#endif /* !_WIN32 */
2002-02-15 00:34:13 +01:00
#ifndef FONTCONFIG_FILE
#define FONTCONFIG_FILE "fonts.conf"
#endif
static FcChar8 *
FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
2002-02-15 00:34:13 +01:00
{
FcChar8 *path;
int size, osize;
2002-02-15 00:34:13 +01:00
if (!dir)
dir = (FcChar8 *) "";
osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
/*
* workaround valgrind warning because glibc takes advantage of how it knows memory is
* allocated to implement strlen by reading in groups of 4
*/
size = (osize + 3) & ~3;
path = malloc (size);
2002-02-15 00:34:13 +01:00
if (!path)
return 0;
2002-03-01 02:00:54 +01:00
strcpy ((char *) path, (const char *) dir);
/* make sure there's a single separator */
#ifdef _WIN32
if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
path[strlen((char *) path)-1] != '\\')) &&
!(file[0] == '/' ||
file[0] == '\\' ||
(isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
strcat ((char *) path, "\\");
#else
if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
strcat ((char *) path, "/");
else
osize--;
#endif
strcat ((char *) path, (char *) file);
2002-02-15 00:34:13 +01:00
if (access ((char *) path, R_OK) == 0)
2002-02-15 00:34:13 +01:00
return path;
2010-04-12 18:18:50 +02:00
FcStrFree (path);
2002-02-15 00:34:13 +01:00
return 0;
}
static FcChar8 **
2002-02-15 00:34:13 +01:00
FcConfigGetPath (void)
{
FcChar8 **path;
FcChar8 *env, *e, *colon;
FcChar8 *dir;
2002-02-15 00:34:13 +01:00
int npath;
int i;
npath = 2; /* default dir + null */
env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
2002-02-15 00:34:13 +01:00
if (env)
{
e = env;
npath++;
while (*e)
if (*e++ == FC_SEARCH_PATH_SEPARATOR)
2002-02-15 00:34:13 +01:00
npath++;
}
path = calloc (npath, sizeof (FcChar8 *));
2002-02-15 00:34:13 +01:00
if (!path)
goto bail0;
i = 0;
if (env)
{
e = env;
2010-04-12 18:18:50 +02:00
while (*e)
2002-02-15 00:34:13 +01:00
{
colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
2002-02-15 00:34:13 +01:00
if (!colon)
colon = e + strlen ((char *) e);
2002-02-15 00:34:13 +01:00
path[i] = malloc (colon - e + 1);
if (!path[i])
goto bail1;
2002-03-01 02:00:54 +01:00
strncpy ((char *) path[i], (const char *) e, colon - e);
2002-02-15 00:34:13 +01:00
path[i][colon - e] = '\0';
if (*colon)
e = colon + 1;
else
e = colon;
i++;
}
}
2010-04-12 18:18:50 +02:00
#ifdef _WIN32
if (fontconfig_path[0] == '\0')
{
2008-08-12 20:10:03 +02:00
char *p;
2012-06-13 13:01:30 +02:00
if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
goto bail1;
2012-06-13 13:01:30 +02:00
p = strrchr ((const char *) fontconfig_path, '\\');
if (p) *p = '\0';
2012-06-13 13:01:30 +02:00
strcat ((char *) fontconfig_path, "\\fonts");
}
#endif
dir = (FcChar8 *) FONTCONFIG_PATH;
path[i] = malloc (strlen ((char *) dir) + 1);
2002-02-15 00:34:13 +01:00
if (!path[i])
goto bail1;
2002-03-01 02:00:54 +01:00
strcpy ((char *) path[i], (const char *) dir);
2002-02-15 00:34:13 +01:00
return path;
bail1:
for (i = 0; path[i]; i++)
free (path[i]);
free (path);
bail0:
return 0;
}
static void
FcConfigFreePath (FcChar8 **path)
2002-02-15 00:34:13 +01:00
{
FcChar8 **p;
2002-02-15 00:34:13 +01:00
for (p = path; *p; p++)
free (*p);
free (path);
}
2012-10-07 23:46:12 +02:00
static FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
FcChar8 *
FcConfigHome (void)
{
if (_FcConfigHomeEnabled)
{
char *home = getenv ("HOME");
#ifdef _WIN32
if (home == NULL)
home = getenv ("USERPROFILE");
#endif
return (FcChar8 *) home;
}
return 0;
}
FcChar8 *
FcConfigXdgCacheHome (void)
{
const char *env = getenv ("XDG_CACHE_HOME");
FcChar8 *ret = NULL;
if (!_FcConfigHomeEnabled)
return NULL;
if (env)
ret = FcStrCopy ((const FcChar8 *)env);
else
{
const FcChar8 *home = FcConfigHome ();
size_t len = home ? strlen ((const char *)home) : 0;
ret = malloc (len + 7 + 1);
if (ret)
{
memcpy (ret, home, len);
memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
ret[len + 7] = 0;
}
}
return ret;
}
FcChar8 *
FcConfigXdgConfigHome (void)
{
const char *env = getenv ("XDG_CONFIG_HOME");
FcChar8 *ret = NULL;
if (!_FcConfigHomeEnabled)
return NULL;
if (env)
ret = FcStrCopy ((const FcChar8 *)env);
else
{
const FcChar8 *home = FcConfigHome ();
size_t len = home ? strlen ((const char *)home) : 0;
ret = malloc (len + 8 + 1);
if (ret)
{
memcpy (ret, home, len);
memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
ret[len + 8] = 0;
}
}
return ret;
}
FcChar8 *
FcConfigXdgDataHome (void)
{
const char *env = getenv ("XDG_DATA_HOME");
FcChar8 *ret = NULL;
if (!_FcConfigHomeEnabled)
return NULL;
if (env)
ret = FcStrCopy ((const FcChar8 *)env);
else
{
const FcChar8 *home = FcConfigHome ();
size_t len = home ? strlen ((const char *)home) : 0;
ret = malloc (len + 13 + 1);
if (ret)
{
memcpy (ret, home, len);
memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
ret[len + 13] = 0;
}
}
return ret;
}
FcBool
FcConfigEnableHome (FcBool enable)
{
FcBool prev = _FcConfigHomeEnabled;
_FcConfigHomeEnabled = enable;
return prev;
}
FcChar8 *
FcConfigFilename (const FcChar8 *url)
2002-02-15 00:34:13 +01:00
{
FcChar8 *file, *dir, **path, **p;
2002-02-15 00:34:13 +01:00
if (!url || !*url)
{
url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
2002-02-15 00:34:13 +01:00
if (!url)
url = (FcChar8 *) FONTCONFIG_FILE;
2002-02-15 00:34:13 +01:00
}
file = 0;
#ifdef _WIN32
if (isalpha (*url) &&
url[1] == ':' &&
(url[2] == '/' || url[2] == '\\'))
goto absolute_path;
#endif
2002-02-15 00:34:13 +01:00
switch (*url) {
case '~':
dir = FcConfigHome ();
2002-02-15 00:34:13 +01:00
if (dir)
file = FcConfigFileExists (dir, url + 1);
else
file = 0;
break;
#ifdef _WIN32
case '\\':
absolute_path:
#endif
2002-02-15 00:34:13 +01:00
case '/':
file = FcConfigFileExists (0, url);
break;
default:
path = FcConfigGetPath ();
if (!path)
return NULL;
2002-02-15 00:34:13 +01:00
for (p = path; *p; p++)
{
file = FcConfigFileExists (*p, url);
if (file)
break;
}
FcConfigFreePath (path);
break;
}
2002-02-15 00:34:13 +01:00
return file;
}
/*
* Manage the application-specific fonts
*/
FcBool
FcConfigAppFontAddFile (FcConfig *config,
const FcChar8 *file)
2002-02-15 00:34:13 +01:00
{
FcFontSet *set;
FcStrSet *subdirs;
FcStrList *sublist;
FcChar8 *subdir;
2002-02-15 00:34:13 +01:00
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
}
subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
if (!subdirs)
return FcFalse;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
set = FcConfigGetFonts (config, FcSetApplication);
if (!set)
{
set = FcFontSetCreate ();
if (!set)
{
FcStrSetDestroy (subdirs);
2002-02-15 00:34:13 +01:00
return FcFalse;
}
2002-02-15 00:34:13 +01:00
FcConfigSetFonts (config, set, FcSetApplication);
}
if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
{
FcStrSetDestroy (subdirs);
return FcFalse;
}
if ((sublist = FcStrListCreate (subdirs)))
{
while ((subdir = FcStrListNext (sublist)))
{
FcConfigAppFontAddDir (config, subdir);
}
FcStrListDone (sublist);
}
FcStrSetDestroy (subdirs);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
FcBool
FcConfigAppFontAddDir (FcConfig *config,
const FcChar8 *dir)
2002-02-15 00:34:13 +01:00
{
FcFontSet *set;
FcStrSet *dirs;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
}
dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
if (!dirs)
return FcFalse;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
set = FcConfigGetFonts (config, FcSetApplication);
if (!set)
{
set = FcFontSetCreate ();
if (!set)
{
FcStrSetDestroy (dirs);
return FcFalse;
}
2002-02-15 00:34:13 +01:00
FcConfigSetFonts (config, set, FcSetApplication);
}
2010-04-12 18:18:50 +02:00
FcStrSetAddFilename (dirs, dir);
2010-04-12 18:18:50 +02:00
if (!FcConfigAddDirList (config, FcSetApplication, dirs))
{
FcStrSetDestroy (dirs);
return FcFalse;
}
FcStrSetDestroy (dirs);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
void
FcConfigAppFontClear (FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return;
}
2002-02-15 00:34:13 +01:00
FcConfigSetFonts (config, 0, FcSetApplication);
}
/*
* Manage filename-based font source selectors
*/
FcBool
FcConfigGlobAdd (FcConfig *config,
const FcChar8 *glob,
FcBool accept)
{
FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
return FcStrSetAdd (set, glob);
}
static FcBool
FcConfigGlobsMatch (const FcStrSet *globs,
const FcChar8 *string)
{
int i;
for (i = 0; i < globs->num; i++)
if (FcStrGlobMatch (globs->strs[i], string))
return FcTrue;
return FcFalse;
}
FcBool
FcConfigAcceptFilename (FcConfig *config,
const FcChar8 *filename)
{
if (FcConfigGlobsMatch (config->acceptGlobs, filename))
return FcTrue;
if (FcConfigGlobsMatch (config->rejectGlobs, filename))
return FcFalse;
return FcTrue;
}
/*
* Manage font-pattern based font source selectors
*/
FcBool
FcConfigPatternsAdd (FcConfig *config,
FcPattern *pattern,
FcBool accept)
{
FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
return FcFontSetAdd (set, pattern);
}
static FcBool
FcConfigPatternsMatch (const FcFontSet *patterns,
const FcPattern *font)
{
int i;
2010-04-12 18:18:50 +02:00
for (i = 0; i < patterns->nfont; i++)
if (FcListPatternMatchAny (patterns->fonts[i], font))
return FcTrue;
return FcFalse;
}
FcBool
FcConfigAcceptFont (FcConfig *config,
const FcPattern *font)
{
if (FcConfigPatternsMatch (config->acceptPatterns, font))
return FcTrue;
if (FcConfigPatternsMatch (config->rejectPatterns, font))
return FcFalse;
return FcTrue;
}
const FcChar8 *
FcConfigGetSysRoot (const FcConfig *config)
{
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return NULL;
}
return config->sysRoot;
}
void
FcConfigSetSysRoot (FcConfig *config,
const FcChar8 *sysroot)
{
FcChar8 *s = NULL;
FcBool init = FcFalse;
if (!config)
{
/* We can't use FcConfigGetCurrent() here to ensure
* the sysroot is set prior to initialize FcConfig,
* to avoid loading caches from non-sysroot dirs.
* So postpone the initialization later.
*/
config = fc_atomic_ptr_get (&_fcConfig);
if (!config)
{
config = FcConfigCreate ();
if (!config)
return;
init = FcTrue;
}
}
if (sysroot)
{
s = FcStrCopyFilename (sysroot);
if (!s)
return;
}
if (config->sysRoot)
FcStrFree (config->sysRoot);
config->sysRoot = s;
if (init)
{
config = FcInitLoadOwnConfigAndFonts (config);
FcConfigSetCurrent (config);
/* FcConfigSetCurrent() increases the refcount.
* decrease it here to avoid the memory leak.
*/
FcConfigDestroy (config);
}
}
#define __fccfg__
#include "fcaliastail.h"
#undef __fccfg__