fontconfig/src/fccfg.c

2117 lines
42 KiB
C
Raw 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.
*/
#include "fcint.h"
#include <dirent.h>
#include <sys/types.h>
2002-02-15 00:34:13 +01:00
2003-06-16 00:45:12 +02:00
#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
#define STRICT
#include <windows.h>
#undef STRICT
#endif
#if defined (_WIN32) && !defined (R_OK)
#define R_OK 4
#endif
FcConfig *_fcConfig;
2002-02-15 00:34:13 +01:00
FcConfig *
FcConfigCreate (void)
{
FcSetName set;
FcConfig *config;
config = malloc (sizeof (FcConfig));
if (!config)
goto bail0;
FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
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
2002-02-15 00:34:13 +01:00
config->blanks = 0;
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;
2008-08-23 00:08:07 +02:00
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);
FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
2002-02-15 00:34:13 +01:00
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->test)
FcTestDestroy (s->test);
if (s->edit)
FcEditDestroy (s->edit);
free (s);
FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
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;
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage));
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;
}
config->ref++;
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
2008-08-23 00:08:07 +02:00
if (--config->ref > 0)
return;
if (config == _fcConfig)
_fcConfig = 0;
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;
FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage));
free (page);
page = next;
}
free (config);
FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
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;
nref++;
FcFontSetAdd (config->fonts[set], font);
}
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)
{
if (config == _fcConfig)
return FcTrue;
2002-02-15 00:34:13 +01:00
if (!config->fonts)
if (!FcConfigBuildFonts (config))
return FcFalse;
if (_fcConfig)
FcConfigDestroy (_fcConfig);
_fcConfig = config;
2002-02-15 00:34:13 +01:00
return FcTrue;
}
FcConfig *
FcConfigGetCurrent (void)
{
if (!_fcConfig)
if (!FcInit ())
return 0;
return _fcConfig;
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 *
2002-02-15 00:34:13 +01:00
FcConfigGetCache (FcConfig *config)
{
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);
}
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
FcBool
FcConfigAddEdit (FcConfig *config,
FcTest *test,
FcEdit *edit,
FcMatchKind kind)
{
FcSubst *subst, **prev;
FcTest *t;
int num;
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;
FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
2002-02-15 00:34:13 +01:00
for (; *prev; prev = &(*prev)->next);
*prev = subst;
subst->next = 0;
subst->test = test;
subst->edit = edit;
num = 0;
for (t = test; t; t = t->next)
{
if (t->kind == FcMatchDefault)
t->kind = kind;
2002-02-15 00:34:13 +01:00
num++;
}
2002-02-15 00:34:13 +01:00
if (config->maxObjects < num)
config->maxObjects = num;
if (FcDebug () & FC_DBG_EDIT)
{
printf ("Add Subst ");
FcSubstPrint (subst);
}
2002-02-15 00:34:13 +01:00
return FcTrue;
}
typedef struct _FcSubState {
FcPatternElt *elt;
FcValueList *value;
} FcSubState;
static FcValue
FcConfigPromote (FcValue v, FcValue u)
{
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 (v.type == FcTypeString && u.type == FcTypeLangSet)
{
v.u.l = FcLangSetPromote (v.u.s);
v.type = FcTypeLangSet;
}
2002-02-15 00:34:13 +01:00
return v;
}
FcBool
FcConfigCompareValue (const FcValue *left_o,
FcOp 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;
2010-04-12 18:18:50 +02:00
left = FcConfigPromote (left, right);
right = FcConfigPromote (right, left);
2010-04-12 18:18:50 +02:00
if (left.type == right.type)
2002-02-15 00:34:13 +01:00
{
switch (left.type) {
2002-02-15 00:34:13 +01:00
case FcTypeInteger:
break; /* FcConfigPromote prevents this from happening */
case FcTypeDouble:
switch (op) {
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:
switch (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:
switch (op) {
2010-04-12 18:18:50 +02:00
case FcOpEqual:
case FcOpListing:
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:
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:
switch (op) {
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:
switch (op) {
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:
switch (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:
switch (op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
2002-02-15 00:34:13 +01:00
ret = FcTrue;
break;
default:
break;
}
break;
case FcTypeFTFace:
switch (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;
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, FcExpr *e)
{
FcValue v, vl, vr;
FcResult r;
FcMatrix *m;
FcChar8 *str;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
switch (e->op) {
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:
v.type = FcTypeMatrix;
v.u.m = e->u.mval;
2002-02-15 00:34:13 +01:00
v = FcValueSave (v);
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;
2002-02-15 00:34:13 +01:00
case FcOpBool:
v.type = FcTypeBool;
v.u.b = e->u.bval;
break;
case FcOpField:
r = FcPatternObjectGet (p, e->u.object, 0, &v);
2002-02-15 00:34:13 +01:00
if (r != FcResultMatch)
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, e->u.tree.left);
if (vl.type == FcTypeBool)
{
if (vl.u.b)
v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
else
v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
}
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, e->u.tree.left);
vr = FcConfigEvaluate (p, 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, e->u.tree.left);
vr = FcConfigEvaluate (p, e->u.tree.right);
vl = FcConfigPromote (vl, vr);
vr = FcConfigPromote (vr, vl);
if (vl.type == vr.type)
{
switch (vl.type) {
case FcTypeDouble:
switch (e->op) {
2010-04-12 18:18:50 +02:00
case FcOpPlus:
2002-02-15 00:34:13 +01:00
v.type = FcTypeDouble;
2010-04-12 18:18:50 +02:00
v.u.d = vl.u.d + vr.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpMinus:
v.type = FcTypeDouble;
2010-04-12 18:18:50 +02:00
v.u.d = vl.u.d - vr.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpTimes:
v.type = FcTypeDouble;
2010-04-12 18:18:50 +02:00
v.u.d = vl.u.d * vr.u.d;
2002-02-15 00:34:13 +01:00
break;
case FcOpDivide:
v.type = FcTypeDouble;
2010-04-12 18:18:50 +02:00
v.u.d = vl.u.d / vr.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:
switch (e->op) {
case FcOpOr:
v.type = FcTypeBool;
v.u.b = vl.u.b || vr.u.b;
break;
case FcOpAnd:
v.type = FcTypeBool;
v.u.b = vl.u.b && vr.u.b;
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:
switch (e->op) {
case FcOpPlus:
v.type = FcTypeString;
str = FcStrPlus (vl.u.s, vr.u.s);
v.u.s = FcSharedStr (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:
switch (e->op) {
case FcOpTimes:
v.type = FcTypeMatrix;
m = malloc (sizeof (FcMatrix));
if (m)
{
FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
FcMatrixMultiply (m, vl.u.m, vr.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:
switch (e->op) {
case FcOpPlus:
v.type = FcTypeCharSet;
v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
if (!v.u.c)
v.type = FcTypeVoid;
break;
case FcOpMinus:
v.type = FcTypeCharSet;
v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
if (!v.u.c)
v.type = FcTypeVoid;
break;
default:
v.type = FcTypeVoid;
break;
}
break;
case FcTypeLangSet:
switch (e->op) {
case FcOpPlus:
v.type = FcTypeLangSet;
v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
if (!v.u.l)
v.type = FcTypeVoid;
break;
case FcOpMinus:
v.type = FcTypeLangSet;
v.u.l = FcLangSetSubtract (vl.u.l, vr.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, e->u.tree.left);
switch (vl.type) {
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, e->u.tree.left);
switch (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, e->u.tree.left);
switch (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, e->u.tree.left);
switch (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, e->u.tree.left);
switch (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,
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 (e->op == FcOpComma)
2002-02-15 00:34:13 +01:00
{
value = FcConfigEvaluate (p, e->u.tree.left);
e = e->u.tree.right;
2002-02-15 00:34:13 +01:00
}
else
{
value = FcConfigEvaluate (p, 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 *
2002-07-31 03:36:37 +02:00
FcConfigValues (FcPattern *p, 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;
FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
if (e->op == FcOpComma)
{
l->value = FcConfigEvaluate (p, e->u.tree.left);
l->next = FcConfigValues (p, e->u.tree.right, binding);
2002-02-15 00:34:13 +01:00
}
else
{
l->value = FcConfigEvaluate (p, 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
FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
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)
{
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, last, v;
FcValueBinding sameBinding;
2010-04-12 18:18:50 +02:00
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);
}
}
/*
* 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
{
FcSubst *s;
FcSubState *st;
int i;
FcTest *t;
FcEdit *e;
FcValueList *l;
FcPattern *m;
2002-02-15 00:34:13 +01:00
if (!config)
{
config = FcConfigGetCurrent ();
if (!config)
return FcFalse;
}
switch (kind) {
case FcMatchPattern:
s = config->substPattern;
break;
case FcMatchFont:
s = config->substFont;
break;
case FcMatchScan:
s = config->substScan;
break;
default:
return FcFalse;
}
2002-02-15 00:34:13 +01:00
st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
if (!st && config->maxObjects)
return FcFalse;
FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute ");
FcPatternPrint (p);
}
for (; s; s = s->next)
{
/*
* Check the tests to see if
* they all match the pattern
*/
for (t = s->test, i = 0; t; t = t->next, i++)
{
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute test ");
FcTestPrint (t);
}
st[i].elt = 0;
if (kind == FcMatchFont && t->kind == FcMatchPattern)
m = p_pat;
else
m = p;
if (m)
st[i].elt = FcPatternObjectFindElt (m, t->object);
else
st[i].elt = 0;
2002-02-15 00:34:13 +01:00
/*
* If there's no such field in the font,
* then FcQualAll matches while FcQualAny does not
*/
if (!st[i].elt)
{
if (t->qual == FcQualAll)
{
st[i].value = 0;
continue;
}
else
break;
}
/*
* Check to see if there is a match, mark the location
* to apply match-relative edits
*/
st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
2002-02-15 00:34:13 +01:00
if (!st[i].value)
break;
if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
break;
if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
break;
2002-02-15 00:34:13 +01:00
}
if (t)
{
if (FcDebug () & FC_DBG_EDIT)
printf ("No match\n");
continue;
}
if (FcDebug () & FC_DBG_EDIT)
{
printf ("Substitute ");
FcSubstPrint (s);
}
for (e = s->edit; e; e = e->next)
{
/*
* Evaluate the list of expressions
*/
2002-07-31 03:36:37 +02:00
l = FcConfigValues (p, e->expr, e->binding);
2002-02-15 00:34:13 +01:00
/*
* Locate any test associated with this field, skipping
* tests associated with the pattern when substituting in
* the font
2002-02-15 00:34:13 +01:00
*/
for (t = s->test, i = 0; t; t = t->next, i++)
{
if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
t->object == e->object)
{
2010-04-12 18:18:50 +02:00
/*
* KLUDGE - the pattern may have been reallocated or
* things may have been inserted or deleted above
* this element by other edits. Go back and find
* the element again
*/
if (e != s->edit && st[i].elt)
st[i].elt = FcPatternObjectFindElt (p, t->object);
if (!st[i].elt)
t = 0;
2002-02-15 00:34:13 +01:00
break;
}
}
2002-02-15 00:34:13 +01:00
switch (e->op) {
case FcOpAssign:
/*
* If there was a test, then replace the matched
* value with the new list of values
*/
if (t)
2002-02-15 00:34:13 +01:00
{
FcValueList *thisValue = st[i].value;
FcValueList *nextValue = thisValue;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
/*
* Append the new list of values after the current value
*/
FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
/*
* Delete the marked value
*/
if (thisValue)
FcConfigDel (&st[i].elt->values, thisValue);
2002-02-15 00:34:13 +01:00
/*
* Adjust any pointers into the value list to ensure
* future edits occur at the same place
*/
for (t = s->test, i = 0; t; t = t->next, i++)
{
if (st[i].value == thisValue)
st[i].value = nextValue;
}
break;
}
/* fall through ... */
case FcOpAssignReplace:
/*
* Delete all of the values and insert
* the new set
*/
FcConfigPatternDel (p, e->object);
FcConfigPatternAdd (p, e->object, l, FcTrue);
2002-02-15 00:34:13 +01:00
/*
* Adjust any pointers into the value list as they no
* longer point to anything valid
*/
if (t)
{
FcPatternElt *thisElt = st[i].elt;
for (t = s->test, i = 0; t; t = t->next, i++)
{
if (st[i].elt == thisElt)
st[i].value = 0;
}
}
break;
case FcOpPrepend:
if (t)
{
FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
break;
}
/* fall through ... */
case FcOpPrependFirst:
FcConfigPatternAdd (p, e->object, l, FcFalse);
2002-02-15 00:34:13 +01:00
break;
case FcOpAppend:
if (t)
{
FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
break;
}
/* fall through ... */
case FcOpAppendLast:
FcConfigPatternAdd (p, e->object, l, FcTrue);
2002-02-15 00:34:13 +01:00
break;
default:
FcValueListDestroy (l);
2002-02-15 00:34:13 +01:00
break;
}
}
/*
* Now go through the pattern and eliminate
* any properties without data
*/
for (e = s->edit; e; e = e->next)
FcConfigPatternCanon (p, e->object);
2002-02-15 00:34:13 +01:00
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute edit");
FcPatternPrint (p);
}
}
FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
free (st);
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute done");
FcPatternPrint (p);
}
return FcTrue;
}
FcBool
FcConfigSubstitute (FcConfig *config,
FcPattern *p,
FcMatchKind kind)
{
return FcConfigSubstituteWithPat (config, p, 0, kind);
}
#if defined (_WIN32)
# define WIN32_LEAN_AND_MEAN
# define WIN32_EXTRA_LEAN
# include <windows.h>
static FcChar8 fontconfig_path[1000] = "";
# if (defined (PIC) || defined (DLL_EXPORT))
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
FcChar8 *p;
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
if (!GetModuleFileName ((HMODULE) hinstDLL, 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.
*/
p = strrchr (fontconfig_path, '\\');
if (p)
{
*p = '\0';
p = strrchr (fontconfig_path, '\\');
if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
FcStrCmpIgnoreCase (p + 1, "lib") == 0))
*p = '\0';
strcat (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;
2002-02-15 00:34:13 +01:00
if (!dir)
dir = (FcChar8 *) "";
size = 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 = (size + 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, "/");
#endif
strcat ((char *) path, (char *) file);
2002-02-15 00:34:13 +01:00
FcMemAlloc (FC_MEM_STRING, size);
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;
if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
goto bail1;
2008-08-12 20:10:03 +02:00
p = strrchr (fontconfig_path, '\\');
if (p) *p = '\0';
strcat (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);
}
static FcBool _FcConfigHomeEnabled = FcTrue;
FcChar8 *
FcConfigHome (void)
{
if (_FcConfigHomeEnabled)
{
char *home = getenv ("HOME");
#ifdef _WIN32
if (home == NULL)
home = getenv ("USERPROFILE");
#endif
return (FcChar8 *) home;
}
return 0;
}
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 0;
for (p = path; *p; p++)
{
file = FcConfigFileExists (*p, url);
if (file)
break;
}
FcConfigFreePath (path);
break;
}
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 = FcStrSetCreate ();
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 = FcStrSetCreate ();
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);
2002-02-15 00:34:13 +01:00
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
FcConfigGlobMatch (const FcChar8 *glob,
const FcChar8 *string)
{
FcChar8 c;
2010-04-12 18:18:50 +02:00
while ((c = *glob++))
{
switch (c) {
case '*':
/* short circuit common case */
if (!*glob)
return FcTrue;
/* short circuit another common case */
if (strchr ((char *) glob, '*') == 0)
{
size_t l1, l2;
l1 = strlen ((char *) string);
l2 = strlen ((char *) glob);
if (l1 < l2)
return FcFalse;
string += (l1 - l2);
}
while (*string)
{
if (FcConfigGlobMatch (glob, string))
return FcTrue;
string++;
}
return FcFalse;
case '?':
if (*string++ == '\0')
return FcFalse;
break;
default:
if (*string++ != c)
return FcFalse;
break;
}
}
return *string == '\0';
}
static FcBool
FcConfigGlobsMatch (const FcStrSet *globs,
const FcChar8 *string)
{
int i;
for (i = 0; i < globs->num; i++)
if (FcConfigGlobMatch (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;
}
#define __fccfg__
#include "fcaliastail.h"
#undef __fccfg__