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
|
2010-11-10 22:45:42 +01:00
|
|
|
* 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
|
2010-11-10 22:45:42 +01:00
|
|
|
* 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.
|
|
|
|
*
|
2009-03-12 21:00:08 +01:00
|
|
|
* 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
|
2009-03-12 21:00:08 +01:00
|
|
|
* 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. */
|
|
|
|
|
2006-04-25 07:57:41 +02:00
|
|
|
#include "fcint.h"
|
2020-07-18 18:21:09 +02:00
|
|
|
#ifdef HAVE_DIRENT_H
|
2006-01-26 17:09:12 +01:00
|
|
|
#include <dirent.h>
|
2020-07-18 18:21:09 +02:00
|
|
|
#endif
|
2006-01-26 17:09:12 +01:00
|
|
|
#include <sys/types.h>
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2003-06-14 01:04:35 +02:00
|
|
|
#if defined (_WIN32) && !defined (R_OK)
|
|
|
|
#define R_OK 4
|
|
|
|
#endif
|
|
|
|
|
2020-06-25 19:38:48 +02:00
|
|
|
#if defined(_WIN32) && !defined(S_ISFIFO)
|
|
|
|
#define S_ISFIFO(m) 0
|
|
|
|
#endif
|
|
|
|
|
2012-10-07 23:02:50 +02:00
|
|
|
static FcConfig *_fcConfig; /* MT-safe */
|
2019-11-01 16:14:48 +01:00
|
|
|
static FcMutex *_lock;
|
|
|
|
|
|
|
|
static void
|
|
|
|
lock_config (void)
|
|
|
|
{
|
|
|
|
FcMutex *lock;
|
|
|
|
retry:
|
|
|
|
lock = fc_atomic_ptr_get (&_lock);
|
|
|
|
if (!lock)
|
|
|
|
{
|
|
|
|
lock = (FcMutex *) malloc (sizeof (FcMutex));
|
|
|
|
FcMutexInit (lock);
|
|
|
|
if (!fc_atomic_ptr_cmpexch (&_lock, NULL, lock))
|
|
|
|
{
|
|
|
|
FcMutexFinish (lock);
|
2021-01-13 14:25:59 +01:00
|
|
|
free (lock);
|
2019-11-01 16:14:48 +01:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
FcMutexLock (lock);
|
|
|
|
/* Initialize random state */
|
|
|
|
FcRandom ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
FcMutexLock (lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unlock_config (void)
|
|
|
|
{
|
2020-10-30 03:29:00 +01:00
|
|
|
FcMutex *lock;
|
|
|
|
lock = fc_atomic_ptr_get (&_lock);
|
|
|
|
FcMutexUnlock (lock);
|
2019-11-01 16:14:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_lock (void)
|
|
|
|
{
|
|
|
|
FcMutex *lock;
|
|
|
|
lock = fc_atomic_ptr_get (&_lock);
|
|
|
|
if (lock && fc_atomic_ptr_cmpexch (&_lock, lock, NULL))
|
|
|
|
{
|
|
|
|
FcMutexFinish (lock);
|
|
|
|
free (lock);
|
|
|
|
}
|
|
|
|
}
|
2012-10-07 22:37:03 +02:00
|
|
|
|
2012-10-07 23:02:50 +02:00
|
|
|
static FcConfig *
|
|
|
|
FcConfigEnsure (void)
|
2012-10-07 22:37:03 +02:00
|
|
|
{
|
|
|
|
FcConfig *config;
|
2018-03-15 04:17:52 +01:00
|
|
|
retry:
|
2012-10-07 23:02:50 +02:00
|
|
|
config = fc_atomic_ptr_get (&_fcConfig);
|
2012-10-07 22:37:03 +02:00
|
|
|
if (!config)
|
2012-10-07 23:02:50 +02:00
|
|
|
{
|
|
|
|
config = FcInitLoadConfigAndFonts ();
|
|
|
|
|
2019-11-01 16:14:48 +01:00
|
|
|
if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
|
|
|
|
if (config)
|
|
|
|
FcConfigDestroy (config);
|
2018-03-15 04:17:52 +01:00
|
|
|
goto retry;
|
2012-10-07 23:02:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2018-06-08 21:31:15 +02:00
|
|
|
static void
|
|
|
|
FcDestroyAsRule (void *data)
|
|
|
|
{
|
|
|
|
FcRuleDestroy (data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FcDestroyAsRuleSet (void *data)
|
|
|
|
{
|
|
|
|
FcRuleSetDestroy (data);
|
|
|
|
}
|
|
|
|
|
2012-10-07 23:02:50 +02:00
|
|
|
FcBool
|
|
|
|
FcConfigInit (void)
|
|
|
|
{
|
|
|
|
return FcConfigEnsure () ? FcTrue : FcFalse;
|
2012-10-07 22:37:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-11-01 16:14:48 +01:00
|
|
|
free_lock ();
|
2012-10-07 22:37:03 +02:00
|
|
|
}
|
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
FcConfig *
|
|
|
|
FcConfigCreate (void)
|
|
|
|
{
|
|
|
|
FcSetName set;
|
|
|
|
FcConfig *config;
|
2014-03-27 07:10:44 +01:00
|
|
|
FcMatchKind k;
|
|
|
|
FcBool err = FcFalse;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
|
|
|
config = malloc (sizeof (FcConfig));
|
|
|
|
if (!config)
|
|
|
|
goto bail0;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2002-05-21 19:06:22 +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
|
|
|
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
config->configMapDirs = FcStrSetCreate();
|
|
|
|
if (!config->configMapDirs)
|
|
|
|
goto bail1_5;
|
|
|
|
|
2002-05-21 19:06:22 +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
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
config->fontDirs = FcStrSetCreate ();
|
|
|
|
if (!config->fontDirs)
|
|
|
|
goto bail3;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2003-05-07 18:13:24 +02:00
|
|
|
config->acceptGlobs = FcStrSetCreate ();
|
|
|
|
if (!config->acceptGlobs)
|
|
|
|
goto bail4;
|
|
|
|
|
|
|
|
config->rejectGlobs = FcStrSetCreate ();
|
|
|
|
if (!config->rejectGlobs)
|
|
|
|
goto bail5;
|
|
|
|
|
2004-12-04 20:41:10 +01:00
|
|
|
config->acceptPatterns = FcFontSetCreate ();
|
|
|
|
if (!config->acceptPatterns)
|
|
|
|
goto bail6;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2004-12-04 20:41:10 +01:00
|
|
|
config->rejectPatterns = FcFontSetCreate ();
|
|
|
|
if (!config->rejectPatterns)
|
|
|
|
goto bail7;
|
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
config->cacheDirs = FcStrSetCreate ();
|
|
|
|
if (!config->cacheDirs)
|
2006-08-31 06:59:53 +02:00
|
|
|
goto bail8;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
|
|
|
|
{
|
2018-06-08 21:31:15 +02:00
|
|
|
config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet);
|
2014-03-27 07:10:44 +01:00
|
|
|
if (!config->subst[k])
|
|
|
|
err = FcTrue;
|
|
|
|
}
|
|
|
|
if (err)
|
|
|
|
goto bail9;
|
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
config->maxObjects = 0;
|
|
|
|
for (set = FcSetSystem; set <= FcSetApplication; set++)
|
|
|
|
config->fonts[set] = 0;
|
2002-05-21 19:06:22 +02:00
|
|
|
|
|
|
|
config->rescanTime = time(0);
|
2010-04-12 18:18:50 +02:00
|
|
|
config->rescanInterval = 30;
|
2008-08-23 00:08:07 +02:00
|
|
|
|
2009-06-06 04:32:31 +02:00
|
|
|
config->expr_pool = NULL;
|
|
|
|
|
2021-10-11 11:35:58 +02:00
|
|
|
config->sysRoot = FcStrRealPath ((const FcChar8 *) getenv("FONTCONFIG_SYSROOT"));
|
2013-02-06 11:35:30 +01:00
|
|
|
|
2018-06-08 21:31:15 +02:00
|
|
|
config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet);
|
2014-03-27 07:10:44 +01:00
|
|
|
if (!config->rulesetList)
|
|
|
|
goto bail9;
|
|
|
|
config->availConfigFiles = FcStrSetCreate ();
|
|
|
|
if (!config->availConfigFiles)
|
|
|
|
goto bail10;
|
|
|
|
|
2012-10-07 20:41:38 +02:00
|
|
|
FcRefInit (&config->ref, 1);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
return config;
|
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
bail10:
|
|
|
|
FcPtrListDestroy (config->rulesetList);
|
|
|
|
bail9:
|
|
|
|
for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
|
|
|
|
if (config->subst[k])
|
|
|
|
FcPtrListDestroy (config->subst[k]);
|
|
|
|
FcStrSetDestroy (config->cacheDirs);
|
2004-12-04 20:41:10 +01:00
|
|
|
bail8:
|
|
|
|
FcFontSetDestroy (config->rejectPatterns);
|
|
|
|
bail7:
|
|
|
|
FcFontSetDestroy (config->acceptPatterns);
|
2003-05-07 18:13:24 +02:00
|
|
|
bail6:
|
|
|
|
FcStrSetDestroy (config->rejectGlobs);
|
|
|
|
bail5:
|
|
|
|
FcStrSetDestroy (config->acceptGlobs);
|
2002-05-21 19:06:22 +02:00
|
|
|
bail4:
|
|
|
|
FcStrSetDestroy (config->fontDirs);
|
2002-02-15 00:34:13 +01:00
|
|
|
bail3:
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrSetDestroy (config->configFiles);
|
2002-02-15 00:34:13 +01:00
|
|
|
bail2:
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
FcStrSetDestroy (config->configMapDirs);
|
|
|
|
bail1_5:
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrSetDestroy (config->configDirs);
|
2002-02-15 00:34:13 +01:00
|
|
|
bail1:
|
|
|
|
free (config);
|
|
|
|
bail0:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-21 08:14:45 +02:00
|
|
|
static FcFileTime
|
2002-05-21 19:06:22 +02:00
|
|
|
FcConfigNewestFile (FcStrSet *files)
|
|
|
|
{
|
|
|
|
FcStrList *list = FcStrListCreate (files);
|
2002-06-21 08:14:45 +02:00
|
|
|
FcFileTime newest = { 0, FcFalse };
|
2002-05-21 19:06:22 +02:00
|
|
|
FcChar8 *file;
|
|
|
|
struct stat statb;
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
while ((file = FcStrListNext (list)))
|
2011-03-14 22:49:21 +01:00
|
|
|
if (FcStat (file, &statb) == 0)
|
2002-06-21 08:14:45 +02:00
|
|
|
if (!newest.set || statb.st_mtime - newest.time > 0)
|
2004-02-07 08:13:48 +01:00
|
|
|
{
|
|
|
|
newest.set = FcTrue;
|
2002-06-21 08:14:45 +02:00
|
|
|
newest.time = statb.st_mtime;
|
2004-02-07 08:13:48 +01:00
|
|
|
}
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrListDone (list);
|
|
|
|
}
|
|
|
|
return newest;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigUptoDate (FcConfig *config)
|
|
|
|
{
|
2007-10-26 06:23:36 +02:00
|
|
|
FcFileTime config_time, config_dir_time, font_time;
|
2002-06-21 08:14:45 +02:00
|
|
|
time_t now = time(0);
|
2019-11-01 06:43:42 +01:00
|
|
|
FcBool ret = FcTrue;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
2002-05-21 19:06:22 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return FcFalse;
|
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
config_time = FcConfigNewestFile (config->configFiles);
|
2007-10-26 06:23:36 +02:00
|
|
|
config_dir_time = FcConfigNewestFile (config->configDirs);
|
2004-06-30 20:41:52 +02:00
|
|
|
font_time = FcConfigNewestFile (config->fontDirs);
|
2002-06-21 08:14:45 +02:00
|
|
|
if ((config_time.set && config_time.time - config->rescanTime > 0) ||
|
2007-10-26 06:23:36 +02:00
|
|
|
(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
|
2004-06-30 20:41:52 +02:00
|
|
|
(font_time.set && (font_time.time - config->rescanTime) > 0))
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
2008-05-25 01:15:27 +02:00
|
|
|
/* 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,
|
2013-01-01 03:11:12 +01:00
|
|
|
"Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
|
2008-05-25 01:15:27 +02:00
|
|
|
config->rescanTime = now;
|
2019-11-01 06:43:42 +01:00
|
|
|
goto bail;
|
2008-05-25 01:15:27 +02:00
|
|
|
}
|
|
|
|
else
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
|
|
|
config->rescanTime = now;
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
|
|
|
|
2009-06-06 04:32:31 +02:00
|
|
|
FcExpr *
|
|
|
|
FcConfigAllocExpr (FcConfig *config)
|
|
|
|
{
|
2013-06-28 08:54:38 +02:00
|
|
|
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;
|
|
|
|
}
|
2009-06-06 04:32:31 +02:00
|
|
|
|
2013-07-04 12:51:03 +02:00
|
|
|
return config->expr_pool->next++;
|
2009-06-06 04:32:31 +02:00
|
|
|
}
|
|
|
|
|
2008-08-23 00:08:07 +02:00
|
|
|
FcConfig *
|
|
|
|
FcConfigReference (FcConfig *config)
|
|
|
|
{
|
|
|
|
if (!config)
|
|
|
|
{
|
2019-11-01 16:14:48 +01:00
|
|
|
/* lock during obtaining the value from _fcConfig and count up refcount there,
|
|
|
|
* there are the race between them.
|
2019-11-01 06:43:42 +01:00
|
|
|
*/
|
2019-11-01 16:14:48 +01:00
|
|
|
lock_config ();
|
2019-11-01 06:43:42 +01:00
|
|
|
retry:
|
|
|
|
config = fc_atomic_ptr_get (&_fcConfig);
|
2008-08-23 00:08:07 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
2019-11-01 16:14:48 +01:00
|
|
|
unlock_config ();
|
2008-08-23 00:08:07 +02:00
|
|
|
|
2019-11-01 16:14:48 +01:00
|
|
|
config = FcInitLoadConfigAndFonts ();
|
|
|
|
if (!config)
|
|
|
|
goto retry;
|
|
|
|
lock_config ();
|
2019-11-01 06:43:42 +01:00
|
|
|
if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
|
|
|
|
{
|
2019-11-01 16:14:48 +01:00
|
|
|
FcConfigDestroy (config);
|
2019-11-01 06:43:42 +01:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
2019-11-01 16:14:48 +01:00
|
|
|
FcRefInc (&config->ref);
|
|
|
|
unlock_config ();
|
2019-11-01 06:43:42 +01:00
|
|
|
}
|
2019-11-01 16:14:48 +01:00
|
|
|
else
|
|
|
|
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;
|
2009-06-06 04:32:31 +02:00
|
|
|
FcExprPage *page;
|
2014-03-27 07:10:44 +01:00
|
|
|
FcMatchKind k;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2022-12-05 13:40:26 +01:00
|
|
|
if (config)
|
|
|
|
{
|
|
|
|
if (FcRefDec (&config->ref) != 1)
|
|
|
|
return;
|
2008-08-23 00:08:07 +02:00
|
|
|
|
2022-12-05 13:40:26 +01:00
|
|
|
(void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
|
2002-05-21 19:06:22 +02:00
|
|
|
|
2022-12-05 13:40:26 +01:00
|
|
|
FcStrSetDestroy (config->configDirs);
|
|
|
|
FcStrSetDestroy (config->configMapDirs);
|
|
|
|
FcStrSetDestroy (config->fontDirs);
|
|
|
|
FcStrSetDestroy (config->cacheDirs);
|
|
|
|
FcStrSetDestroy (config->configFiles);
|
|
|
|
FcStrSetDestroy (config->acceptGlobs);
|
|
|
|
FcStrSetDestroy (config->rejectGlobs);
|
|
|
|
FcFontSetDestroy (config->acceptPatterns);
|
|
|
|
FcFontSetDestroy (config->rejectPatterns);
|
2002-05-21 19:06:22 +02:00
|
|
|
|
2022-12-05 13:40:26 +01:00
|
|
|
for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
|
|
|
|
FcPtrListDestroy (config->subst[k]);
|
|
|
|
FcPtrListDestroy (config->rulesetList);
|
|
|
|
FcStrSetDestroy (config->availConfigFiles);
|
|
|
|
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)
|
2013-02-06 11:35:30 +01:00
|
|
|
FcStrFree (config->sysRoot);
|
2009-06-06 04:32:31 +02:00
|
|
|
|
2022-12-05 13:40:26 +01:00
|
|
|
free (config);
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-09-01 10:15:14 +02: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,
|
2018-05-23 15:15:33 +02:00
|
|
|
FcSetName set, FcStrSet *dirSet, FcChar8 *forDir)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
FcFontSet *fs;
|
|
|
|
intptr_t *dirs;
|
|
|
|
int i;
|
2018-05-23 15:15:33 +02:00
|
|
|
FcBool relocated = FcFalse;
|
|
|
|
|
|
|
|
if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0)
|
|
|
|
relocated = FcTrue;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
|
|
|
* Add fonts
|
|
|
|
*/
|
|
|
|
fs = FcCacheSet (cache);
|
|
|
|
if (fs)
|
2005-08-24 08:21:30 +02:00
|
|
|
{
|
2006-09-05 07:26:24 +02:00
|
|
|
int nref = 0;
|
2022-12-05 13:40:26 +01:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
for (i = 0; i < fs->nfont; i++)
|
2005-08-24 08:21:30 +02:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
FcPattern *font = FcFontSetFont (fs, i);
|
|
|
|
FcChar8 *font_file;
|
2018-05-23 15:15:33 +02:00
|
|
|
FcChar8 *relocated_font_file = NULL;
|
2006-09-01 10:15:14 +02:00
|
|
|
|
|
|
|
if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
|
2018-05-23 15:15:33 +02:00
|
|
|
0, &font_file) == FcResultMatch)
|
2006-09-01 10:15:14 +02:00
|
|
|
{
|
2018-05-23 15:15:33 +02:00
|
|
|
if (relocated)
|
|
|
|
{
|
|
|
|
FcChar8 *slash = FcStrLastSlash (font_file);
|
|
|
|
relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL);
|
|
|
|
font_file = relocated_font_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if font is banned by filename
|
|
|
|
*/
|
|
|
|
if (!FcConfigAcceptFilename (config, font_file))
|
|
|
|
{
|
|
|
|
free (relocated_font_file);
|
|
|
|
continue;
|
|
|
|
}
|
2006-09-01 10:15:14 +02:00
|
|
|
}
|
2018-05-23 15:15:33 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
|
|
|
* Check to see if font is banned by pattern
|
|
|
|
*/
|
|
|
|
if (!FcConfigAcceptFont (config, font))
|
2018-05-23 15:15:33 +02:00
|
|
|
{
|
|
|
|
free (relocated_font_file);
|
2006-09-01 10:15:14 +02:00
|
|
|
continue;
|
2018-05-23 15:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (relocated_font_file)
|
|
|
|
{
|
|
|
|
font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
|
|
|
|
free (relocated_font_file);
|
|
|
|
}
|
|
|
|
|
2013-01-16 14:30:44 +01:00
|
|
|
if (FcFontSetAdd (config->fonts[set], font))
|
|
|
|
nref++;
|
2005-08-24 08:21:30 +02:00
|
|
|
}
|
2006-09-05 07:26:24 +02:00
|
|
|
FcDirCacheReference (cache, nref);
|
2005-08-24 08:21:30 +02:00
|
|
|
}
|
2006-09-01 10:15:14 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add directories
|
|
|
|
*/
|
|
|
|
dirs = FcCacheDirs (cache);
|
|
|
|
if (dirs)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
for (i = 0; i < cache->dirs_count; i++)
|
|
|
|
{
|
2017-09-23 11:49:55 +02:00
|
|
|
const FcChar8 *dir = FcCacheSubdir (cache, i);
|
|
|
|
FcChar8 *s = NULL;
|
|
|
|
|
2018-05-23 16:00:01 +02:00
|
|
|
if (relocated)
|
2017-09-23 11:49:55 +02:00
|
|
|
{
|
2017-10-02 14:17:06 +02:00
|
|
|
FcChar8 *base = FcStrBasename (dir);
|
2018-05-23 16:00:01 +02:00
|
|
|
dir = s = FcStrBuildFilename (forDir, base, NULL);
|
2017-10-02 14:17:06 +02:00
|
|
|
FcStrFree (base);
|
2017-09-23 11:49:55 +02:00
|
|
|
}
|
2006-09-01 10:15:14 +02:00
|
|
|
if (FcConfigAcceptFilename (config, dir))
|
2006-09-15 09:23:40 +02:00
|
|
|
FcStrSetAddFilename (dirSet, dir);
|
2017-09-23 11:49:55 +02:00
|
|
|
if (s)
|
|
|
|
FcStrFree (s);
|
2005-09-03 06:56:56 +02:00
|
|
|
}
|
2006-09-01 10:15:14 +02:00
|
|
|
}
|
|
|
|
return FcTrue;
|
|
|
|
}
|
2005-09-03 06:56:56 +02:00
|
|
|
|
2006-09-15 09:23:40 +02:00
|
|
|
static FcBool
|
|
|
|
FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
|
|
|
|
{
|
|
|
|
FcStrList *dirlist;
|
|
|
|
FcChar8 *dir;
|
|
|
|
FcCache *cache;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-15 09:23:40 +02:00
|
|
|
dirlist = FcStrListCreate (dirSet);
|
|
|
|
if (!dirlist)
|
|
|
|
return FcFalse;
|
2022-12-05 13:40:26 +01:00
|
|
|
|
2006-09-15 09:23:40 +02:00
|
|
|
while ((dir = FcStrListNext (dirlist)))
|
|
|
|
{
|
|
|
|
if (FcDebug () & FC_DBG_FONTSET)
|
2014-06-17 13:08:24 +02:00
|
|
|
printf ("adding fonts from %s\n", dir);
|
2006-09-15 09:23:40 +02:00
|
|
|
cache = FcDirCacheRead (dir, FcFalse, config);
|
|
|
|
if (!cache)
|
|
|
|
continue;
|
2018-05-23 15:15:33 +02:00
|
|
|
FcConfigAddCache (config, cache, set, dirSet, dir);
|
2006-09-15 09:23:40 +02:00
|
|
|
FcDirCacheUnload (cache);
|
|
|
|
}
|
|
|
|
FcStrListDone (dirlist);
|
2015-06-27 02:02:13 +02:00
|
|
|
return FcTrue;
|
2006-09-15 09:23:40 +02:00
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
|
|
|
* Scan the current list of directories in the configuration
|
|
|
|
* and build the set of available fonts.
|
|
|
|
*/
|
2005-11-29 01:21:05 +01:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
FcBool
|
|
|
|
FcConfigBuildFonts (FcConfig *config)
|
|
|
|
{
|
|
|
|
FcFontSet *fonts;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcBool ret = FcTrue;
|
2005-08-25 09:38:02 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
2006-09-01 10:15:14 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return FcFalse;
|
2022-12-05 13:40:26 +01:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
fonts = FcFontSetCreate ();
|
|
|
|
if (!fonts)
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
FcConfigSetFonts (config, fonts, FcSetSystem);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-15 09:23:40 +02:00
|
|
|
if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
if (FcDebug () & FC_DBG_FONTSET)
|
|
|
|
FcFontSetPrint (fonts);
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigSetCurrent (FcConfig *config)
|
|
|
|
{
|
2012-10-07 23:02:50 +02:00
|
|
|
FcConfig *cfg;
|
|
|
|
|
2019-11-01 16:14:48 +01:00
|
|
|
if (config)
|
|
|
|
{
|
|
|
|
if (!config->fonts[FcSetSystem])
|
|
|
|
if (!FcConfigBuildFonts (config))
|
|
|
|
return FcFalse;
|
|
|
|
FcRefInc (&config->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
lock_config ();
|
2012-10-07 23:02:50 +02:00
|
|
|
retry:
|
|
|
|
cfg = fc_atomic_ptr_get (&_fcConfig);
|
|
|
|
|
|
|
|
if (config == cfg)
|
2019-11-01 16:14:48 +01:00
|
|
|
{
|
|
|
|
unlock_config ();
|
|
|
|
if (config)
|
|
|
|
FcConfigDestroy (config);
|
2007-11-04 06:45:31 +01:00
|
|
|
return FcTrue;
|
2019-11-01 16:14:48 +01:00
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2012-10-07 23:02:50 +02:00
|
|
|
if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
|
|
|
|
goto retry;
|
2019-11-01 16:14:48 +01:00
|
|
|
unlock_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
|
2002-05-21 19:06:22 +02:00
|
|
|
FcConfigAddConfigDir (FcConfig *config,
|
|
|
|
const FcChar8 *d)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-05-21 19:06:22 +02:00
|
|
|
return FcStrSetAddFilename (config->configDirs, d);
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrList *
|
|
|
|
FcConfigGetConfigDirs (FcConfig *config)
|
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
FcStrList *ret;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
2002-05-21 19:06:22 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return NULL;
|
|
|
|
ret = FcStrListCreate (config->configDirs);
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigAddFontDir (FcConfig *config,
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
const FcChar8 *d,
|
2019-01-31 11:17:47 +01:00
|
|
|
const FcChar8 *m,
|
|
|
|
const FcChar8 *salt)
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
2019-04-02 12:00:17 +02:00
|
|
|
if (FcDebug() & FC_DBG_CACHE)
|
|
|
|
{
|
|
|
|
if (m)
|
|
|
|
{
|
2019-04-04 07:04:17 +02:00
|
|
|
printf ("%s -> %s%s%s%s\n", d, m, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : "");
|
2019-04-02 12:00:17 +02:00
|
|
|
}
|
|
|
|
else if (salt)
|
|
|
|
{
|
2019-04-04 07:04:17 +02:00
|
|
|
printf ("%s%s%s%s\n", d, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : "");
|
2019-04-02 12:00:17 +02:00
|
|
|
}
|
|
|
|
}
|
2019-01-31 11:17:47 +01:00
|
|
|
return FcStrSetAddFilenamePairWithSalt (config->fontDirs, d, m, salt);
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
2019-01-31 08:52:09 +01:00
|
|
|
FcBool
|
|
|
|
FcConfigResetFontDirs (FcConfig *config)
|
|
|
|
{
|
2019-04-02 12:00:17 +02:00
|
|
|
if (FcDebug() & FC_DBG_CACHE)
|
|
|
|
{
|
|
|
|
printf ("Reset font directories!\n");
|
|
|
|
}
|
2019-01-31 08:52:09 +01:00
|
|
|
return FcStrSetDeleteAll (config->fontDirs);
|
|
|
|
}
|
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrList *
|
|
|
|
FcConfigGetFontDirs (FcConfig *config)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
FcStrList *ret;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return NULL;
|
|
|
|
ret = FcStrListCreate (config->fontDirs);
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
static FcBool
|
|
|
|
FcConfigPathStartsWith(const FcChar8 *path,
|
|
|
|
const FcChar8 *start)
|
|
|
|
{
|
|
|
|
int len = strlen((char *) start);
|
|
|
|
|
|
|
|
if (strncmp((char *) path, (char *) start, len) != 0)
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
switch (path[len]) {
|
|
|
|
case '\0':
|
|
|
|
case FC_DIR_SEPARATOR:
|
|
|
|
return FcTrue;
|
|
|
|
default:
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FcChar8 *
|
|
|
|
FcConfigMapFontPath(FcConfig *config,
|
|
|
|
const FcChar8 *path)
|
|
|
|
{
|
|
|
|
FcStrList *list;
|
|
|
|
FcChar8 *dir;
|
2019-04-04 08:47:34 +02:00
|
|
|
const FcChar8 *map, *rpath;
|
2019-01-29 08:02:37 +01:00
|
|
|
FcChar8 *retval;
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
|
|
|
|
list = FcConfigGetFontDirs(config);
|
|
|
|
if (!list)
|
|
|
|
return 0;
|
|
|
|
while ((dir = FcStrListNext(list)))
|
|
|
|
if (FcConfigPathStartsWith(path, dir))
|
|
|
|
break;
|
|
|
|
FcStrListDone(list);
|
|
|
|
if (!dir)
|
|
|
|
return 0;
|
2019-01-31 11:17:47 +01:00
|
|
|
map = FcStrTripleSecond(dir);
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
if (!map)
|
|
|
|
return 0;
|
2019-04-04 08:47:34 +02:00
|
|
|
rpath = path + strlen ((char *) dir);
|
|
|
|
while (*rpath == '/')
|
|
|
|
rpath++;
|
|
|
|
retval = FcStrBuildFilename(map, rpath, NULL);
|
2019-01-29 08:02:37 +01:00
|
|
|
if (retval)
|
|
|
|
{
|
|
|
|
size_t len = strlen ((const char *) retval);
|
2019-04-04 08:47:34 +02:00
|
|
|
while (len > 0 && retval[len-1] == '/')
|
|
|
|
len--;
|
|
|
|
/* trim the last slash */
|
|
|
|
retval[len] = 0;
|
2019-01-29 08:02:37 +01:00
|
|
|
}
|
|
|
|
return retval;
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
}
|
|
|
|
|
2019-01-31 11:17:47 +01:00
|
|
|
const FcChar8 *
|
|
|
|
FcConfigMapSalt (FcConfig *config,
|
|
|
|
const FcChar8 *path)
|
|
|
|
{
|
|
|
|
FcStrList *list;
|
|
|
|
FcChar8 *dir;
|
|
|
|
|
|
|
|
list = FcConfigGetFontDirs (config);
|
|
|
|
if (!list)
|
|
|
|
return NULL;
|
|
|
|
while ((dir = FcStrListNext (list)))
|
|
|
|
if (FcConfigPathStartsWith (path, dir))
|
|
|
|
break;
|
|
|
|
FcStrListDone (list);
|
|
|
|
if (!dir)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return FcStrTripleThird (dir);
|
|
|
|
}
|
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
FcBool
|
|
|
|
FcConfigAddCacheDir (FcConfig *config,
|
|
|
|
const FcChar8 *d)
|
|
|
|
{
|
|
|
|
return FcStrSetAddFilename (config->cacheDirs, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
FcStrList *
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfigGetCacheDirs (FcConfig *config)
|
2006-08-04 18:13:00 +02:00
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
FcStrList *ret;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
2006-08-04 18:13:00 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return NULL;
|
|
|
|
ret = FcStrListCreate (config->cacheDirs);
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2006-08-04 18:13:00 +02:00
|
|
|
}
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
FcBool
|
|
|
|
FcConfigAddConfigFile (FcConfig *config,
|
2002-02-15 07:01:28 +01:00
|
|
|
const FcChar8 *f)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-05-21 19:06:22 +02:00
|
|
|
FcBool ret;
|
2019-10-21 09:17:42 +02:00
|
|
|
FcChar8 *file = FcConfigGetFilename (config, 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
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
ret = FcStrSetAdd (config->configFiles, file);
|
|
|
|
FcStrFree (file);
|
|
|
|
return ret;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrList *
|
2002-02-15 00:34:13 +01:00
|
|
|
FcConfigGetConfigFiles (FcConfig *config)
|
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
FcStrList *ret;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return NULL;
|
|
|
|
ret = FcStrListCreate (config->configFiles);
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
2002-02-15 07:01:28 +01:00
|
|
|
FcChar8 *
|
2012-12-30 04:32:56 +01:00
|
|
|
FcConfigGetCache (FcConfig *config FC_UNUSED)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-08-31 06:59:53 +02: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;
|
|
|
|
}
|
|
|
|
|
2017-08-04 17:31:52 +02:00
|
|
|
|
|
|
|
FcBlanks *
|
|
|
|
FcBlanksCreate (void)
|
|
|
|
{
|
|
|
|
/* Deprecated. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-08-04 17:36:12 +02:00
|
|
|
FcBlanksDestroy (FcBlanks *b FC_UNUSED)
|
2017-08-04 17:31:52 +02:00
|
|
|
{
|
|
|
|
/* Deprecated. */
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
2017-08-04 17:36:12 +02:00
|
|
|
FcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
|
2017-08-04 17:31:52 +02:00
|
|
|
{
|
|
|
|
/* Deprecated. */
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
2017-08-04 17:36:12 +02:00
|
|
|
FcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
|
2017-08-04 17:31:52 +02:00
|
|
|
{
|
|
|
|
/* Deprecated. */
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
FcBlanks *
|
2017-08-04 17:36:12 +02:00
|
|
|
FcConfigGetBlanks (FcConfig *config FC_UNUSED)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2017-08-04 17:31:52 +02:00
|
|
|
/* Deprecated. */
|
|
|
|
return NULL;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
2017-08-04 17:36:12 +02:00
|
|
|
FcConfigAddBlank (FcConfig *config FC_UNUSED,
|
|
|
|
FcChar32 blank FC_UNUSED)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2017-08-04 17:31:52 +02:00
|
|
|
/* Deprecated. */
|
|
|
|
return FcFalse;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
2017-08-04 17:31:52 +02:00
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
int
|
2007-11-04 05:56:36 +01:00
|
|
|
FcConfigGetRescanInterval (FcConfig *config)
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
2002-05-21 19:06:22 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return 0;
|
|
|
|
ret = config->rescanInterval;
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
2007-11-04 05:56:36 +01:00
|
|
|
FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
2002-05-21 19:06:22 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return FcFalse;
|
2002-05-21 19:06:22 +02:00
|
|
|
config->rescanInterval = rescanInterval;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
2007-11-04 21:20:45 +01:00
|
|
|
/*
|
|
|
|
* 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
|
2013-07-04 12:51:03 +02:00
|
|
|
FcConfigAddRule (FcConfig *config,
|
|
|
|
FcRule *rule,
|
2002-02-15 00:34:13 +01:00
|
|
|
FcMatchKind kind)
|
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
/* deprecated */
|
|
|
|
return FcFalse;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static FcValue
|
2012-10-07 20:41:38 +02:00
|
|
|
FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2020-08-21 05:45:19 +02:00
|
|
|
switch (v.type)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2020-08-21 05:45:19 +02:00
|
|
|
case FcTypeInteger:
|
|
|
|
v.type = FcTypeDouble;
|
|
|
|
v.u.d = (double) v.u.i;
|
2020-08-22 08:35:24 +02:00
|
|
|
/* Fallthrough */
|
|
|
|
case FcTypeDouble:
|
|
|
|
if (u.type == FcTypeRange && buf)
|
|
|
|
{
|
|
|
|
v.u.r = FcRangePromote (v.u.d, buf);
|
|
|
|
v.type = FcTypeRange;
|
|
|
|
}
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcTypeVoid:
|
|
|
|
if (u.type == FcTypeMatrix)
|
|
|
|
{
|
|
|
|
v.u.m = &FcIdentityMatrix;
|
|
|
|
v.type = FcTypeMatrix;
|
|
|
|
}
|
|
|
|
else if (u.type == FcTypeLangSet && buf)
|
|
|
|
{
|
|
|
|
v.u.l = FcLangSetPromote (NULL, buf);
|
|
|
|
v.type = FcTypeLangSet;
|
|
|
|
}
|
|
|
|
else if (u.type == FcTypeCharSet && buf)
|
|
|
|
{
|
|
|
|
v.u.c = FcCharSetPromote (buf);
|
|
|
|
v.type = FcTypeCharSet;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FcTypeString:
|
|
|
|
if (u.type == FcTypeLangSet && buf)
|
|
|
|
{
|
|
|
|
v.u.l = FcLangSetPromote (v.u.s, buf);
|
|
|
|
v.type = FcTypeLangSet;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2013-11-20 10:44:59 +01:00
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
2005-08-24 08:21:30 +02:00
|
|
|
FcConfigCompareValue (const FcValue *left_o,
|
2013-06-28 08:04:11 +02:00
|
|
|
unsigned int op_,
|
2005-08-24 08:21:30 +02:00
|
|
|
const FcValue *right_o)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2020-08-21 06:49:04 +02:00
|
|
|
FcValue left;
|
|
|
|
FcValue right;
|
2003-02-06 20:22:43 +01:00
|
|
|
FcBool ret = FcFalse;
|
2012-04-11 12:52:35 +02:00
|
|
|
FcOp op = FC_OP_GET_OP (op_);
|
|
|
|
int flags = FC_OP_GET_FLAGS (op_);
|
2021-02-12 20:51:43 +01:00
|
|
|
FcValuePromotionBuffer buf1, buf2;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2020-08-21 06:49:04 +02:00
|
|
|
if (left_o->type != right_o->type)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2020-08-21 06:49:04 +02:00
|
|
|
left = FcValueCanonicalize(left_o);
|
|
|
|
right = FcValueCanonicalize(right_o);
|
2020-08-21 05:45:19 +02:00
|
|
|
left = FcConfigPromote (left, right, &buf1);
|
|
|
|
right = FcConfigPromote (right, left, &buf2);
|
2020-08-21 06:49:04 +02:00
|
|
|
left_o = &left;
|
|
|
|
right_o = &right;
|
|
|
|
if (left_o->type != right_o->type)
|
2020-08-21 05:45:19 +02:00
|
|
|
{
|
|
|
|
if (op == FcOpNotEqual || op == FcOpNotContains)
|
|
|
|
ret = FcTrue;
|
|
|
|
return ret;
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2020-08-21 06:49:04 +02:00
|
|
|
switch (left_o->type) {
|
2020-08-21 05:45:19 +02:00
|
|
|
case FcTypeUnknown:
|
|
|
|
break; /* No way to guess how to compare for this object */
|
2020-08-21 06:49:04 +02:00
|
|
|
case FcTypeInteger: {
|
|
|
|
int l = left_o->u.i;
|
|
|
|
int r = right_o->u.i;
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l == r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l != r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpLess:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l < r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpLessEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l <= r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpMore:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l > r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpMoreEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l >= r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
|
|
|
case FcTypeDouble: {
|
|
|
|
double l = left_o->u.d;
|
|
|
|
double r = right_o->u.d;
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l == r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l != r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpLess:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l < r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpLessEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l <= r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpMore:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l > r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpMoreEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l >= r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
|
|
|
case FcTypeBool: {
|
|
|
|
FcBool l = left_o->u.b;
|
|
|
|
FcBool r = right_o->u.b;
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l == r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l == r || l >= FcDontCare;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l != r;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = !(l == r || l >= FcDontCare);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpLess:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l != r && r >= FcDontCare;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpLessEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l == r || r >= FcDontCare;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpMore:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l != r && l >= FcDontCare;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpMoreEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = l == r || l >= FcDontCare;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
|
|
|
case FcTypeString: {
|
|
|
|
const FcChar8 *l = FcValueString (left_o);
|
|
|
|
const FcChar8 *r = FcValueString (right_o);
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
|
|
|
case FcOpListing:
|
|
|
|
if (flags & FcOpFlagIgnoreBlanks)
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcStrCmpIgnoreBlanksAndCase (l, r) == 0;
|
2020-08-21 05:45:19 +02:00
|
|
|
else
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcStrCmpIgnoreCase (l, r) == 0;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcStrStrIgnoreCase (l, r) != 0;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
|
|
|
if (flags & FcOpFlagIgnoreBlanks)
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcStrCmpIgnoreBlanksAndCase (l, r) != 0;
|
2020-08-21 05:45:19 +02:00
|
|
|
else
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcStrCmpIgnoreCase (l, r) != 0;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcStrStrIgnoreCase (l, r) == 0;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
|
|
|
case FcTypeMatrix: {
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcMatrixEqual (left_o->u.m, right_o->u.m);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = !FcMatrixEqual (left_o->u.m, right_o->u.m);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
|
|
|
case FcTypeCharSet: {
|
|
|
|
const FcCharSet *l = FcValueCharSet (left_o);
|
|
|
|
const FcCharSet *r = FcValueCharSet (right_o);
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
|
|
|
/* left contains right if right is a subset of left */
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcCharSetIsSubset (r, l);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotContains:
|
|
|
|
/* left contains right if right is a subset of left */
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = !FcCharSetIsSubset (r, l);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcCharSetEqual (l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = !FcCharSetEqual (l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
|
|
|
case FcTypeLangSet: {
|
|
|
|
const FcLangSet *l = FcValueLangSet (left_o);
|
|
|
|
const FcLangSet *r = FcValueLangSet (right_o);
|
2020-08-21 05:45:19 +02:00
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcLangSetContains (l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = !FcLangSetContains (l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = FcLangSetEqual (l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = !FcLangSetEqual (l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
2020-08-21 05:45:19 +02:00
|
|
|
case FcTypeVoid:
|
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
|
|
|
ret = FcTrue;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FcTypeFTFace:
|
|
|
|
switch ((int) op) {
|
|
|
|
case FcOpEqual:
|
|
|
|
case FcOpContains:
|
|
|
|
case FcOpListing:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = left_o->u.f == right_o->u.f;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
case FcOpNotEqual:
|
|
|
|
case FcOpNotContains:
|
2020-08-21 06:49:04 +02:00
|
|
|
ret = left_o->u.f != right_o->u.f;
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-21 06:49:04 +02:00
|
|
|
case FcTypeRange: {
|
|
|
|
const FcRange *l = FcValueRange (left_o);
|
|
|
|
const FcRange *r = FcValueRange (right_o);
|
|
|
|
ret = FcRangeCompare (op, l, r);
|
2020-08-21 05:45:19 +02:00
|
|
|
break;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2020-08-21 06:49:04 +02:00
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-16 01:38:06 +02:00
|
|
|
#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
|
2012-12-30 05:58:38 +01:00
|
|
|
FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2013-11-20 10:44:59 +01:00
|
|
|
FcValue v, vl, vr, vle, vre;
|
2002-02-15 00:34:13 +01:00
|
|
|
FcMatrix *m;
|
2006-04-10 21:33:03 +02:00
|
|
|
FcChar8 *str;
|
2012-04-11 12:52:35 +02:00
|
|
|
FcOp op = FC_OP_GET_OP (e->op);
|
2013-11-20 10:44:59 +01:00
|
|
|
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:
|
2012-12-30 03:39:06 +01:00
|
|
|
{
|
|
|
|
FcMatrix m;
|
|
|
|
FcValue xx, xy, yx, yy;
|
2012-12-30 04:11:09 +01:00
|
|
|
v.type = FcTypeMatrix;
|
2012-10-07 20:41:38 +02:00
|
|
|
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);
|
2012-12-30 03:39:06 +01:00
|
|
|
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;
|
2005-08-24 08:21:30 +02:00
|
|
|
v.u.c = e->u.cval;
|
2002-02-15 00:34:13 +01:00
|
|
|
v = FcValueSave (v);
|
|
|
|
break;
|
2010-12-06 04:38:18 +01:00
|
|
|
case FcOpLangSet:
|
|
|
|
v.type = FcTypeLangSet;
|
|
|
|
v.u.l = e->u.lval;
|
|
|
|
v = FcValueSave (v);
|
|
|
|
break;
|
2013-11-20 10:44:59 +01:00
|
|
|
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:
|
2012-12-30 05:58:38 +01:00
|
|
|
if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
|
2013-01-01 03:11:12 +01:00
|
|
|
{
|
|
|
|
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;
|
2013-01-01 03:11:12 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
}
|
2006-01-25 15:52:49 +01:00
|
|
|
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:
|
2012-12-30 05:58:38 +01:00
|
|
|
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)
|
2012-12-30 05:58:38 +01:00
|
|
|
v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
|
2002-02-15 00:34:13 +01:00
|
|
|
else
|
2012-12-30 05:58:38 +01:00
|
|
|
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;
|
2002-08-22 20:53:22 +02:00
|
|
|
case FcOpEqual:
|
2002-02-15 00:34:13 +01:00
|
|
|
case FcOpNotEqual:
|
|
|
|
case FcOpLess:
|
|
|
|
case FcOpLessEqual:
|
|
|
|
case FcOpMore:
|
|
|
|
case FcOpMoreEqual:
|
2002-08-22 20:53:22 +02:00
|
|
|
case FcOpContains:
|
|
|
|
case FcOpNotContains:
|
2003-07-20 18:06:18 +02:00
|
|
|
case FcOpListing:
|
2012-12-30 05:58:38 +01:00
|
|
|
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
|
|
|
vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
|
2002-08-11 20:11:04 +02:00
|
|
|
v.type = FcTypeBool;
|
2005-08-24 08:21:30 +02:00
|
|
|
v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
|
2002-08-11 20:11:04 +02:00
|
|
|
FcValueDestroy (vl);
|
|
|
|
FcValueDestroy (vr);
|
2022-12-05 13:40:26 +01:00
|
|
|
break;
|
2002-08-11 20:11:04 +02:00
|
|
|
case FcOpOr:
|
|
|
|
case FcOpAnd:
|
2002-02-15 00:34:13 +01:00
|
|
|
case FcOpPlus:
|
|
|
|
case FcOpMinus:
|
|
|
|
case FcOpTimes:
|
|
|
|
case FcOpDivide:
|
2012-12-30 05:58:38 +01:00
|
|
|
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
|
|
|
vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
|
2013-11-20 10:44:59 +01:00
|
|
|
vle = FcConfigPromote (vl, vr, &buf1);
|
|
|
|
vre = FcConfigPromote (vr, vle, &buf2);
|
|
|
|
if (vle.type == vre.type)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2013-11-20 10:44:59 +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) {
|
2022-12-05 13:40:26 +01:00
|
|
|
case FcOpPlus:
|
2002-02-15 00:34:13 +01:00
|
|
|
v.type = FcTypeDouble;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.d = vle.u.d + vre.u.d;
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
case FcOpMinus:
|
|
|
|
v.type = FcTypeDouble;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.d = vle.u.d - vre.u.d;
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
case FcOpTimes:
|
|
|
|
v.type = FcTypeDouble;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.d = vle.u.d * vre.u.d;
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
case FcOpDivide:
|
|
|
|
v.type = FcTypeDouble;
|
2013-11-20 10:44:59 +01:00
|
|
|
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;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.b = vle.u.b || vre.u.b;
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
case FcOpAnd:
|
|
|
|
v.type = FcTypeBool;
|
2013-11-20 10:44:59 +01:00
|
|
|
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;
|
2013-11-20 10:44:59 +01:00
|
|
|
str = FcStrPlus (vle.u.s, vre.u.s);
|
2013-01-02 09:06:15 +01:00
|
|
|
v.u.s = FcStrdup (str);
|
2006-04-10 21:33:03 +02:00
|
|
|
FcStrFree (str);
|
2022-12-05 13:40:26 +01:00
|
|
|
|
2005-08-24 08:21:30 +02:00
|
|
|
if (!v.u.s)
|
2002-02-15 00:34:13 +01:00
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
}
|
2002-06-20 05:43:09 +02:00
|
|
|
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)
|
|
|
|
{
|
2013-11-20 10:44:59 +01:00
|
|
|
FcMatrixMultiply (m, vle.u.m, vre.u.m);
|
2005-08-24 08:21:30 +02:00
|
|
|
v.u.m = m;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2010-12-06 04:10:17 +01:00
|
|
|
case FcTypeCharSet:
|
2012-12-30 04:11:09 +01:00
|
|
|
switch ((int) op) {
|
2010-12-06 04:10:17 +01:00
|
|
|
case FcOpPlus:
|
|
|
|
v.type = FcTypeCharSet;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
|
2010-12-06 04:10:17 +01:00
|
|
|
if (!v.u.c)
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
case FcOpMinus:
|
|
|
|
v.type = FcTypeCharSet;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
|
2010-12-06 04:10:17 +01:00
|
|
|
if (!v.u.c)
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2010-12-06 04:38:18 +01:00
|
|
|
case FcTypeLangSet:
|
2012-12-30 04:11:09 +01:00
|
|
|
switch ((int) op) {
|
2010-12-06 04:38:18 +01:00
|
|
|
case FcOpPlus:
|
|
|
|
v.type = FcTypeLangSet;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
|
2010-12-06 04:38:18 +01:00
|
|
|
if (!v.u.l)
|
|
|
|
v.type = FcTypeVoid;
|
|
|
|
break;
|
|
|
|
case FcOpMinus:
|
|
|
|
v.type = FcTypeLangSet;
|
2013-11-20 10:44:59 +01:00
|
|
|
v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
|
2010-12-06 04:38:18 +01:00
|
|
|
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:
|
2012-12-30 05:58:38 +01:00
|
|
|
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;
|
2003-04-16 01:38:06 +02:00
|
|
|
case FcOpFloor:
|
2012-12-30 05:58:38 +01:00
|
|
|
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
2012-12-30 04:11:09 +01:00
|
|
|
switch ((int) vl.type) {
|
2003-04-16 01:38:06 +02:00
|
|
|
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:
|
2012-12-30 05:58:38 +01:00
|
|
|
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
2012-12-30 04:11:09 +01:00
|
|
|
switch ((int) vl.type) {
|
2003-04-16 01:38:06 +02:00
|
|
|
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:
|
2012-12-30 05:58:38 +01:00
|
|
|
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
2012-12-30 04:11:09 +01:00
|
|
|
switch ((int) vl.type) {
|
2003-04-16 01:38:06 +02:00
|
|
|
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:
|
2012-12-30 05:58:38 +01:00
|
|
|
vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
2012-12-30 04:11:09 +01:00
|
|
|
switch ((int) vl.type) {
|
2003-04-16 01:38:06 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-08-18 22:33:57 +02:00
|
|
|
/* The bulk of the time in FcConfigSubstitute is spent walking
|
|
|
|
* lists of family names. We speed this up with a hash table.
|
|
|
|
* Since we need to take the ignore-blanks option into account,
|
|
|
|
* we use two separate hash tables.
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
} FamilyTableEntry;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
FcHashTable *family_blank_hash;
|
|
|
|
FcHashTable *family_hash;
|
|
|
|
} FamilyTable;
|
|
|
|
|
|
|
|
static FcBool
|
|
|
|
FamilyTableLookup (FamilyTable *table,
|
|
|
|
FcOp _op,
|
|
|
|
const FcChar8 *s)
|
|
|
|
{
|
|
|
|
FamilyTableEntry *fe;
|
|
|
|
int flags = FC_OP_GET_FLAGS (_op);
|
|
|
|
FcHashTable *hash;
|
|
|
|
|
|
|
|
if (flags & FcOpFlagIgnoreBlanks)
|
|
|
|
hash = table->family_blank_hash;
|
|
|
|
else
|
|
|
|
hash = table->family_hash;
|
|
|
|
|
|
|
|
return FcHashTableFind (hash, (const void *)s, (void **)&fe);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FamilyTableAdd (FamilyTable *table,
|
|
|
|
FcValueListPtr values)
|
|
|
|
{
|
|
|
|
FcValueListPtr ll;
|
|
|
|
for (ll = values; ll; ll = FcValueListNext (ll))
|
|
|
|
{
|
|
|
|
const FcChar8 *s = FcValueString (&ll->value);
|
|
|
|
FamilyTableEntry *fe;
|
|
|
|
|
|
|
|
if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe))
|
|
|
|
{
|
|
|
|
fe = malloc (sizeof (FamilyTableEntry));
|
|
|
|
fe->count = 0;
|
|
|
|
FcHashTableAdd (table->family_hash, (void *)s, fe);
|
|
|
|
}
|
|
|
|
fe->count++;
|
|
|
|
|
|
|
|
if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe))
|
|
|
|
{
|
|
|
|
fe = malloc (sizeof (FamilyTableEntry));
|
|
|
|
fe->count = 0;
|
|
|
|
FcHashTableAdd (table->family_blank_hash, (void *)s, fe);
|
|
|
|
}
|
|
|
|
fe->count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FamilyTableDel (FamilyTable *table,
|
|
|
|
const FcChar8 *s)
|
|
|
|
{
|
|
|
|
FamilyTableEntry *fe;
|
|
|
|
|
|
|
|
if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe))
|
|
|
|
{
|
|
|
|
fe->count--;
|
|
|
|
if (fe->count == 0)
|
|
|
|
FcHashTableRemove (table->family_hash, (void *)s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe))
|
|
|
|
{
|
|
|
|
fe->count--;
|
|
|
|
if (fe->count == 0)
|
|
|
|
FcHashTableRemove (table->family_blank_hash, (void *)s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-30 18:03:04 +02:00
|
|
|
static FcBool
|
|
|
|
copy_string (const void *src, void **dest)
|
|
|
|
{
|
|
|
|
*dest = strdup ((char *)src);
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
2020-08-18 22:33:57 +02:00
|
|
|
static void
|
|
|
|
FamilyTableInit (FamilyTable *table,
|
|
|
|
FcPattern *p)
|
|
|
|
{
|
|
|
|
FcPatternElt *e;
|
|
|
|
|
|
|
|
table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
|
|
|
|
(FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
|
2020-08-30 18:03:04 +02:00
|
|
|
(FcCopyFunc)copy_string,
|
2020-08-18 22:33:57 +02:00
|
|
|
NULL,
|
2020-08-30 18:03:04 +02:00
|
|
|
free,
|
2020-08-18 22:33:57 +02:00
|
|
|
free);
|
|
|
|
table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase,
|
|
|
|
(FcCompareFunc)FcStrCmpIgnoreCase,
|
2020-08-30 18:03:04 +02:00
|
|
|
(FcCopyFunc)copy_string,
|
2020-08-18 22:33:57 +02:00
|
|
|
NULL,
|
2020-08-30 18:03:04 +02:00
|
|
|
free,
|
2020-08-18 22:33:57 +02:00
|
|
|
free);
|
|
|
|
e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT);
|
|
|
|
if (e)
|
|
|
|
FamilyTableAdd (table, FcPatternEltValues (e));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FamilyTableClear (FamilyTable *table)
|
|
|
|
{
|
|
|
|
if (table->family_blank_hash)
|
|
|
|
FcHashTableDestroy (table->family_blank_hash);
|
|
|
|
if (table->family_hash)
|
|
|
|
FcHashTableDestroy (table->family_hash);
|
|
|
|
}
|
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
static FcValueList *
|
|
|
|
FcConfigMatchValueList (FcPattern *p,
|
2012-12-30 05:58:38 +01:00
|
|
|
FcPattern *p_pat,
|
|
|
|
FcMatchKind kind,
|
2002-02-15 00:34:13 +01:00
|
|
|
FcTest *t,
|
2020-08-18 22:33:57 +02:00
|
|
|
FcValueList *values,
|
|
|
|
FamilyTable *table)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-05-21 19:06:22 +02:00
|
|
|
FcValueList *ret = 0;
|
|
|
|
FcExpr *e = t->expr;
|
|
|
|
FcValue value;
|
2002-06-19 00:23:05 +02:00
|
|
|
FcValueList *v;
|
2020-12-06 12:52:44 +01:00
|
|
|
FcOp op;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2002-05-21 19:06:22 +02:00
|
|
|
while (e)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2003-07-20 18:06:18 +02:00
|
|
|
/* Compute the value of the match expression */
|
2012-04-11 12:52:35 +02:00
|
|
|
if (FC_OP_GET_OP (e->op) == FcOpComma)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2012-12-30 05:58:38 +01:00
|
|
|
value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
|
2002-05-21 19:06:22 +02:00
|
|
|
e = e->u.tree.right;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-30 05:58:38 +01:00
|
|
|
value = FcConfigEvaluate (p, p_pat, kind, e);
|
2002-05-21 19:06:22 +02:00
|
|
|
e = 0;
|
|
|
|
}
|
|
|
|
|
2020-08-18 22:33:57 +02:00
|
|
|
if (t->object == FC_FAMILY_OBJECT && table)
|
|
|
|
{
|
2020-12-06 12:52:44 +01:00
|
|
|
op = FC_OP_GET_OP (t->op);
|
|
|
|
if (op == FcOpEqual || op == FcOpListing)
|
2020-08-18 22:33:57 +02:00
|
|
|
{
|
2020-12-06 12:52:44 +01:00
|
|
|
if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
|
|
|
|
{
|
2020-08-18 22:33:57 +02:00
|
|
|
ret = 0;
|
|
|
|
goto done;
|
2020-12-06 12:52:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (op == FcOpNotEqual && t->qual == FcQualAll)
|
|
|
|
{
|
|
|
|
ret = 0;
|
|
|
|
if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
|
|
|
|
{
|
|
|
|
ret = values;
|
|
|
|
}
|
|
|
|
goto done;
|
2020-08-18 22:33:57 +02:00
|
|
|
}
|
|
|
|
}
|
2006-08-30 13:16:22 +02:00
|
|
|
for (v = values; v; v = FcValueListNext(v))
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
2003-07-20 18:06:18 +02:00
|
|
|
/* Compare the pattern value to the match expression value */
|
2005-08-24 08:21:30 +02:00
|
|
|
if (FcConfigCompareValue (&v->value, t->op, &value))
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-05-21 19:06:22 +02:00
|
|
|
if (!ret)
|
|
|
|
ret = v;
|
2020-08-18 21:02:21 +02:00
|
|
|
if (t->qual != FcQualAll)
|
|
|
|
break;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (t->qual == FcQualAll)
|
|
|
|
{
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
}
|
2020-08-18 22:33:57 +02:00
|
|
|
done:
|
2002-06-08 19:32:05 +02:00
|
|
|
FcValueDestroy (value);
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FcValueList *
|
2012-12-30 05:58:38 +01:00
|
|
|
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;
|
2012-04-11 12:52:35 +02:00
|
|
|
if (FC_OP_GET_OP (e->op) == FcOpComma)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2012-12-30 05:58:38 +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
|
|
|
|
{
|
2012-12-30 05:58:38 +01:00
|
|
|
l->value = FcConfigEvaluate (p, p_pat, kind, e);
|
2006-08-30 13:16:22 +02:00
|
|
|
l->next = NULL;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2002-07-31 03:36:37 +02:00
|
|
|
l->binding = binding;
|
2005-11-18 05:21:10 +01:00
|
|
|
if (l->value.type == FcTypeVoid)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcValueList *next = FcValueListNext(l);
|
2005-06-28 05:41:02 +02:00
|
|
|
|
2005-11-18 05:21:10 +01:00
|
|
|
free (l);
|
|
|
|
l = next;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2005-11-18 05:21:10 +01:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FcBool
|
2005-06-28 05:41:02 +02:00
|
|
|
FcConfigAdd (FcValueListPtr *head,
|
2002-02-15 00:34:13 +01:00
|
|
|
FcValueList *position,
|
|
|
|
FcBool append,
|
2013-01-02 03:09:08 +01:00
|
|
|
FcValueList *new,
|
2020-08-18 22:33:57 +02:00
|
|
|
FcObject object,
|
|
|
|
FamilyTable *table)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2013-01-02 03:09:08 +01:00
|
|
|
FcValueListPtr *prev, l, last, v;
|
2003-02-12 19:22:12 +01:00
|
|
|
FcValueBinding sameBinding;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2013-01-02 03:09:08 +01: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 22:33:57 +02:00
|
|
|
if (object == FC_FAMILY_OBJECT && table)
|
|
|
|
{
|
|
|
|
FamilyTableAdd (table, new);
|
|
|
|
}
|
|
|
|
|
2003-02-12 19:22:12 +01:00
|
|
|
if (position)
|
|
|
|
sameBinding = position->binding;
|
|
|
|
else
|
|
|
|
sameBinding = FcValueBindingWeak;
|
2006-08-30 13:16:22 +02:00
|
|
|
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;
|
2006-08-30 13:16:22 +02:00
|
|
|
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;
|
2006-08-30 13:16:22 +02:00
|
|
|
prev = &(*prev)->next)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
if (*prev == position)
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
prev = head;
|
|
|
|
|
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
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");
|
2012-05-01 13:18:41 +02:00
|
|
|
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)
|
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
last = new;
|
|
|
|
while (last->next != NULL)
|
|
|
|
last = last->next;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-30 13:16:22 +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
|
2005-06-28 05:41:02 +02:00
|
|
|
FcConfigDel (FcValueListPtr *head,
|
2020-08-18 22:33:57 +02:00
|
|
|
FcValueList *position,
|
|
|
|
FcObject object,
|
|
|
|
FamilyTable *table)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
FcValueListPtr *prev;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2020-08-18 22:33:57 +02:00
|
|
|
if (object == FC_FAMILY_OBJECT && table)
|
|
|
|
{
|
|
|
|
FamilyTableDel (table, FcValueString (&position->value));
|
|
|
|
}
|
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
for (prev = head; *prev != NULL; prev = &(*prev)->next)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
if (*prev == position)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
|
|
|
*prev = position->next;
|
2006-08-30 13:16:22 +02:00
|
|
|
position->next = NULL;
|
|
|
|
FcValueListDestroy (position);
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FcConfigPatternAdd (FcPattern *p,
|
2020-08-18 22:33:57 +02:00
|
|
|
FcObject object,
|
2002-02-15 00:34:13 +01:00
|
|
|
FcValueList *list,
|
2020-08-18 22:33:57 +02:00
|
|
|
FcBool append,
|
|
|
|
FamilyTable *table)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
|
|
|
if (list)
|
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcPatternElt *e = FcPatternObjectInsertElt (p, object);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!e)
|
|
|
|
return;
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigAdd (&e->values, 0, append, list, object, table);
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all values associated with a field
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
FcConfigPatternDel (FcPattern *p,
|
2020-08-18 22:33:57 +02:00
|
|
|
FcObject object,
|
|
|
|
FamilyTable *table)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcPatternElt *e = FcPatternObjectFindElt (p, object);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!e)
|
|
|
|
return;
|
2006-08-30 13:16:22 +02:00
|
|
|
while (e->values != NULL)
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigDel (&e->values, e->values, object, table);
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FcConfigPatternCanon (FcPattern *p,
|
2006-08-30 13:16:22 +02:00
|
|
|
FcObject object)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcPatternElt *e = FcPatternObjectFindElt (p, object);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!e)
|
|
|
|
return;
|
2006-08-30 13:16:22 +02:00
|
|
|
if (e->values == NULL)
|
|
|
|
FcPatternObjectDel (p, object);
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
2002-08-19 21:32:05 +02:00
|
|
|
FcConfigSubstituteWithPat (FcConfig *config,
|
|
|
|
FcPattern *p,
|
|
|
|
FcPattern *p_pat,
|
|
|
|
FcMatchKind kind)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2013-01-16 03:41:26 +01:00
|
|
|
FcValue v;
|
2014-03-27 07:10:44 +01:00
|
|
|
FcPtrList *s;
|
|
|
|
FcPtrListIter iter, iter2;
|
2013-07-04 12:51:03 +02:00
|
|
|
FcRule *r;
|
2014-03-27 07:10:44 +01:00
|
|
|
FcRuleSet *rs;
|
2013-08-26 05:47:07 +02:00
|
|
|
FcValueList *l, **value = NULL, *vl;
|
2002-08-11 20:11:04 +02:00
|
|
|
FcPattern *m;
|
2012-05-22 07:17:10 +02:00
|
|
|
FcStrSet *strs;
|
2013-07-04 12:51:03 +02:00
|
|
|
FcObject object = FC_INVALID_OBJECT;
|
2013-08-26 05:47:07 +02:00
|
|
|
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;
|
2020-08-18 22:33:57 +02:00
|
|
|
FamilyTable data;
|
|
|
|
FamilyTable *table = &data;
|
2013-08-05 13:04:13 +02:00
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
|
|
|
|
return FcFalse;
|
2019-11-01 06:43:42 +01:00
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
|
|
|
if (!config)
|
|
|
|
return FcFalse;
|
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
s = config->subst[kind];
|
|
|
|
if (kind == FcMatchPattern)
|
|
|
|
{
|
2012-06-08 12:17:57 +02:00
|
|
|
strs = FcGetDefaultLangs ();
|
|
|
|
if (strs)
|
|
|
|
{
|
|
|
|
FcStrList *l = FcStrListCreate (strs);
|
|
|
|
FcChar8 *lang;
|
|
|
|
FcValue v;
|
2015-02-09 08:45:43 +01:00
|
|
|
FcLangSet *lsund = FcLangSetCreate ();
|
2012-06-08 12:17:57 +02:00
|
|
|
|
2015-02-09 08:45:43 +01:00
|
|
|
FcLangSetAdd (lsund, (const FcChar8 *)"und");
|
2012-06-08 12:17:57 +02:00
|
|
|
FcStrSetDestroy (strs);
|
|
|
|
while (l && (lang = FcStrListNext (l)))
|
|
|
|
{
|
2014-07-23 12:17:26 +02:00
|
|
|
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;
|
2015-02-09 08:45:43 +01:00
|
|
|
if (FcLangSetContains (vv.u.l, lsund))
|
|
|
|
goto bail_lang;
|
2014-07-23 12:17:26 +02:00
|
|
|
}
|
|
|
|
else
|
2015-02-09 08:45:43 +01:00
|
|
|
{
|
2014-07-23 12:17:26 +02:00
|
|
|
if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
|
|
|
|
goto bail_lang;
|
2015-02-09 08:45:43 +01:00
|
|
|
if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
|
|
|
|
goto bail_lang;
|
|
|
|
}
|
2014-07-23 12:17:26 +02:00
|
|
|
}
|
|
|
|
}
|
2012-06-08 12:17:57 +02:00
|
|
|
v.type = FcTypeString;
|
|
|
|
v.u.s = lang;
|
2014-07-23 12:17:26 +02:00
|
|
|
|
2012-06-08 12:17:57 +02:00
|
|
|
FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
|
|
|
|
}
|
2014-07-23 12:17:26 +02:00
|
|
|
bail_lang:
|
2012-06-08 12:17:57 +02:00
|
|
|
FcStrListDone (l);
|
2015-02-09 08:45:43 +01:00
|
|
|
FcLangSetDestroy (lsund);
|
2012-06-08 12:17:57 +02:00
|
|
|
}
|
2013-01-16 03:41:26 +01:00
|
|
|
if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
|
|
|
|
{
|
|
|
|
FcChar8 *prgname = FcGetPrgname ();
|
|
|
|
if (prgname)
|
|
|
|
FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
|
|
|
|
}
|
2006-09-03 02:52:12 +02:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
2020-08-18 22:33:57 +02:00
|
|
|
|
|
|
|
FamilyTableInit (&data, p);
|
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
FcPtrListIterInit (s, &iter);
|
|
|
|
for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter);
|
2018-01-03 14:15:11 +01:00
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
|
|
|
{
|
|
|
|
printf ("\nRule Set: %s\n", rs->name);
|
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
FcPtrListIterInit (rs->subst[kind], &iter2);
|
|
|
|
for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2))
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2);
|
|
|
|
for (i = 0; i < nobjs; i++)
|
|
|
|
{
|
|
|
|
elt[i] = NULL;
|
|
|
|
value[i] = NULL;
|
|
|
|
tst[i] = NULL;
|
|
|
|
}
|
|
|
|
for (; r; r = r->next)
|
|
|
|
{
|
|
|
|
switch (r->type) {
|
|
|
|
case FcRuleUnknown:
|
|
|
|
/* shouldn't be reached */
|
|
|
|
break;
|
|
|
|
case FcRuleTest:
|
|
|
|
object = FC_OBJ_ID (r->u.test->object);
|
|
|
|
/*
|
|
|
|
* Check the tests to see if
|
|
|
|
* they all match the pattern
|
|
|
|
*/
|
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
2013-07-04 12:51:03 +02:00
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
printf ("FcConfigSubstitute test ");
|
|
|
|
FcTestPrint (r->u.test);
|
2013-07-04 12:51:03 +02:00
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
|
2020-08-18 22:33:57 +02:00
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
m = p_pat;
|
2020-08-18 22:33:57 +02:00
|
|
|
table = NULL;
|
|
|
|
}
|
2013-07-04 12:51:03 +02:00
|
|
|
else
|
2020-08-18 22:33:57 +02:00
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
m = p;
|
2020-08-18 22:33:57 +02:00
|
|
|
table = &data;
|
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
elt[object] = e;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
value[object] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
|
|
|
printf ("No match\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Check to see if there is a match, mark the location
|
|
|
|
* to apply match-relative edits
|
|
|
|
*/
|
2020-08-18 22:33:57 +02:00
|
|
|
vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table);
|
2014-03-27 07:10:44 +01:00
|
|
|
/* 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))
|
2013-07-04 12:51:03 +02:00
|
|
|
{
|
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
|
|
|
printf ("No match\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
case FcRuleEdit:
|
|
|
|
object = FC_OBJ_ID (r->u.edit->object);
|
2013-07-04 12:51:03 +02:00
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
2014-03-27 07:10:44 +01:00
|
|
|
{
|
|
|
|
printf ("Substitute ");
|
|
|
|
FcEditPrint (r->u.edit);
|
|
|
|
printf ("\n\n");
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
/*
|
2014-03-27 07:10:44 +01:00
|
|
|
* Evaluate the list of expressions
|
2002-02-15 00:34:13 +01:00
|
|
|
*/
|
2020-08-18 22:33:57 +02:00
|
|
|
l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding);
|
2014-03-27 07:10:44 +01:00
|
|
|
if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
|
|
|
|
elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
|
2013-07-04 12:51:03 +02:00
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
switch (FC_OP_GET_OP (r->u.edit->op)) {
|
|
|
|
case FcOpAssign:
|
2013-07-04 12:51:03 +02:00
|
|
|
/*
|
2014-03-27 07:10:44 +01:00
|
|
|
* If there was a test, then replace the matched
|
|
|
|
* value with the new list of values
|
2013-07-04 12:51:03 +02:00
|
|
|
*/
|
2014-03-27 07:10:44 +01:00
|
|
|
if (value[object])
|
|
|
|
{
|
|
|
|
FcValueList *thisValue = value[object];
|
|
|
|
FcValueList *nextValue = l;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Append the new list of values after the current value
|
|
|
|
*/
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table);
|
2014-03-27 07:10:44 +01:00
|
|
|
/*
|
|
|
|
* Delete the marked value
|
|
|
|
*/
|
|
|
|
if (thisValue)
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigDel (&elt[object]->values, thisValue, object, table);
|
2014-03-27 07:10:44 +01:00
|
|
|
/*
|
|
|
|
* Adjust a pointer into the value list to ensure
|
|
|
|
* future edits occur at the same place
|
|
|
|
*/
|
|
|
|
value[object] = nextValue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through ... */
|
|
|
|
case FcOpAssignReplace:
|
2013-07-04 12:51:03 +02:00
|
|
|
/*
|
2014-03-27 07:10:44 +01:00
|
|
|
* Delete all of the values and insert
|
|
|
|
* the new set
|
2013-07-04 12:51:03 +02:00
|
|
|
*/
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigPatternDel (p, r->u.edit->object, table);
|
|
|
|
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
|
2013-07-04 12:51:03 +02:00
|
|
|
/*
|
2014-03-27 07:10:44 +01:00
|
|
|
* Adjust a pointer into the value list as they no
|
|
|
|
* longer point to anything valid
|
2013-07-04 12:51:03 +02:00
|
|
|
*/
|
2014-03-27 07:10:44 +01:00
|
|
|
value[object] = NULL;
|
2013-07-04 12:51:03 +02:00
|
|
|
break;
|
2014-03-27 07:10:44 +01:00
|
|
|
case FcOpPrepend:
|
|
|
|
if (value[object])
|
|
|
|
{
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table);
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through ... */
|
|
|
|
case FcOpPrependFirst:
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table);
|
2013-07-04 12:51:03 +02:00
|
|
|
break;
|
2014-03-27 07:10:44 +01:00
|
|
|
case FcOpAppend:
|
|
|
|
if (value[object])
|
|
|
|
{
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table);
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through ... */
|
|
|
|
case FcOpAppendLast:
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
case FcOpDelete:
|
|
|
|
if (value[object])
|
|
|
|
{
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigDel (&elt[object]->values, value[object], object, table);
|
2018-07-19 05:08:34 +02:00
|
|
|
FcValueListDestroy (l);
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through ... */
|
|
|
|
case FcOpDeleteAll:
|
2020-08-18 22:33:57 +02:00
|
|
|
FcConfigPatternDel (p, r->u.edit->object, table);
|
2018-07-19 05:08:34 +02:00
|
|
|
FcValueListDestroy (l);
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
FcValueListDestroy (l);
|
2013-07-04 12:51:03 +02:00
|
|
|
break;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
/*
|
|
|
|
* Now go through the pattern and eliminate
|
|
|
|
* any properties without data
|
|
|
|
*/
|
|
|
|
FcConfigPatternCanon (p, r->u.edit->object);
|
|
|
|
|
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
2013-07-04 12:51:03 +02:00
|
|
|
{
|
2014-03-27 07:10:44 +01:00
|
|
|
printf ("FcConfigSubstitute edit");
|
|
|
|
FcPatternPrint (p);
|
2013-07-04 12:51:03 +02:00
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
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:
|
2020-08-18 22:33:57 +02:00
|
|
|
FamilyTableClear (&data);
|
2013-08-05 13:04:13 +02:00
|
|
|
if (elt)
|
|
|
|
free (elt);
|
|
|
|
if (value)
|
|
|
|
free (value);
|
2013-08-31 03:43:13 +02:00
|
|
|
if (tst)
|
|
|
|
free (tst);
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfigDestroy (config);
|
2013-08-05 13:04:13 +02:00
|
|
|
|
|
|
|
return retval;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
2002-08-19 21:32:05 +02:00
|
|
|
FcBool
|
|
|
|
FcConfigSubstitute (FcConfig *config,
|
|
|
|
FcPattern *p,
|
|
|
|
FcMatchKind kind)
|
|
|
|
{
|
|
|
|
return FcConfigSubstituteWithPat (config, p, 0, kind);
|
|
|
|
}
|
|
|
|
|
2008-05-04 04:45:31 +02:00
|
|
|
#if defined (_WIN32)
|
|
|
|
|
2012-10-07 23:46:12 +02:00
|
|
|
static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
|
2015-04-08 10:41:25 +02:00
|
|
|
FcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
|
2003-03-22 22:25:34 +01:00
|
|
|
|
2008-05-04 04:45:31 +02:00
|
|
|
# if (defined (PIC) || defined (DLL_EXPORT))
|
|
|
|
|
2013-01-03 00:35:56 +01:00
|
|
|
BOOL WINAPI
|
|
|
|
DllMain (HINSTANCE hinstDLL,
|
|
|
|
DWORD fdwReason,
|
|
|
|
LPVOID lpvReserved);
|
|
|
|
|
2003-03-22 22:25:34 +01:00
|
|
|
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,
|
2003-03-22 22:25:34 +01:00
|
|
|
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, '\\');
|
2003-03-22 22:25:34 +01:00
|
|
|
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))
|
2003-03-22 22:25:34 +01:00
|
|
|
*p = '\0';
|
2015-04-08 10:41:25 +02:00
|
|
|
strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
|
2012-06-13 13:01:30 +02:00
|
|
|
strcat ((char *) fontconfig_path, "\\etc\\fonts");
|
2003-03-22 22:25:34 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
fontconfig_path[0] = '\0';
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2003-03-22 22:25:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-05-04 04:45:31 +02:00
|
|
|
# endif /* !PIC */
|
|
|
|
|
2003-03-22 22:25:34 +01:00
|
|
|
#undef FONTCONFIG_PATH
|
|
|
|
#define FONTCONFIG_PATH fontconfig_path
|
|
|
|
|
2008-05-04 04:45:31 +02:00
|
|
|
#endif /* !_WIN32 */
|
2003-03-22 22:25:34 +01:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
#ifndef FONTCONFIG_FILE
|
|
|
|
#define FONTCONFIG_FILE "fonts.conf"
|
|
|
|
#endif
|
|
|
|
|
2002-02-15 07:01:28 +01:00
|
|
|
static FcChar8 *
|
|
|
|
FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-02-15 07:01:28 +01:00
|
|
|
FcChar8 *path;
|
2012-06-01 12:06:17 +02:00
|
|
|
int size, osize;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
|
|
|
if (!dir)
|
2002-02-15 07:01:28 +01:00
|
|
|
dir = (FcChar8 *) "";
|
2011-03-28 22:33:12 +02:00
|
|
|
|
2012-06-01 12:06:17 +02:00
|
|
|
osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
|
2011-03-28 22:33:12 +02:00
|
|
|
/*
|
|
|
|
* workaround valgrind warning because glibc takes advantage of how it knows memory is
|
|
|
|
* allocated to implement strlen by reading in groups of 4
|
|
|
|
*/
|
2012-06-01 12:06:17 +02:00
|
|
|
size = (osize + 3) & ~3;
|
2011-03-28 22:33:12 +02:00
|
|
|
|
|
|
|
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);
|
2003-03-22 22:25:34 +01:00
|
|
|
/* make sure there's a single separator */
|
|
|
|
#ifdef _WIN32
|
|
|
|
if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
|
|
|
|
path[strlen((char *) path)-1] != '\\')) &&
|
2005-03-09 01:47:11 +01:00
|
|
|
!(file[0] == '/' ||
|
|
|
|
file[0] == '\\' ||
|
|
|
|
(isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
|
2003-03-22 22:25:34 +01:00
|
|
|
strcat ((char *) path, "\\");
|
|
|
|
#else
|
2002-02-15 07:01:28 +01:00
|
|
|
if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
|
|
|
|
strcat ((char *) path, "/");
|
2012-12-07 11:09:36 +01:00
|
|
|
else
|
|
|
|
osize--;
|
2003-03-22 22:25:34 +01:00
|
|
|
#endif
|
2002-02-15 07:01:28 +01:00
|
|
|
strcat ((char *) path, (char *) file);
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2002-02-15 07:01:28 +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
|
|
|
|
2002-09-01 00:17:32 +02:00
|
|
|
FcStrFree (path);
|
2012-06-01 12:06:17 +02:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-02-15 07:01:28 +01:00
|
|
|
static FcChar8 **
|
2002-02-15 00:34:13 +01:00
|
|
|
FcConfigGetPath (void)
|
|
|
|
{
|
2002-02-15 07:01:28 +01:00
|
|
|
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 */
|
2002-02-15 07:01:28 +01:00
|
|
|
env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
|
2002-02-15 00:34:13 +01:00
|
|
|
if (env)
|
|
|
|
{
|
|
|
|
e = env;
|
|
|
|
npath++;
|
|
|
|
while (*e)
|
2003-03-22 22:25:34 +01:00
|
|
|
if (*e++ == FC_SEARCH_PATH_SEPARATOR)
|
2002-02-15 00:34:13 +01:00
|
|
|
npath++;
|
|
|
|
}
|
2002-02-15 07:01:28 +01:00
|
|
|
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
|
|
|
{
|
2003-03-22 22:25:34 +01:00
|
|
|
colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!colon)
|
2002-02-15 07:01:28 +01:00
|
|
|
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
|
|
|
|
2008-05-04 04:45:31 +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)))
|
2008-05-04 04:45:31 +02:00
|
|
|
goto bail1;
|
2012-06-13 13:01:30 +02:00
|
|
|
p = strrchr ((const char *) fontconfig_path, '\\');
|
2008-05-04 04:45:31 +02:00
|
|
|
if (p) *p = '\0';
|
2012-06-13 13:01:30 +02:00
|
|
|
strcat ((char *) fontconfig_path, "\\fonts");
|
2008-05-04 04:45:31 +02:00
|
|
|
}
|
|
|
|
#endif
|
2002-02-15 07:01:28 +01:00
|
|
|
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
|
2002-02-15 07:01:28 +01:00
|
|
|
FcConfigFreePath (FcChar8 **path)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-02-15 07:01:28 +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 */
|
2003-03-02 20:12:23 +01:00
|
|
|
|
|
|
|
FcChar8 *
|
|
|
|
FcConfigHome (void)
|
|
|
|
{
|
|
|
|
if (_FcConfigHomeEnabled)
|
2003-03-22 22:25:34 +01:00
|
|
|
{
|
|
|
|
char *home = getenv ("HOME");
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (home == NULL)
|
|
|
|
home = getenv ("USERPROFILE");
|
|
|
|
#endif
|
|
|
|
|
2005-09-11 04:16:09 +02:00
|
|
|
return (FcChar8 *) home;
|
2003-03-22 22:25:34 +01:00
|
|
|
}
|
2003-03-02 20:12:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-12 11:18:19 +01:00
|
|
|
FcChar8 *
|
|
|
|
FcConfigXdgCacheHome (void)
|
|
|
|
{
|
|
|
|
const char *env = getenv ("XDG_CACHE_HOME");
|
|
|
|
FcChar8 *ret = NULL;
|
|
|
|
|
2014-06-30 08:12:32 +02:00
|
|
|
if (!_FcConfigHomeEnabled)
|
|
|
|
return NULL;
|
2020-07-14 12:24:36 +02:00
|
|
|
if (env && env[0])
|
2012-03-12 11:18:19 +01:00
|
|
|
ret = FcStrCopy ((const FcChar8 *)env);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const FcChar8 *home = FcConfigHome ();
|
2014-06-30 08:12:32 +02:00
|
|
|
size_t len = home ? strlen ((const char *)home) : 0;
|
2012-03-12 11:18:19 +01:00
|
|
|
|
|
|
|
ret = malloc (len + 7 + 1);
|
|
|
|
if (ret)
|
|
|
|
{
|
2018-07-19 09:50:20 +02:00
|
|
|
if (home)
|
|
|
|
memcpy (ret, home, len);
|
2012-03-12 11:18:19 +01:00
|
|
|
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;
|
|
|
|
|
2014-06-30 08:12:32 +02:00
|
|
|
if (!_FcConfigHomeEnabled)
|
|
|
|
return NULL;
|
2012-03-12 11:18:19 +01:00
|
|
|
if (env)
|
|
|
|
ret = FcStrCopy ((const FcChar8 *)env);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const FcChar8 *home = FcConfigHome ();
|
2014-06-30 08:12:32 +02:00
|
|
|
size_t len = home ? strlen ((const char *)home) : 0;
|
2012-03-12 11:18:19 +01:00
|
|
|
|
|
|
|
ret = malloc (len + 8 + 1);
|
|
|
|
if (ret)
|
|
|
|
{
|
2018-07-19 09:50:20 +02:00
|
|
|
if (home)
|
|
|
|
memcpy (ret, home, len);
|
2012-03-12 11:18:19 +01:00
|
|
|
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;
|
|
|
|
|
2014-06-30 08:12:32 +02:00
|
|
|
if (!_FcConfigHomeEnabled)
|
|
|
|
return NULL;
|
2012-03-12 11:18:19 +01:00
|
|
|
if (env)
|
|
|
|
ret = FcStrCopy ((const FcChar8 *)env);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const FcChar8 *home = FcConfigHome ();
|
2014-06-30 08:12:32 +02:00
|
|
|
size_t len = home ? strlen ((const char *)home) : 0;
|
2012-03-12 11:18:19 +01:00
|
|
|
|
|
|
|
ret = malloc (len + 13 + 1);
|
|
|
|
if (ret)
|
|
|
|
{
|
2018-07-19 09:50:20 +02:00
|
|
|
if (home)
|
|
|
|
memcpy (ret, home, len);
|
2012-03-12 11:18:19 +01:00
|
|
|
memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
|
|
|
|
ret[len + 13] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-03-29 14:25:21 +02:00
|
|
|
FcStrSet *
|
|
|
|
FcConfigXdgDataDirs (void)
|
|
|
|
{
|
|
|
|
const char *env = getenv ("XDG_DATA_DIRS");
|
|
|
|
FcStrSet *ret = FcStrSetCreate ();
|
|
|
|
|
|
|
|
if (env)
|
|
|
|
{
|
|
|
|
FcChar8 *ee, *e = ee = FcStrCopy ((const FcChar8 *) env);
|
|
|
|
|
|
|
|
/* We don't intentionally use FC_SEARCH_PATH_SEPARATOR here because of:
|
|
|
|
* The directories in $XDG_DATA_DIRS should be seperated with a colon ':'.
|
|
|
|
* in doc.
|
|
|
|
*/
|
|
|
|
while (e)
|
|
|
|
{
|
|
|
|
FcChar8 *p = (FcChar8 *) strchr ((const char *) e, ':');
|
|
|
|
FcChar8 *s;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
{
|
|
|
|
s = FcStrCopy (e);
|
|
|
|
e = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*p = 0;
|
|
|
|
s = FcStrCopy (e);
|
|
|
|
e = p + 1;
|
|
|
|
}
|
|
|
|
len = strlen ((const char *) s);
|
|
|
|
if (s[len - 1] == FC_DIR_SEPARATOR)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
while (len > 1 && s[len - 1] == FC_DIR_SEPARATOR);
|
|
|
|
s[len] = 0;
|
|
|
|
}
|
|
|
|
FcStrSetAdd (ret, s);
|
|
|
|
FcStrFree (s);
|
|
|
|
}
|
|
|
|
FcStrFree (ee);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* From spec doc at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
|
|
|
*
|
|
|
|
* If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.
|
|
|
|
*/
|
|
|
|
FcStrSetAdd (ret, (const FcChar8 *) "/usr/local/share");
|
|
|
|
FcStrSetAdd (ret, (const FcChar8 *) "/usr/share");
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-03-02 20:12:23 +01:00
|
|
|
FcBool
|
|
|
|
FcConfigEnableHome (FcBool enable)
|
|
|
|
{
|
|
|
|
FcBool prev = _FcConfigHomeEnabled;
|
|
|
|
_FcConfigHomeEnabled = enable;
|
|
|
|
return prev;
|
|
|
|
}
|
|
|
|
|
2002-02-15 07:01:28 +01:00
|
|
|
FcChar8 *
|
2019-10-21 09:17:42 +02:00
|
|
|
FcConfigGetFilename (FcConfig *config,
|
|
|
|
const FcChar8 *url)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
2002-02-15 07:01:28 +01:00
|
|
|
FcChar8 *file, *dir, **path, **p;
|
2019-10-21 09:17:42 +02:00
|
|
|
const FcChar8 *sysroot;
|
2008-05-04 04:45:31 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
2019-10-21 09:17:42 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return NULL;
|
2019-10-21 09:17:42 +02:00
|
|
|
sysroot = FcConfigGetSysRoot (config);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!url || !*url)
|
|
|
|
{
|
2002-02-15 07:01:28 +01:00
|
|
|
url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!url)
|
2002-02-15 07:01:28 +01:00
|
|
|
url = (FcChar8 *) FONTCONFIG_FILE;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2002-02-15 07:01:28 +01:00
|
|
|
file = 0;
|
2003-03-22 22:25:34 +01:00
|
|
|
|
2018-07-12 00:50:26 +02:00
|
|
|
if (FcStrIsAbsoluteFilename(url))
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
2020-09-15 11:15:37 +02:00
|
|
|
if (sysroot)
|
|
|
|
{
|
|
|
|
size_t len = strlen ((const char *) sysroot);
|
|
|
|
|
|
|
|
/* Workaround to avoid adding sysroot repeatedly */
|
|
|
|
if (strncmp ((const char *) url, (const char *) sysroot, len) == 0)
|
|
|
|
sysroot = NULL;
|
|
|
|
}
|
2019-11-01 06:43:42 +01:00
|
|
|
file = FcConfigFileExists (sysroot, url);
|
|
|
|
goto bail;
|
|
|
|
}
|
2003-03-22 22:25:34 +01:00
|
|
|
|
2018-07-12 00:50:26 +02:00
|
|
|
if (*url == '~')
|
|
|
|
{
|
2003-03-02 20:12:23 +01:00
|
|
|
dir = FcConfigHome ();
|
2002-02-15 00:34:13 +01:00
|
|
|
if (dir)
|
2019-10-21 09:17:42 +02:00
|
|
|
{
|
|
|
|
FcChar8 *s;
|
|
|
|
|
|
|
|
if (sysroot)
|
|
|
|
s = FcStrBuildFilename (sysroot, dir, NULL);
|
|
|
|
else
|
|
|
|
s = dir;
|
|
|
|
file = FcConfigFileExists (s, url + 1);
|
|
|
|
if (sysroot)
|
|
|
|
FcStrFree (s);
|
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
else
|
|
|
|
file = 0;
|
|
|
|
}
|
2018-09-04 11:08:37 +02:00
|
|
|
else
|
2018-07-12 00:50:26 +02:00
|
|
|
{
|
2018-09-04 11:08:37 +02:00
|
|
|
path = FcConfigGetPath ();
|
|
|
|
if (!path)
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
file = NULL;
|
|
|
|
goto bail;
|
|
|
|
}
|
2018-09-04 11:08:37 +02:00
|
|
|
for (p = path; *p; p++)
|
|
|
|
{
|
2019-10-21 09:17:42 +02:00
|
|
|
FcChar8 *s;
|
|
|
|
|
|
|
|
if (sysroot)
|
|
|
|
s = FcStrBuildFilename (sysroot, *p, NULL);
|
|
|
|
else
|
|
|
|
s = *p;
|
|
|
|
file = FcConfigFileExists (s, url);
|
|
|
|
if (sysroot)
|
|
|
|
FcStrFree (s);
|
2018-09-04 11:08:37 +02:00
|
|
|
if (file)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FcConfigFreePath (path);
|
2018-07-12 00:50:26 +02:00
|
|
|
}
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2019-10-21 09:17:42 +02:00
|
|
|
FcChar8 *
|
|
|
|
FcConfigFilename (const FcChar8 *url)
|
|
|
|
{
|
|
|
|
return FcConfigGetFilename (NULL, url);
|
|
|
|
}
|
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
FcChar8 *
|
|
|
|
FcConfigRealFilename (FcConfig *config,
|
|
|
|
const FcChar8 *url)
|
|
|
|
{
|
2019-10-21 09:17:42 +02:00
|
|
|
FcChar8 *n = FcConfigGetFilename (config, url);
|
2014-03-27 07:10:44 +01:00
|
|
|
|
|
|
|
if (n)
|
|
|
|
{
|
2018-11-06 08:33:03 +01:00
|
|
|
FcChar8 buf[FC_PATH_MAX];
|
2014-03-27 07:10:44 +01:00
|
|
|
ssize_t len;
|
2020-02-19 06:02:31 +01:00
|
|
|
struct stat sb;
|
2014-03-27 07:10:44 +01:00
|
|
|
|
2019-10-21 09:17:42 +02:00
|
|
|
if ((len = FcReadLink (n, buf, sizeof (buf) - 1)) != -1)
|
2014-03-27 07:10:44 +01:00
|
|
|
{
|
|
|
|
buf[len] = 0;
|
2018-07-12 00:50:26 +02:00
|
|
|
|
2020-02-19 06:02:31 +01:00
|
|
|
/* We try to pick up a config from FONTCONFIG_FILE
|
|
|
|
* when url is null. don't try to address the real filename
|
|
|
|
* if it is a named pipe.
|
|
|
|
*/
|
|
|
|
if (!url && FcStat (n, &sb) == 0 && S_ISFIFO (sb.st_mode))
|
|
|
|
return n;
|
|
|
|
else if (!FcStrIsAbsoluteFilename (buf))
|
2018-07-12 00:50:26 +02:00
|
|
|
{
|
2019-10-21 09:17:42 +02:00
|
|
|
FcChar8 *dirname = FcStrDirname (n);
|
|
|
|
FcStrFree (n);
|
2018-07-12 00:50:26 +02:00
|
|
|
if (!dirname)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL);
|
|
|
|
FcStrFree (dirname);
|
|
|
|
if (!path)
|
|
|
|
return NULL;
|
|
|
|
|
2019-10-21 09:17:42 +02:00
|
|
|
n = FcStrCanonFilename (path);
|
2018-07-12 00:50:26 +02:00
|
|
|
FcStrFree (path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-10-21 09:17:42 +02:00
|
|
|
FcStrFree (n);
|
|
|
|
n = FcStrdup (buf);
|
2018-07-12 00:50:26 +02:00
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-21 09:17:42 +02:00
|
|
|
return n;
|
2014-03-27 07:10:44 +01:00
|
|
|
}
|
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
/*
|
|
|
|
* Manage the application-specific fonts
|
|
|
|
*/
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigAppFontAddFile (FcConfig *config,
|
2002-02-15 07:01:28 +01:00
|
|
|
const FcChar8 *file)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
|
|
|
FcFontSet *set;
|
2002-05-21 19:06:22 +02:00
|
|
|
FcStrSet *subdirs;
|
|
|
|
FcStrList *sublist;
|
|
|
|
FcChar8 *subdir;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcBool ret = FcTrue;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return FcFalse;
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2016-01-09 03:06:31 +01:00
|
|
|
subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
|
2002-05-21 19:06:22 +02:00
|
|
|
if (!subdirs)
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
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)
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
|
|
|
FcStrSetDestroy (subdirs);
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
FcConfigSetFonts (config, set, FcSetApplication);
|
|
|
|
}
|
2022-12-05 13:40:26 +01:00
|
|
|
|
2017-08-04 17:31:52 +02:00
|
|
|
if (!FcFileScanConfig (set, subdirs, file, config))
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
|
|
|
FcStrSetDestroy (subdirs);
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
2015-06-27 02:02:13 +02:00
|
|
|
if ((sublist = FcStrListCreate (subdirs)))
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
|
|
|
while ((subdir = FcStrListNext (sublist)))
|
|
|
|
{
|
2015-06-27 02:02:13 +02:00
|
|
|
FcConfigAppFontAddDir (config, subdir);
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
|
|
|
FcStrListDone (sublist);
|
|
|
|
}
|
2006-02-04 01:09:42 +01:00
|
|
|
FcStrSetDestroy (subdirs);
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigAppFontAddDir (FcConfig *config,
|
2002-02-15 07:01:28 +01:00
|
|
|
const FcChar8 *dir)
|
2002-02-15 00:34:13 +01:00
|
|
|
{
|
|
|
|
FcFontSet *set;
|
2006-09-15 09:23:40 +02:00
|
|
|
FcStrSet *dirs;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcBool ret = FcTrue;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
2002-02-15 00:34:13 +01:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return FcFalse;
|
2006-09-15 09:23:40 +02:00
|
|
|
|
2016-01-09 03:06:31 +01:00
|
|
|
dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
|
2006-09-15 09:23:40 +02:00
|
|
|
if (!dirs)
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
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)
|
2002-05-21 19:06:22 +02:00
|
|
|
{
|
2015-06-27 02:02:13 +02:00
|
|
|
FcStrSetDestroy (dirs);
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
2002-05-21 19:06:22 +02:00
|
|
|
}
|
2002-02-15 00:34:13 +01:00
|
|
|
FcConfigSetFonts (config, set, FcSetApplication);
|
|
|
|
}
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-15 09:23:40 +02:00
|
|
|
FcStrSetAddFilename (dirs, dir);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-15 09:23:40 +02:00
|
|
|
if (!FcConfigAddDirList (config, FcSetApplication, dirs))
|
2015-06-27 02:02:13 +02:00
|
|
|
{
|
|
|
|
FcStrSetDestroy (dirs);
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
2015-06-27 02:02:13 +02:00
|
|
|
}
|
2006-09-15 09:23:40 +02:00
|
|
|
FcStrSetDestroy (dirs);
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcConfigAppFontClear (FcConfig *config)
|
|
|
|
{
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
2003-09-01 07:11:17 +02:00
|
|
|
if (!config)
|
2019-11-01 06:43:42 +01:00
|
|
|
return;
|
2003-09-01 07:11:17 +02:00
|
|
|
|
2002-02-15 00:34:13 +01:00
|
|
|
FcConfigSetFonts (config, 0, FcSetApplication);
|
2019-11-01 06:43:42 +01:00
|
|
|
|
|
|
|
FcConfigDestroy (config);
|
2002-02-15 00:34:13 +01:00
|
|
|
}
|
2003-05-07 18:13:24 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Manage filename-based font source selectors
|
|
|
|
*/
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigGlobAdd (FcConfig *config,
|
|
|
|
const FcChar8 *glob,
|
|
|
|
FcBool accept)
|
|
|
|
{
|
|
|
|
FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
|
2023-01-24 21:00:57 +01:00
|
|
|
FcChar8 *realglob = FcStrCopyFilename(glob);
|
|
|
|
if (!realglob)
|
|
|
|
return FcFalse;
|
2003-05-07 18:13:24 +02:00
|
|
|
|
2023-01-24 21:00:57 +01:00
|
|
|
FcBool ret = FcStrSetAdd (set, realglob);
|
|
|
|
FcStrFree(realglob);
|
|
|
|
return ret;
|
2003-05-07 18:13:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static FcBool
|
|
|
|
FcConfigGlobsMatch (const FcStrSet *globs,
|
|
|
|
const FcChar8 *string)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < globs->num; i++)
|
2013-05-08 04:57:49 +02:00
|
|
|
if (FcStrGlobMatch (globs->strs[i], string))
|
2003-05-07 18:13:24 +02:00
|
|
|
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;
|
|
|
|
}
|
2004-12-04 20:41:10 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
2004-12-04 20:41:10 +01: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;
|
|
|
|
}
|
2013-02-06 11:35:30 +01:00
|
|
|
|
|
|
|
const FcChar8 *
|
|
|
|
FcConfigGetSysRoot (const FcConfig *config)
|
|
|
|
{
|
|
|
|
if (!config)
|
|
|
|
{
|
|
|
|
config = FcConfigGetCurrent ();
|
|
|
|
if (!config)
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-10-30 01:00:28 +01:00
|
|
|
return config->sysRoot;
|
2013-02-06 11:35:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcConfigSetSysRoot (FcConfig *config,
|
|
|
|
const FcChar8 *sysroot)
|
|
|
|
{
|
2014-07-04 11:04:52 +02:00
|
|
|
FcChar8 *s = NULL;
|
2013-02-06 11:35:30 +01:00
|
|
|
FcBool init = FcFalse;
|
2019-11-01 16:14:48 +01:00
|
|
|
int nretry = 3;
|
2013-02-06 11:35:30 +01:00
|
|
|
|
2019-11-01 16:14:48 +01:00
|
|
|
retry:
|
2013-02-06 11:35:30 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-04 11:04:52 +02:00
|
|
|
if (sysroot)
|
|
|
|
{
|
2021-10-11 11:35:58 +02:00
|
|
|
s = FcStrRealPath (sysroot);
|
2014-07-04 11:04:52 +02:00
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
}
|
2013-02-06 11:35:30 +01:00
|
|
|
|
|
|
|
if (config->sysRoot)
|
|
|
|
FcStrFree (config->sysRoot);
|
|
|
|
|
|
|
|
config->sysRoot = s;
|
|
|
|
if (init)
|
|
|
|
{
|
|
|
|
config = FcInitLoadOwnConfigAndFonts (config);
|
2019-11-01 16:14:48 +01:00
|
|
|
if (!config)
|
|
|
|
{
|
|
|
|
/* Something failed. this is usually unlikely. so retrying */
|
|
|
|
init = FcFalse;
|
|
|
|
if (--nretry == 0)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "Fontconfig warning: Unable to initialize config and retry limit exceeded. sysroot functionality may not work as expected.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
goto retry;
|
|
|
|
}
|
2013-02-06 11:35:30 +01:00
|
|
|
FcConfigSetCurrent (config);
|
2014-08-12 11:48:00 +02:00
|
|
|
/* FcConfigSetCurrent() increases the refcount.
|
|
|
|
* decrease it here to avoid the memory leak.
|
|
|
|
*/
|
|
|
|
FcConfigDestroy (config);
|
2013-02-06 11:35:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-27 07:10:44 +01:00
|
|
|
FcRuleSet *
|
|
|
|
FcRuleSetCreate (const FcChar8 *name)
|
|
|
|
{
|
|
|
|
FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet));
|
|
|
|
FcMatchKind k;
|
|
|
|
const FcChar8 *p;
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
p = (const FcChar8 *)"";
|
|
|
|
else
|
|
|
|
p = name;
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
ret->name = FcStrdup (p);
|
|
|
|
ret->description = NULL;
|
|
|
|
ret->domain = NULL;
|
|
|
|
for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
|
2018-06-08 21:31:15 +02:00
|
|
|
ret->subst[k] = FcPtrListCreate (FcDestroyAsRule);
|
2014-03-27 07:10:44 +01:00
|
|
|
FcRefInit (&ret->ref, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcRuleSetDestroy (FcRuleSet *rs)
|
|
|
|
{
|
|
|
|
FcMatchKind k;
|
|
|
|
|
|
|
|
if (!rs)
|
|
|
|
return;
|
|
|
|
if (FcRefDec (&rs->ref) != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rs->name)
|
|
|
|
FcStrFree (rs->name);
|
|
|
|
if (rs->description)
|
|
|
|
FcStrFree (rs->description);
|
|
|
|
if (rs->domain)
|
|
|
|
FcStrFree (rs->domain);
|
|
|
|
for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
|
|
|
|
FcPtrListDestroy (rs->subst[k]);
|
|
|
|
|
|
|
|
free (rs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcRuleSetReference (FcRuleSet *rs)
|
|
|
|
{
|
|
|
|
if (!FcRefIsConst (&rs->ref))
|
|
|
|
FcRefInc (&rs->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcRuleSetEnable (FcRuleSet *rs,
|
|
|
|
FcBool flag)
|
|
|
|
{
|
|
|
|
if (rs)
|
|
|
|
{
|
|
|
|
rs->enabled = flag;
|
|
|
|
/* XXX: we may want to provide a feature
|
|
|
|
* to enable/disable rulesets through API
|
|
|
|
* in the future?
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcRuleSetAddDescription (FcRuleSet *rs,
|
|
|
|
const FcChar8 *domain,
|
|
|
|
const FcChar8 *description)
|
|
|
|
{
|
|
|
|
if (rs->domain)
|
|
|
|
FcStrFree (rs->domain);
|
|
|
|
if (rs->description)
|
|
|
|
FcStrFree (rs->description);
|
|
|
|
|
|
|
|
rs->domain = domain ? FcStrdup (domain) : NULL;
|
2018-01-03 14:15:11 +01:00
|
|
|
rs->description = description ? FcStrdup (description) : NULL;
|
2014-03-27 07:10:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
FcRuleSetAdd (FcRuleSet *rs,
|
|
|
|
FcRule *rule,
|
|
|
|
FcMatchKind kind)
|
|
|
|
{
|
|
|
|
FcPtrListIter iter;
|
|
|
|
FcRule *r;
|
|
|
|
int n = 0, ret;
|
|
|
|
|
|
|
|
if (!rs ||
|
|
|
|
kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
|
|
|
|
return -1;
|
|
|
|
FcPtrListIterInitAtLast (rs->subst[kind], &iter);
|
|
|
|
if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (r = rule; r; r = r->next)
|
|
|
|
{
|
|
|
|
switch (r->type)
|
|
|
|
{
|
|
|
|
case FcRuleTest:
|
2018-07-19 09:55:40 +02:00
|
|
|
if (r->u.test)
|
|
|
|
{
|
|
|
|
if (r->u.test->kind == FcMatchDefault)
|
|
|
|
r->u.test->kind = kind;
|
|
|
|
if (n < r->u.test->object)
|
|
|
|
n = r->u.test->object;
|
|
|
|
}
|
2014-03-27 07:10:44 +01:00
|
|
|
break;
|
|
|
|
case FcRuleEdit:
|
|
|
|
if (n < r->u.edit->object)
|
|
|
|
n = r->u.edit->object;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (FcDebug () & FC_DBG_EDIT)
|
|
|
|
{
|
2018-01-03 14:15:11 +01:00
|
|
|
printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name);
|
2014-03-27 07:10:44 +01:00
|
|
|
FcRulePrint (rule);
|
|
|
|
}
|
|
|
|
ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
|
|
|
|
|
|
|
|
return ret < 0 ? 0 : ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcConfigFileInfoIterInit (FcConfig *config,
|
|
|
|
FcConfigFileInfoIter *iter)
|
|
|
|
{
|
|
|
|
FcConfig *c;
|
|
|
|
FcPtrListIter *i = (FcPtrListIter *)iter;
|
|
|
|
|
|
|
|
if (!config)
|
|
|
|
c = FcConfigGetCurrent ();
|
|
|
|
else
|
|
|
|
c = config;
|
|
|
|
FcPtrListIterInit (c->rulesetList, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigFileInfoIterNext (FcConfig *config,
|
|
|
|
FcConfigFileInfoIter *iter)
|
|
|
|
{
|
|
|
|
FcConfig *c;
|
|
|
|
FcPtrListIter *i = (FcPtrListIter *)iter;
|
|
|
|
|
|
|
|
if (!config)
|
|
|
|
c = FcConfigGetCurrent ();
|
|
|
|
else
|
|
|
|
c = config;
|
|
|
|
if (FcPtrListIterIsValid (c->rulesetList, i))
|
|
|
|
{
|
|
|
|
FcPtrListIterNext (c->rulesetList, i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcConfigFileInfoIterGet (FcConfig *config,
|
|
|
|
FcConfigFileInfoIter *iter,
|
|
|
|
FcChar8 **name,
|
|
|
|
FcChar8 **description,
|
|
|
|
FcBool *enabled)
|
|
|
|
{
|
|
|
|
FcConfig *c;
|
|
|
|
FcRuleSet *r;
|
|
|
|
FcPtrListIter *i = (FcPtrListIter *)iter;
|
|
|
|
|
|
|
|
if (!config)
|
|
|
|
c = FcConfigGetCurrent ();
|
|
|
|
else
|
|
|
|
c = config;
|
|
|
|
if (!FcPtrListIterIsValid (c->rulesetList, i))
|
|
|
|
return FcFalse;
|
|
|
|
r = FcPtrListIterGetValue (c->rulesetList, i);
|
|
|
|
if (name)
|
|
|
|
*name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf");
|
|
|
|
if (description)
|
|
|
|
*description = FcStrdup (!r->description ? _("No description") :
|
|
|
|
dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf",
|
|
|
|
(const char *) r->description));
|
|
|
|
if (enabled)
|
|
|
|
*enabled = r->enabled;
|
|
|
|
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
2006-09-05 11:24:01 +02:00
|
|
|
#define __fccfg__
|
|
|
|
#include "fcaliastail.h"
|
|
|
|
#undef __fccfg__
|