summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--COPYING22
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL3
-rw-r--r--Imakefile25
-rw-r--r--NEWS0
-rw-r--r--README2
-rw-r--r--acconfig.h2
-rw-r--r--configure.in202
-rw-r--r--cvscompile.sh6
-rw-r--r--doc/fontconfig.tex55
-rw-r--r--fc-cache/Imakefile19
-rw-r--r--fc-cache/fc-cache.c145
-rw-r--r--fc-cache/fc-cache.man45
-rw-r--r--fc-list/Imakefile17
-rw-r--r--fc-list/fc-list.c128
-rw-r--r--fc-list/fc-list.man36
-rwxr-xr-xfindfonts8
-rw-r--r--fontconfig/Imakefile8
-rw-r--r--fontconfig/fcfreetype.h34
-rw-r--r--fontconfig/fcprivate.h117
-rw-r--r--fontconfig/fcxml.h37
-rw-r--r--fontconfig/fontconfig.h551
-rw-r--r--fonts.conf.in191
-rw-r--r--fonts.dtd165
-rwxr-xr-xsetfontdirs19
-rw-r--r--src/Imakefile90
-rw-r--r--src/fcblanks.c84
-rw-r--r--src/fccache.c592
-rw-r--r--src/fccfg.c1369
-rw-r--r--src/fccharset.c1521
-rw-r--r--src/fcdbg.c272
-rw-r--r--src/fcdefault.c87
-rw-r--r--src/fcdir.c178
-rw-r--r--src/fcfreetype.c236
-rw-r--r--src/fcfs.c82
-rw-r--r--src/fcinit.c174
-rw-r--r--src/fcint.h480
-rw-r--r--src/fclist.c442
-rw-r--r--src/fcmatch.c347
-rw-r--r--src/fcmatrix.c112
-rw-r--r--src/fcname.c621
-rw-r--r--src/fcpat.c491
-rw-r--r--src/fcstr.c188
-rw-r--r--src/fcxml.c1032
-rw-r--r--src/fontconfig.man1113
46 files changed, 11349 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..9cee037
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Keith Packard <keithp@keithp.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..6a4d888
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+$XFree86: $
+
+Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Keith Packard not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. Keith Packard makes no
+representations about the suitability of this software for any purpose. It
+is provided "as is" without express or implied warranty.
+
+KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+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.
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..6798b36
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,3 @@
+The configuration files (fonts.conf, fonts.dtd) go in a new directory
+/etc/fonts, the install step doesn't current create this directory or copy
+the config files.
diff --git a/Imakefile b/Imakefile
new file mode 100644
index 0000000..3c26d2d
--- /dev/null
+++ b/Imakefile
@@ -0,0 +1,25 @@
+#define IHaveSubdirs
+#define PassCDebugFlags
+
+LINTSUBDIRS=src fc-cache fc-list
+
+SUBDIRS=fontconfig $(LINTSUBDIRS)
+
+#ifndef FontconfigDir
+#define FontconfigDir /etc/fonts
+#endif
+
+FONTCONFIGDIR=FontconfigDir
+
+MakeSubdirs($(SUBDIRS))
+DependSubdirs($(SUBDIRS))
+MakeLintLibSubdirs($(LINTSUBDIRS))
+MakeLintSubdirs($(LINTSUBDIRS),install.ln,install.ln)
+
+InstallNonExecFileNoClobber(fonts.conf,$(FONTCONFIGDIR))
+InstallNonExecFileNoClobber(fonts.dtd,$(FONTCONFIGDIR))
+
+all:: fonts.conf
+
+fonts.conf: fonts.conf.in
+ sh ./setfontdirs
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..98f0fca
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+ Fontconfig
+ Font configuration and customization library
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..8ed6317
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,2 @@
+#undef HAVE_FREETYPE
+#undef FC_FALLBACK_FONTS
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..0cfcba0
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,202 @@
+AC_INIT(fontconfig/fontconfig.h)
+
+AC_PREREQ(2.13)
+
+FC_MAJOR=1
+FC_MINOR=0
+FC_SUB=1
+FC_PRE=
+FC_IFACE_AGE=0
+FC_BIN_AGE=0
+
+AC_SUBST(FC_MAJOR)
+AC_SUBST(FC_MINOR)
+AC_SUBST(FC_SUB)
+AC_SUBST(FC_IFACE_AGE)
+AC_SUBST(FC_BIN_AGE)
+
+LT_RELEASE=$FC_MAJOR.$FC_MINOR
+LT_CURRENT=`expr $FC_SUB - $FC_IFACE_AGE`
+LT_REVISION=$FC_IFACE_AGE
+LT_AGE=`expr $FC_BIN_AGE - $FC_IFACE_AGE`
+AC_SUBST(LT_RELEASE)
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+
+AM_INIT_AUTOMAKE("fontconfig", $FC_MAJOR.$FC_MINOR.$FC_SUB$FC_PRE)
+
+AC_CANONICAL_HOST
+AM_CONFIG_HEADER(config.h)
+
+AC_ARG_WITH(freetype_includes, [ --with-freetype-includes=DIR Use FreeType includes in DIR], freetype_includes=$withval, freetype_includes=yes)
+AC_ARG_WITH(freetype_lib, [ --with-freetype-lib=DIR Use FreeType library in DIR], freetype_lib=$withval, freetype_lib=yes)
+AC_ARG_WITH(freetype_config, [ --with-freeetype-config=PROG Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes)
+AC_ARG_WITH(xml2_includes, [ --with-xml2-includes=DIR Use xml2 includes in DIR], xml2_includes=$withval, xml2_includes=yes)
+AC_ARG_WITH(xml2_lib, [ --with-xml2-lib=DIR Use xml2 library in DIR], xml2_lib=$withval, xml2_lib=yes)
+AC_ARG_WITH(xml2_config, [ --with-freeetype-config=PROG Use FreeType configuration program PROG], xml2_config=$withval, xml2_config=yes)
+AC_ARG_WITH(fallback_fonts, [ --with-fallback-fonts=DIR Use fonts from DIR when config is busted], fallback_fonts="$withval", fallback_fonts=yes)
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+
+AC_PROG_LN_S
+
+dnl
+dnl Libtool
+dnl
+AM_DISABLE_STATIC
+AM_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+if libtool --features | grep "enable static" >/dev/null; then
+ STATIC="-static"
+else
+ STATIC=
+fi
+AC_SUBST(STATIC)
+
+AC_SUBST(DEBUG_CFLAGS)
+AC_SUBST(GLOBAL_CFLAGS)
+
+AC_CHECK_FUNCS(getopt_long getopt)
+
+case "$freetype_config" in
+no)
+ ;;
+yes)
+ AC_CHECK_PROG(ft_config, freetype-config, freetype-config, no)
+ ;;
+*)
+ ft_config="$freetype_config"
+ ;;
+esac
+
+case "$freetype_includes" in
+no)
+ freetype_includes=""
+ ;;
+yes)
+ case "$ft_config" in
+ no)
+ freetype_includes=""
+ ;;
+ *)
+ freetype_includes="`$ft_config --cflags`"
+ ;;
+ esac
+ ;;
+*)
+ freetype_includes="-I$freetype_includes"
+ ;;
+esac
+
+case "$freetype_lib" in
+no)
+ freetype_lib=""
+ ;;
+yes)
+ case "$ft_config" in
+ no)
+ freetype_lib=""
+ ;;
+ *)
+ freetype_lib="`$ft_config --libs`"
+ ;;
+ esac
+ ;;
+*)
+ freetype_lib="-L$freetype_lib -lfreetype"
+ ;;
+esac
+
+case "$fallback_fonts" in
+yes)
+ AC_DEFINE_UNQUOTED(FC_FALLBACK_FONTS, "/usr/X11R6/lib/X11/fonts/Type1")
+ ;;
+*)
+ AC_DEFINE_UNQUOTED(FC_FALLBACK_FONTS, "$fallback_fonts")
+ ;;
+esac
+
+saved_LIBS="$LIBS"
+LIBS="$LIBS $freetype_lib"
+saved_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $freetype_includes"
+AC_CHECK_HEADERS(ft2build.h)
+
+case "$ac_cv_header_ft2build_h" in
+no)
+ CPPFLAGS="$saved_CPPFLAGS"
+ LIBS="$saved_LIBS"
+ ;;
+yes)
+ AC_CHECK_FUNCS(FT_Init_FreeType)
+ case "$ac_cv_func_FT_Init_FreeType" in
+ no)
+ CPPFLAGS="$saved_CPPFLAGS"
+ LIBS="$saved_LIBS"
+ ;;
+ yes)
+ AC_DEFINE(HAVE_FREETYPE)
+ ;;
+ esac
+ ;;
+esac
+
+case "$xml2_config" in
+no)
+ ;;
+yes)
+ AC_CHECK_PROG(xml2_config_prog, xml2-config, xml2-config, no)
+ ;;
+*)
+ ;;
+esac
+
+case "$xml2_includes" in
+no)
+ xml2_includes=""
+ ;;
+yes)
+ case "$xml2_config_prog" in
+ no)
+ xml2_includes=""
+ ;;
+ *)
+ xml2_includes="`$xml2_config_prog --cflags`"
+ ;;
+ esac
+ ;;
+*)
+ xml2_includes="-I$xml2_includes"
+ ;;
+esac
+
+case "$xml2_lib" in
+no)
+ xml2_lib=""
+ ;;
+yes)
+ case "$xml2_config_prog" in
+ no)
+ xml2_lib=""
+ ;;
+ *)
+ xml2_lib="`$xml2_config_prog --libs`"
+ ;;
+ esac
+ ;;
+*)
+ xml2_lib="-L$xml2_lib -lxml2"
+ ;;
+esac
+
+saved_LIBS="$LIBS"
+LIBS="$LIBS $xml2_lib"
+saved_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $xml2_includes"
+AC_CHECK_HEADERS(xmlversion.h)
+
+AC_OUTPUT(Makefile src/Makefile fontconfig/Makefile fc-cache/Makefile fc-list/Makefile)
diff --git a/cvscompile.sh b/cvscompile.sh
new file mode 100644
index 0000000..371f458
--- /dev/null
+++ b/cvscompile.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+aclocal
+autoheader
+automake -a
+autoconf
+
diff --git a/doc/fontconfig.tex b/doc/fontconfig.tex
new file mode 100644
index 0000000..2e60a51
--- /dev/null
+++ b/doc/fontconfig.tex
@@ -0,0 +1,55 @@
+\documentclass[10pt]{article}
+\usepackage{latexsym}
+\usepackage{epsfig}
+\usepackage{times}
+
+\begin{document}
+\date{}
+\title{The Fontconfig Library:\\
+Architecture and Users Guide}
+\author{Keith Packard\\
+{\em XFree86 Core Team}\\
+keithp@keithp.com}
+\maketitle
+\thispagestyle{empty}
+
+\abstract
+
+The Fontconfig library provides for central administration and configuration
+of fonts in a POSIX system. All font consumers can share a common database
+of fonts and use common matching rules for font names. The set of available
+fonts can be configured for each user and a set of configurable matching
+rules allow for customizing the selection of fonts and configuring various
+parameters related to rasterizing of those fonts for display in a variety of
+media. The Fontconfig library is designed to co-exist peacefully with
+existing font configuration and rasterization mechanisms; while it uses the
+FreeType library to discover characteristics of available fonts, there
+is no requirement to use FreeType for rasterization.
+
+\section {Introduction}
+
+\section {Configuration Files}
+
+\section {Application Interface}
+
+\subsection {Datatypes}
+
+\subsection {Font Set Interface}
+
+\subsection {Font Patterns}
+
+\subsection {Listing Available Fonts}
+
+\subsection {Using Font Names}
+
+\subsection {Manipulating Matrices}
+
+\subsection {UTF-8 Helper Functions}
+
+\section {Font Sub-System Interface}
+
+\subsection {Extending Font Names}
+
+\subsection {Executing Configuration Rules}
+
+\end{document}
diff --git a/fc-cache/Imakefile b/fc-cache/Imakefile
new file mode 100644
index 0000000..12216e7
--- /dev/null
+++ b/fc-cache/Imakefile
@@ -0,0 +1,19 @@
+#include "../../libxml2/config.h"
+#if HAVE_ZLIB_H
+ZLIB=-lz
+#endif
+
+INCLUDES=-I../../freetype2 -I/usr/include/libxml2 -I..
+FREETYPE2REQLIB = ../../freetype2/libfreetype.a
+XML2REQLIB=../../libxml2/.libs/libxml2.a $(ZLIB) -lm
+
+LOCAL_LIBRARIES=-L../src -lfontconfig $(FREETYPE2REQLIB) $(XML2REQLIB)
+
+SRCS=fc-cache.c
+OBJS=fc-cache.o
+
+ComplexProgramTarget(fc-cache)
+LinkBuildBinary(ProgramTargetName(fc-cache))
+
+install::
+ FC_DEBUG=128 FONTCONFIG_PATH=.. ./fc-cache -v
diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c
new file mode 100644
index 0000000..6e84ccd
--- /dev/null
+++ b/fc-cache/fc-cache.c
@@ -0,0 +1,145 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#define HAVE_GETOPT 1
+#endif
+
+#if HAVE_GETOPT_LONG
+#define _GNU_SOURCE
+#include <getopt.h>
+const struct option longopts[] = {
+ {"version", 0, 0, 'V'},
+ {"verbose", 0, 0, 'v'},
+ {"help", 0, 0, '?'},
+ {NULL,0,0,0},
+};
+#else
+#if HAVE_GETOPT
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+#endif
+
+void usage (char *program)
+{
+ fprintf (stderr, "usage: %s [-vV?] [--verbose] [--version] [--help] [dirs]\n",
+ program);
+ fprintf (stderr, "Build font information caches in [dirs]\n"
+ "(all directories in font configuration by default).\n");
+ fprintf (stderr, "\n");
+ fprintf (stderr, " -v, --verbose display status information while busy\n");
+ fprintf (stderr, " -V, --version display font config version and exit\n");
+ fprintf (stderr, " -?, --help display this help and exit\n");
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0;
+ FcFontSet *set;
+ char **dirs;
+ int verbose = 0;
+ int i;
+#if HAVE_GETOPT_LONG || HAVE_GETOPT
+ int c;
+
+#if HAVE_GETOPT_LONG
+ while ((c = getopt_long (argc, argv, "Vv?", longopts, NULL)) != -1)
+#else
+ while ((c = getopt (argc, argv, "Vv?")) != -1)
+#endif
+ {
+ switch (c) {
+ case 'V':
+ fprintf (stderr, "fontconfig version %d.%d.%d\n",
+ FC_MAJOR, FC_MINOR, FC_REVISION);
+ exit (0);
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage (argv[0]);
+ }
+ }
+ i = optind;
+#else
+ i = 1;
+#endif
+
+ if (!FcInitConfig ())
+ {
+ fprintf (stderr, "Can't init font config library\n");
+ return 1;
+ }
+ if (argv[i])
+ dirs = argv+i;
+ else
+ dirs = FcConfigGetDirs (0);
+ /*
+ * Now scan all of the directories into separate databases
+ * and write out the results
+ */
+ while (dirs && *dirs)
+ {
+ if (verbose)
+ printf ("%s: Scanning directory \"%s\"\n", argv[0], *dirs);
+ set = FcFontSetCreate ();
+ if (!set)
+ {
+ fprintf (stderr, "Out of memory in \"%s\"\n", *dirs);
+ ret++;
+ }
+ else
+ {
+ if (!FcDirScan (set, 0, FcConfigGetBlanks (0), *dirs, FcTrue))
+ {
+ fprintf (stderr, "Can't scan directory \"%s\"\n", *dirs);
+ ret++;
+ }
+ else
+ {
+ if (verbose)
+ printf ("%s: Saving %d font names for \"%s\"\n",
+ argv[0], set->nfont, *dirs);
+ if (!FcDirSave (set, *dirs))
+ {
+ fprintf (stderr, "Can't save cache in \"%s\"\n", *dirs);
+ ret++;
+ }
+ }
+ FcFontSetDestroy (set);
+ }
+ ++dirs;
+ }
+ if (verbose)
+ printf ("%s: %s\n", argv[0], ret ? "failed" : "succeeded");
+ return ret;
+}
diff --git a/fc-cache/fc-cache.man b/fc-cache/fc-cache.man
new file mode 100644
index 0000000..6fc4ed9
--- /dev/null
+++ b/fc-cache/fc-cache.man
@@ -0,0 +1,45 @@
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission. Keith Packard makes no
+.\" representations about the suitability of this software for any purpose. It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" 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.
+.\"
+.\"
+.\" $XFree86: xc/programs/fc-cache/fc-cache.man,v 1.3 2001/02/09 03:47:56 tsi Exp $
+.\"
+.TH FC-CACHE 1 __vendorversion__
+.SH NAME
+fc-cache, fonts.cache \- create an index of FreeType font files in a directory
+.SH SYNOPSIS
+.B "fc-cache"
+.RI [ directory-name
+\|.\|.\|. ]
+.SH DESCRIPTION
+If directory arguments are not given,
+.I fc-cache
+uses each directory in the current font configuration. Each directory is
+scanned for font files readable by FreeType. A cache is created which
+contains properties of each font and the associated filename. This cache is
+used to speed application startup when using the fontconfig library.
+.SH FILES
+.TP 15
+.B fonts.cache
+Maps file names to font properties. Read by the fontconfig library at
+application startup to locate appropriate fonts.
+.SH "SEE ALSO"
+fontconfig(3)
diff --git a/fc-list/Imakefile b/fc-list/Imakefile
new file mode 100644
index 0000000..a773b45
--- /dev/null
+++ b/fc-list/Imakefile
@@ -0,0 +1,17 @@
+#include "../../libxml2/config.h"
+#if HAVE_ZLIB_H
+ZLIB=-lz
+#endif
+
+INCLUDES=-I../../freetype2 -I/usr/include/libxml2 -I..
+FREETYPE2REQLIB = ../../freetype2/libfreetype.a
+XML2REQLIB=../../libxml2/.libs/libxml2.a $(ZLIB) -lm
+
+LOCAL_LIBRARIES=-L../src -lfontconfig $(FREETYPE2REQLIB) $(XML2REQLIB)
+DEPLIBS=../src/libfontconfig.a
+
+SRCS=fc-list.c
+OBJS=fc-list.o
+
+ComplexProgramTarget(fc-list)
+LinkBuildBinary(ProgramTargetName(fc-list))
diff --git a/fc-list/fc-list.c b/fc-list/fc-list.c
new file mode 100644
index 0000000..67d7120
--- /dev/null
+++ b/fc-list/fc-list.c
@@ -0,0 +1,128 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#define HAVE_GETOPT 1
+#endif
+
+#if HAVE_GETOPT_LONG
+#define _GNU_SOURCE
+#include <getopt.h>
+const struct option longopts[] = {
+ {"version", 0, 0, 'V'},
+ {"verbose", 0, 0, 'v'},
+ {"help", 0, 0, '?'},
+ {NULL,0,0,0},
+};
+#else
+#if HAVE_GETOPT
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+#endif
+
+void usage (char *program)
+{
+ fprintf (stderr, "usage: %s [-vV?] [--verbose] [--version] [--help] [dirs]\n",
+ program);
+ fprintf (stderr, "Build font information caches in [dirs]\n"
+ "(all directories in font configuration by default).\n");
+ fprintf (stderr, "\n");
+ fprintf (stderr, " -v, --verbose display status information while busy\n");
+ fprintf (stderr, " -V, --version display font config version and exit\n");
+ fprintf (stderr, " -?, --help display this help and exit\n");
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0;
+ FcFontSet *set;
+ int verbose = 0;
+ int i;
+ FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_LANG, 0);
+ FcFontSet *fs;
+ FcPattern *pat;
+#if HAVE_GETOPT_LONG || HAVE_GETOPT
+ int c;
+
+#if HAVE_GETOPT_LONG
+ while ((c = getopt_long (argc, argv, "Vv?", longopts, NULL)) != -1)
+#else
+ while ((c = getopt (argc, argv, "Vv?")) != -1)
+#endif
+ {
+ switch (c) {
+ case 'V':
+ fprintf (stderr, "fontconfig version %d.%d.%d\n",
+ FC_MAJOR, FC_MINOR, FC_REVISION);
+ exit (0);
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage (argv[0]);
+ }
+ }
+ i = optind;
+#else
+ i = 1;
+#endif
+
+ if (!FcInit ())
+ {
+ fprintf (stderr, "Can't init font config library\n");
+ return 1;
+ }
+ if (argv[i])
+ pat = FcNameParse (argv[i]);
+ else
+ pat = FcPatternCreate ();
+
+ fs = FcFontList (0, pat, os);
+ if (pat)
+ FcPatternDestroy (pat);
+
+ if (fs)
+ {
+ int j;
+
+ for (j = 0; j < fs->nfont; j++)
+ {
+ FcChar8 *font;
+
+ font = FcNameUnparse (fs->fonts[j]);
+ printf ("%s\n", font);
+ free (font);
+ }
+ FcFontSetDestroy (fs);
+ }
+ return 0;
+}
diff --git a/fc-list/fc-list.man b/fc-list/fc-list.man
new file mode 100644
index 0000000..87eb792
--- /dev/null
+++ b/fc-list/fc-list.man
@@ -0,0 +1,36 @@
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission. Keith Packard makes no
+.\" representations about the suitability of this software for any purpose. It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" 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.
+.\"
+.\"
+.\" $XFree86: xc/programs/fc-list/fc-list.man,v 1.3 2001/02/09 03:47:56 tsi Exp $
+.\"
+.TH FC-LIST 1 __vendorversion__
+.SH NAME
+fc-list \- list available fonts
+.SH SYNOPSIS
+.B "fc-list"
+.RI [ font-pattern ]
+.SH DESCRIPTION
+If font pattern is not given,
+.I fc-list
+lists all available faces and styles in the current font configuration.
+.SH "SEE ALSO"
+fontconfig(3)
diff --git a/findfonts b/findfonts
new file mode 100755
index 0000000..2666f8d
--- /dev/null
+++ b/findfonts
@@ -0,0 +1,8 @@
+#!/bin/sh
+dirs="/usr/share/fonts /usr/X11R6/lib/X11/fonts"
+for d in $dirs; do
+ find $d \( -name '*.[Tt][Tt][Ff]' -o -name '*.[Pp][Ff][BbAa]' \) -print
+done | while read f; do
+ dir=`dirname $f`
+ echo $dir
+done | sort -u | sed 's/^/ <dir>/' | sed 's;$;</dir>;'
diff --git a/fontconfig/Imakefile b/fontconfig/Imakefile
new file mode 100644
index 0000000..be1f65c
--- /dev/null
+++ b/fontconfig/Imakefile
@@ -0,0 +1,8 @@
+#define IncSubdir fontconfig
+
+HEADERS=fcfreetype.h fcprivate.h fcxml.h fontconfig.h
+
+BuildIncludes($(HEADERS),IncSubdir,..)
+#if BuildLibraries
+InstallMultipleFlags($(HEADERS),$(INCDIR)/IncSubdir,$(INSTINCFLAGS))
+#endif
diff --git a/fontconfig/fcfreetype.h b/fontconfig/fcfreetype.h
new file mode 100644
index 0000000..14f342b
--- /dev/null
+++ b/fontconfig/fcfreetype.h
@@ -0,0 +1,34 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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.
+ */
+
+#ifndef _FCFREETYPE_H_
+#define _FCFREETYPE_H_
+
+FT_UInt
+FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4);
+
+FcCharSet *
+FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks);
+
+#endif
diff --git a/fontconfig/fcprivate.h b/fontconfig/fcprivate.h
new file mode 100644
index 0000000..490ca33
--- /dev/null
+++ b/fontconfig/fcprivate.h
@@ -0,0 +1,117 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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.
+ */
+
+#ifndef _FCPRIVATE_H_
+#define _FCPRIVATE_H_
+
+/*
+ * I tried this with functions that took va_list* arguments
+ * but portability concerns made me change these functions
+ * into macros (sigh).
+ */
+
+#define FcPatternVapBuild(result, orig, va) \
+{ \
+ FcPattern *__p__ = (orig); \
+ const char *__o__; \
+ FcValue __v__; \
+ \
+ if (!__p__) \
+ { \
+ __p__ = FcPatternCreate (); \
+ if (!__p__) \
+ goto _FcPatternVapBuild_bail0; \
+ } \
+ for (;;) \
+ { \
+ __o__ = va_arg (va, const char *); \
+ if (!__o__) \
+ break; \
+ __v__.type = va_arg (va, FcType); \
+ switch (__v__.type) { \
+ case FcTypeVoid: \
+ goto _FcPatternVapBuild_bail1; \
+ case FcTypeInteger: \
+ __v__.u.i = va_arg (va, int); \
+ break; \
+ case FcTypeDouble: \
+ __v__.u.d = va_arg (va, double); \
+ break; \
+ case FcTypeString: \
+ __v__.u.s = va_arg (va, char *); \
+ break; \
+ case FcTypeBool: \
+ __v__.u.b = va_arg (va, FcBool); \
+ break; \
+ case FcTypeMatrix: \
+ __v__.u.m = va_arg (va, FcMatrix *); \
+ break; \
+ case FcTypeCharSet: \
+ __v__.u.c = va_arg (va, FcCharSet *); \
+ break; \
+ } \
+ if (!FcPatternAdd (__p__, __o__, __v__, FcTrue)) \
+ goto _FcPatternVapBuild_bail1; \
+ } \
+ result = __p__; \
+ goto _FcPatternVapBuild_return; \
+ \
+_FcPatternVapBuild_bail1: \
+ if (!orig) \
+ FcPatternDestroy (__p__); \
+_FcPatternVapBuild_bail0: \
+ result = 0; \
+ \
+_FcPatternVapBuild_return: \
+ ; \
+}
+
+
+#define FcObjectSetVapBuild(__ret__, __first__, __va__) \
+{ \
+ FcObjectSet *__os__; \
+ const char *__ob__; \
+ \
+ __ret__ = 0; \
+ __os__ = FcObjectSetCreate (); \
+ if (!__os__) \
+ goto _FcObjectSetVapBuild_bail0; \
+ __ob__ = __first__; \
+ while (__ob__) \
+ { \
+ if (!FcObjectSetAdd (__os__, __ob__)) \
+ goto _FcObjectSetVapBuild_bail1; \
+ __ob__ = va_arg (__va__, const char *); \
+ } \
+ __ret__ = __os__; \
+ \
+_FcObjectSetVapBuild_bail1: \
+ if (!__ret__ && __os__) \
+ FcObjectSetDestroy (__os__); \
+_FcObjectSetVapBuild_bail0: \
+ ; \
+}
+
+#endif /* _FCPRIVATE_H_ */
+
diff --git a/fontconfig/fcxml.h b/fontconfig/fcxml.h
new file mode 100644
index 0000000..b5d1b7d
--- /dev/null
+++ b/fontconfig/fcxml.h
@@ -0,0 +1,37 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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.
+ */
+
+#ifndef _FCXML_H_
+#define _FCXML_H_
+
+#include <libxml/parser.h>
+
+xmlDocPtr
+FcConfigLoad (const char *file);
+
+FcBool
+FcConfigParse (FcConfig *config,
+ xmlDocPtr doc);
+
+#endif /* _FCXML_H_ */
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
new file mode 100644
index 0000000..c7105e0
--- /dev/null
+++ b/fontconfig/fontconfig.h
@@ -0,0 +1,551 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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.
+ */
+
+#ifndef _FONTCONFIG_H_
+#define _FONTCONFIG_H_
+
+#include <stdarg.h>
+
+typedef unsigned char FcChar8;
+typedef unsigned short FcChar16;
+typedef unsigned int FcChar32;
+typedef int FcBool;
+
+/*
+ * Current Fontconfig version number
+ */
+#define FC_MAJOR 1
+#define FC_MINOR 0
+#define FC_REVISION 0
+
+#define FC_VERSION ((FC_MAJOR * 10000) + (FC_MINOR * 100) + (FC_REVISION))
+
+#define FcTrue 1
+#define FcFalse 0
+
+#define FC_FAMILY "family" /* String */
+#define FC_STYLE "style" /* String */
+#define FC_SLANT "slant" /* Int */
+#define FC_WEIGHT "weight" /* Int */
+#define FC_SIZE "size" /* Double */
+#define FC_PIXEL_SIZE "pixelsize" /* Double */
+#define FC_SPACING "spacing" /* Int */
+#define FC_FOUNDRY "foundry" /* String */
+#define FC_ANTIALIAS "antialias" /* Bool (depends) */
+#define FC_HINTING "hinting" /* Bool (true) */
+#define FC_VERTICAL_LAYOUT "verticallayout" /* Bool (false) */
+#define FC_AUTOHINT "autohint" /* Bool (false) */
+#define FC_GLOBAL_ADVANCE "globaladvance" /* Bool (true) */
+#define FC_FILE "file" /* String */
+#define FC_INDEX "index" /* Int */
+#define FC_RASTERIZER "rasterizer" /* String */
+#define FC_OUTLINE "outline" /* Bool */
+#define FC_SCALABLE "scalable" /* Bool */
+#define FC_SCALE "scale" /* double */
+#define FC_DPI "dpi" /* double */
+#define FC_RGBA "rgba" /* Int */
+#define FC_MINSPACE "minspace" /* Bool use minimum line spacing */
+#define FC_SOURCE "source" /* String (X11, freetype) */
+#define FC_CHARSET "charset" /* CharSet */
+#define FC_LANG "lang" /* String OS/2 CodePageRange */
+
+#define FC_DIR_CACHE_FILE "fonts.cache"
+#define FC_USER_CACHE_FILE ".fonts.cache"
+
+/* Adjust outline rasterizer */
+#define FC_CHAR_WIDTH "charwidth" /* Int */
+#define FC_CHAR_HEIGHT "charheight"/* Int */
+#define FC_MATRIX "matrix" /* FcMatrix */
+
+#define FC_WEIGHT_LIGHT 0
+#define FC_WEIGHT_MEDIUM 100
+#define FC_WEIGHT_DEMIBOLD 180
+#define FC_WEIGHT_BOLD 200
+#define FC_WEIGHT_BLACK 210
+
+#define FC_SLANT_ROMAN 0
+#define FC_SLANT_ITALIC 100
+#define FC_SLANT_OBLIQUE 110
+
+#define FC_PROPORTIONAL 0
+#define FC_MONO 100
+#define FC_CHARCELL 110
+
+/* sub-pixel order */
+#define FC_RGBA_NONE 0
+#define FC_RGBA_RGB 1
+#define FC_RGBA_BGR 2
+#define FC_RGBA_VRGB 3
+#define FC_RGBA_VBGR 4
+
+/* language groups from the OS/2 CodePageRange bits */
+#define FC_LANG_LATIN_1 "latin1" /* 0 */
+#define FC_LANG_LATIN_2_EASTERN_EUROPE "latin2easterneurope" /* 1 */
+#define FC_LANG_CYRILLIC "cyrillic" /* 2 */
+#define FC_LANG_GREEK "greek" /* 3 */
+#define FC_LANG_TURKISH "turkish" /* 4 */
+#define FC_LANG_HEBREW "hebrew" /* 5 */
+#define FC_LANG_ARABIC "arabic" /* 6 */
+#define FC_LANG_WINDOWS_BALTIC "windowsbaltic" /* 7 */
+#define FC_LANG_VIETNAMESE "vietnamese" /* 8 */
+/* 9-15 reserved for Alternate ANSI */
+#define FC_LANG_THAI "thai" /* 16 */
+#define FC_LANG_JAPANESE "japanese" /* 17 */
+#define FC_LANG_SIMPLIFIED_CHINESE "simplifiedchinese" /* 18 */
+#define FC_LANG_KOREAN_WANSUNG "koreanwansung" /* 19 */
+#define FC_LANG_TRADITIONAL_CHINESE "traditionalchinese" /* 20 */
+#define FC_LANG_KOREAN_JOHAB "koreanjohab" /* 21 */
+/* 22-28 reserved for Alternate ANSI & OEM */
+#define FC_LANG_MACINTOSH "macintosh" /* 29 */
+#define FC_LANG_OEM "oem" /* 30 */
+#define FC_LANG_SYMBOL "symbol" /* 31 */
+/* 32-47 reserved for OEM */
+#define FC_LANG_IBM_GREEK "ibmgreek" /* 48 */
+#define FC_LANG_MSDOS_RUSSIAN "msdosrussian" /* 49 */
+#define FC_LANG_MSDOS_NORDIC "msdosnordic" /* 50 */
+#define FC_LANG_ARABIC_864 "arabic864" /* 51 */
+#define FC_LANG_MSDOS_CANADIAN_FRENCH "msdoscanadianfrench" /* 52 */
+#define FC_LANG_HEBREW_862 "hebrew862" /* 53 */
+#define FC_LANG_MSDOS_ICELANDIC "msdosicelandic" /* 54 */
+#define FC_LANG_MSDOS_PORTUGUESE "msdosportuguese" /* 55 */
+#define FC_LANG_IBM_TURKISH "ibmturkish" /* 56 */
+#define FC_LANG_IBM_CYRILLIC "ibmcyrillic" /* 57 */
+#define FC_LANG_LATIN_2 "latin2" /* 58 */
+#define FC_LANG_MSDOS_BALTIC "msdosbaltic" /* 59 */
+#define FC_LANG_GREEK_437_G "greek437g" /* 60 */
+#define FC_LANG_ARABIC_ASMO_708 "arabicasmo708" /* 61 */
+#define FC_LANG_WE_LATIN_1 "welatin1" /* 62 */
+#define FC_LANG_US "us" /* 63 */
+
+typedef enum _FcType {
+ FcTypeVoid,
+ FcTypeInteger,
+ FcTypeDouble,
+ FcTypeString,
+ FcTypeBool,
+ FcTypeMatrix,
+ FcTypeCharSet
+} FcType;
+
+typedef struct _FcMatrix {
+ double xx, xy, yx, yy;
+} FcMatrix;
+
+#define FcMatrixInit(m) ((m)->xx = (m)->yy = 1, \
+ (m)->xy = (m)->yx = 0)
+
+/*
+ * A data structure to represent the available glyphs in a font.
+ * This is represented as a sparse boolean btree.
+ */
+
+typedef struct _FcCharSet FcCharSet;
+
+typedef struct _FcObjectType {
+ const char *object;
+ FcType type;
+} FcObjectType;
+
+typedef struct _FcConstant {
+ const char *name;
+ const char *object;
+ int value;
+} FcConstant;
+
+typedef enum _FcResult {
+ FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId
+} FcResult;
+
+typedef struct _FcValue {
+ FcType type;
+ union {
+ const FcChar8 *s;
+ int i;
+ FcBool b;
+ double d;
+ const FcMatrix *m;
+ const FcCharSet *c;
+ } u;
+} FcValue;
+
+typedef struct _FcPattern FcPattern;
+
+typedef struct _FcFontSet {
+ int nfont;
+ int sfont;
+ FcPattern **fonts;
+} FcFontSet;
+
+typedef struct _FcObjectSet {
+ int nobject;
+ int sobject;
+ const char **objects;
+} FcObjectSet;
+
+typedef enum _FcMatchKind {
+ FcMatchPattern, FcMatchFont
+} FcMatchKind;
+
+typedef enum _FcSetName {
+ FcSetSystem = 0,
+ FcSetApplication = 1
+} FcSetName;
+
+#if defined(__cplusplus) || defined(c_plusplus) /* for C++ V2.0 */
+#define _FCFUNCPROTOBEGIN extern "C" { /* do not leave open across includes */
+#define _FCFUNCPROTOEND }
+#else
+#define _FCFUNCPROTOBEGIN
+#define _FCFUNCPROTOEND
+#endif
+
+typedef struct _FcConfig FcConfig;
+
+typedef struct _FcFileCache FcFileCache;
+
+typedef struct _FcBlanks FcBlanks;
+
+_FCFUNCPROTOBEGIN
+
+/* fcblanks.c */
+FcBlanks *
+FcBlanksCreate (void);
+
+void
+FcBlanksDestroy (FcBlanks *b);
+
+FcBool
+FcBlanksAdd (FcBlanks *b, FcChar32 ucs4);
+
+FcBool
+FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4);
+
+/* fccfg.c */
+char *
+FcConfigFilename (const char *url);
+
+FcConfig *
+FcConfigCreate (void);
+
+void
+FcConfigDestroy (FcConfig *config);
+
+FcBool
+FcConfigSetCurrent (FcConfig *config);
+
+FcConfig *
+FcConfigGetCurrent (void);
+
+FcBool
+FcConfigBuildFonts (FcConfig *config);
+
+char **
+FcConfigGetDirs (FcConfig *config);
+
+char **
+FcConfigGetConfigFiles (FcConfig *config);
+
+char *
+FcConfigGetCache (FcConfig *config);
+
+FcBlanks *
+FcConfigGetBlanks (FcConfig *config);
+
+FcFontSet *
+FcConfigGetFonts (FcConfig *config,
+ FcSetName set);
+
+FcBool
+FcConfigAppFontAddFile (FcConfig *config,
+ const char *file);
+
+FcBool
+FcConfigAppFontAddDir (FcConfig *config,
+ const char *dir);
+
+void
+FcConfigAppFontClear (FcConfig *config);
+
+FcBool
+FcConfigSubstitute (FcConfig *config,
+ FcPattern *p,
+ FcMatchKind kind);
+
+/* fccharset.c */
+FcCharSet *
+FcCharSetCreate (void);
+
+void
+FcCharSetDestroy (FcCharSet *fcs);
+
+FcBool
+FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4);
+
+FcCharSet *
+FcCharSetCopy (FcCharSet *src);
+
+FcBool
+FcCharSetEqual (const FcCharSet *a, const FcCharSet *b);
+
+FcCharSet *
+FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b);
+
+FcCharSet *
+FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
+
+FcCharSet *
+FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b);
+
+FcBool
+FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4);
+
+FcChar32
+FcCharSetCount (const FcCharSet *a);
+
+FcChar32
+FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b);
+
+FcChar32
+FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b);
+
+#ifndef FONTCONFIG_NO_FREETYPE
+#include <freetype/freetype.h>
+FT_UInt
+FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4);
+#endif
+
+/* fcdbg.c */
+void
+FcPatternPrint (FcPattern *p);
+
+/* fcdefault.c */
+void
+FcDefaultSubstitute (FcPattern *pattern);
+
+/* fcdir.c */
+FcBool
+FcDirScan (FcFontSet *set,
+ FcFileCache *cache,
+ FcBlanks *blanks,
+ const char *dir,
+ FcBool force);
+
+FcBool
+FcDirSave (FcFontSet *set, const char *dir);
+
+/* fcfreetype.c */
+FcPattern *
+FcFreeTypeQuery (const char *file, int id, FcBlanks *blanks, int *count);
+
+/* fcfs.c */
+
+FcFontSet *
+FcFontSetCreate (void);
+
+void
+FcFontSetDestroy (FcFontSet *s);
+
+FcBool
+FcFontSetAdd (FcFontSet *s, FcPattern *font);
+
+/* fcinit.c */
+FcBool
+FcInitFonts (void);
+
+FcBool
+FcInitConfig (void);
+
+FcBool
+FcInit (void);
+
+/* fclist.c */
+FcObjectSet *
+FcObjectSetCreate (void);
+
+FcBool
+FcObjectSetAdd (FcObjectSet *os, const char *object);
+
+void
+FcObjectSetDestroy (FcObjectSet *os);
+
+FcObjectSet *
+FcObjectSetVaBuild (const char *first, va_list va);
+
+FcObjectSet *
+FcObjectSetBuild (const char *first, ...);
+
+FcFontSet *
+FcFontList (FcConfig *config,
+ FcPattern *p,
+ FcObjectSet *os);
+
+/* fcmatch.c */
+FcPattern *
+FcFontMatch (FcConfig *config,
+ FcPattern *p,
+ FcResult *result);
+
+/* fcmatrix.c */
+FcMatrix *
+FcMatrixCopy (const FcMatrix *mat);
+
+FcBool
+FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2);
+
+void
+FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b);
+
+void
+FcMatrixRotate (FcMatrix *m, double c, double s);
+
+void
+FcMatrixScale (FcMatrix *m, double sx, double sy);
+
+void
+FcMatrixShear (FcMatrix *m, double sh, double sv);
+
+/* fcname.c */
+
+FcBool
+FcNameRegisterObjectTypes (const FcObjectType *types, int ntype);
+
+FcBool
+FcNameUnregisterObjectTypes (const FcObjectType *types, int ntype);
+
+const FcObjectType *
+FcNameGetObjectType (const char *object);
+
+FcBool
+FcNameRegisterConstants (const FcConstant *consts, int nconsts);
+
+FcBool
+FcNameUnregisterConstants (const FcConstant *consts, int nconsts);
+
+const FcConstant *
+FcNameGetConstant (char *string);
+
+FcBool
+FcNameConstant (char *string, int *result);
+
+FcPattern *
+FcNameParse (const char *name);
+
+FcChar8 *
+FcNameUnparse (FcPattern *pat);
+
+/* fcpat.c */
+FcPattern *
+FcPatternCreate (void);
+
+FcPattern *
+FcPatternDuplicate (FcPattern *p);
+
+void
+FcValueDestroy (FcValue v);
+
+FcValue
+FcValueSave (FcValue v);
+
+void
+FcPatternDestroy (FcPattern *p);
+
+FcBool
+FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append);
+
+FcResult
+FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v);
+
+FcBool
+FcPatternDel (FcPattern *p, const char *object);
+
+FcBool
+FcPatternAddInteger (FcPattern *p, const char *object, int i);
+
+FcBool
+FcPatternAddDouble (FcPattern *p, const char *object, double d);
+
+FcBool
+FcPatternAddString (FcPattern *p, const char *object, const char *s);
+
+FcBool
+FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s);
+
+FcBool
+FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c);
+
+FcBool
+FcPatternAddBool (FcPattern *p, const char *object, FcBool b);
+
+FcResult
+FcPatternGetInteger (FcPattern *p, const char *object, int n, int *i);
+
+FcResult
+FcPatternGetDouble (FcPattern *p, const char *object, int n, double *d);
+
+FcResult
+FcPatternGetString (FcPattern *p, const char *object, int n, char **const s);
+
+FcResult
+FcPatternGetMatrix (FcPattern *p, const char *object, int n, FcMatrix **s);
+
+FcResult
+FcPatternGetCharSet (FcPattern *p, const char *object, int n, FcCharSet **c);
+
+FcResult
+FcPatternGetBool (FcPattern *p, const char *object, int n, FcBool *b);
+
+FcPattern *
+FcPatternVaBuild (FcPattern *orig, va_list va);
+
+FcPattern *
+FcPatternBuild (FcPattern *orig, ...);
+
+/* fcstr.c */
+
+char *
+FcStrCopy (const char *s);
+
+#define FcToLower(c) (('A' <= (c) && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
+
+int
+FcStrCmpIgnoreCase (const char *s1, const char *s2);
+
+int
+FcUtf8ToUcs4 (FcChar8 *src_orig,
+ FcChar32 *dst,
+ int len);
+
+FcBool
+FcUtf8Len (FcChar8 *string,
+ int len,
+ int *nchar,
+ int *wchar);
+
+/* fcxml.c */
+FcBool
+FcConfigParseAndLoad (FcConfig *config, const char *file, FcBool complain);
+
+_FCFUNCPROTOEND
+
+#endif /* _FONTCONFIG_H_ */
diff --git a/fonts.conf.in b/fonts.conf.in
new file mode 100644
index 0000000..e85c0c4
--- /dev/null
+++ b/fonts.conf.in
@@ -0,0 +1,191 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts.conf file to configure system font access -->
+<fontconfig>
+
+<!-- FONTPATH_START -->
+
+<!--
+ Common X11R6 font directories
+-->
+
+ <dir>/usr/X11R6/lib/X11/fonts/truetype</dir>
+ <dir>/usr/X11R6/lib/X11/fonts/Type1</dir>
+ <dir>/usr/X11R6/lib/X11/fonts/TrueType</dir>
+
+<!-- FONTPATH_END -->
+
+<!--
+ Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>monospace</string>
+ </edit>
+ </match>
+
+<!--
+ Accept deprecated 'sans' alias, replacing it with 'sans-serif'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>sans-serif</string>
+ </edit>
+ </match>
+
+<!--
+ Mark common families with their generics so we'll get
+ something reasonable
+-->
+
+<!--
+ Serif faces
+ -->
+ <alias>
+ <family>Times</family>
+ <default><family>serif</family></default>
+ </alias>
+ <alias>
+ <family>Times New Roman</family>
+ <default><family>serif</family></default>
+ </alias>
+<!--
+ Sans-serif faces
+ -->
+ <alias>
+ <family>Helvetica</family>
+ <default><family>sans-serif</family></default>
+ </alias>
+ <alias>
+ <family>Arial</family>
+ <default><family>sans-serif</family></default>
+ </alias>
+ <alias>
+ <family>Verdana</family>
+ <default><family>sans-serif</family></default>
+ </alias>
+<!--
+ Monospace faces
+ -->
+ <alias>
+ <family>Courier</family>
+ <default><family>monospace</family></default>
+ </alias>
+ <alias>
+ <family>Courier New</family>
+ <default><family>monospace</family></default>
+ </alias>
+ <alias>
+ <family>Andale Mono</family>
+ <default><family>monospace</family></default>
+ </alias>
+<!--
+ If the font still has no generic name, add sans-serif
+ -->
+ <match target="pattern">
+ <test qual="all" name="family" compare="not_eq">
+ <string>sans-serif</string>
+ </test>
+ <test qual="all" name="family" compare="not_eq">
+ <string>serif</string>
+ </test>
+ <test qual="all" name="family" compare="not_eq">
+ <string>monospace</string>
+ </test>
+ <edit name="family" mode="append_last">
+ <string>sans-serif</string>
+ </edit>
+ </match>
+
+<!--
+ Load per-user customization file
+-->
+ <include ignore_missing="yes">~/.fonts.conf</include>
+
+<!--
+ Alias well known font names to available TrueType fonts
+-->
+ <alias>
+ <family>Times</family>
+ <prefer><family>Times New Roman</family></prefer>
+ <default><family>serif</family></default>
+ </alias>
+ <alias>
+ <family>Helvetica</family>
+ <prefer><family>Verdana</family></prefer>
+ <default><family>sans-serif</family></default>
+ </alias>
+ <alias>
+ <family>Arial</family>
+ <prefer><family>Verdana</family></prefer>
+ <default><family>sans-serif</family></default>
+ </alias>
+ <alias>
+ <family>Courier</family>
+ <prefer><family>Courier New</family></prefer>
+ <default><family>monospace</family></default>
+ </alias>
+
+<!--
+ Provide required aliases for standard names
+-->
+ <alias>
+ <family>serif</family>
+ <prefer>
+ <family>Times New Roman</family>
+ <family>Nimbus Roman No9 L</family>
+ <family>Luxi Serif</family>
+ <family>Times</family>
+ </prefer>
+ </alias>
+ <alias>
+ <family>sans-serif</family>
+ <prefer>
+ <family>Verdana</family>
+ <family>Nimbus Sans L</family>
+ <family>Luxi Sans</family>
+ <family>Arial</family>
+ <family>Helvetica</family>
+ </prefer>
+ </alias>
+ <alias>
+ <family>monospace</family>
+ <prefer>
+ <family>Andale Mono</family>
+ <family>Courier New</family>
+ <family>Nimbus Mono L</family>
+ <family>Luxi Mono</family>
+ </prefer>
+ </alias>
+
+<!--
+ These are the default Unicode chars that are expected to be blank
+ in fonts. All other blank chars are assumed to be broken and
+ won't appear in the resulting charsets
+ -->
+ <config><blank>
+ <int>0x20</int> <!-- space -->
+ <int>0xa0</int> <!-- nsbp -->
+ <int>0x2000</int> <!-- general punctuation spaces -->
+ <int>0x2001</int>
+ <int>0x2002</int>
+ <int>0x2003</int>
+ <int>0x2004</int>
+ <int>0x2005</int>
+ <int>0x2005</int>
+ <int>0x2006</int>
+ <int>0x2007</int>
+ <int>0x2008</int>
+ <int>0x2009</int>
+ <int>0x200a</int>
+ <int>0x200b</int>
+ <int>0x3000</int> <!-- CJK space -->
+ </blank></config>
+
+</fontconfig>
diff --git a/fonts.dtd b/fonts.dtd
new file mode 100644
index 0000000..a3c987b
--- /dev/null
+++ b/fonts.dtd
@@ -0,0 +1,165 @@
+<!-- This is the Document Type Definition for font configuration files -->
+<!ELEMENT fontconfig (dir |
+ cache |
+ include |
+ config |
+ match |
+ alias)* >
+
+<!--
+ Add a directory that provides fonts
+-->
+<!ELEMENT dir (#PCDATA)>
+<!ATTLIST dir xml:space (default|preserve) 'preserve'>
+
+<!--
+ Define the per-user file that holds cache font information.
+
+ If the filename begins with '~', it is replaced with the users
+ home directory path.
+-->
+<!ELEMENT cache (#PCDATA)>
+<!ATTLIST cache xml:space (default|preserve) 'preserve'>
+
+<!--
+ Reference another configuration file; note that this
+ is another complete font configuration file and not
+ just a file included by the XML parser.
+
+ Set 'ignore_missing' to 'yes' if errors are to be ignored.
+
+ If the filename begins with '~', it is replaced with the users
+ home directory path.
+-->
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include
+ ignore_missing (no|yes) "no"
+ xml:space (default|preserve) "preserve">
+
+<!--
+ Global library configuration data
+ -->
+<!ELEMENT config (blanks)*>
+
+<!--
+ Specify the set of Unicode encoding values which
+ represent glyphs that are allowed to contain no
+ data. With this list, fontconfig can examine
+ fonts for broken glyphs and eliminate them from
+ the set of valid Unicode chars. This idea
+ was borrowed from Mozilla
+ -->
+<!ELEMENT blanks (int)*>
+
+<!--
+ Aliases are just a special case for multiple match elements
+
+ They are syntactically equivalent to:
+
+ <match>
+ <test name="family">
+ <string value=[family]/>
+ </test>
+ <edit name="family" mode="prepend">
+ <string value=[prefer]/>
+ ...
+ </edit>
+ <edit name="family" mode="append">
+ <string value=[accept]/>
+ ...
+ </edit>
+ <edit name="family" mode="append_last">
+ <string value=[default]/>
+ ...
+ </edit>
+ </match>
+-->
+<!ELEMENT alias (family, prefer?, accept?, default?)>
+<!ELEMENT prefer (family)*>
+<!ELEMENT accept (family)*>
+<!ELEMENT default (family)*>
+<!ELEMENT family (#PCDATA)>
+<!ATTLIST family xml:space (default|preserve) 'preserve'>
+
+<!ENTITY % expr 'int|double|string|matrix|bool|charset
+ |name|const
+ |or|and|eq|not_eq|less|less_eq|more|more_eq
+ |plus|minus|times|divide|not|if'>
+
+<!--
+ Match and edit patterns.
+
+ If 'target' is 'pattern', execute the match before selecting a font.
+ if 'target' is 'font', execute the match on the result of a font
+ selection.
+-->
+<!ELEMENT match (test*, edit*)>
+<!ATTLIST match
+ target (pattern|font) "pattern">
+
+<!--
+ Match a field in a pattern
+
+ if 'qual' is 'any', then the match succeeds if any value in the field matches.
+ if 'qual' is 'all', then the match succeeds only if all values match.
+-->
+<!ELEMENT test (%expr;)>
+<!ATTLIST test
+ qual (any|all) "any"
+ name CDATA #REQUIRED
+ compare (eq|not_eq|less|less_eq|more|more_eq) "eq">
+
+<!--
+ Edit a field in a pattern
+
+ The enclosed values are used together to edit the list of values
+ associated with 'name'.
+
+ If 'name' matches one of those used in a test element for this match element:
+ if 'mode' is 'assign', replace the matched value.
+ if 'mode' is 'assign_replace', replace all of the values
+ if 'mode' is 'prepend', insert before the matched value
+ if 'mode' is 'append', insert after the matched value
+ if 'mode' is 'prepend_first', insert before all of the values
+ if 'mode' is 'append_last', insert after all of the values
+ If 'name' doesn't match any of those used in a test element:
+ if 'mode' is 'assign' or 'assign_replace, replace all of the values
+ if 'mode' is 'prepend' or 'prepend_first', insert before all of the values
+ if 'mode' is 'append' or 'append_last', insert after all of the values
+-->
+<!ELEMENT edit (%expr;)*>
+<!ATTLIST edit
+ name CDATA #REQUIRED
+ mode (assign|assign_replace|prepend|append|prepend_first|append_last) "assign">
+
+<!--
+ Elements of expressions follow
+-->
+<!ELEMENT int (#PCDATA)>
+<!ATTLIST int xml:space (default|preserve) 'preserve'>
+<!ELEMENT double (#PCDATA)>
+<!ATTLIST double xml:space (default|preserve) 'preserve'>
+<!ELEMENT string (#PCDATA)>
+<!ATTLIST string xml:space (default|preserve) 'preserve'>
+<!ELEMENT matrix (double,double,double,double)>
+<!ELEMENT bool (true|false)>
+<!ELEMENT charset (#PCDATA)>
+<!ATTLIST charset xml:space (default|preserve) 'preserve'>
+<!ELEMENT name (#PCDATA)>
+<!ATTLIST name xml:space (default|preserve) 'preserve'>
+<!ELEMENT const (#PCDATA)>
+<!ATTLIST const xml:space (default|preserve) 'preserve'>
+<!ELEMENT or (%expr;)*>
+<!ELEMENT and (%expr;)*>
+<!ELEMENT eq ((%expr;), (%expr;))>
+<!ELEMENT not_eq ((%expr;), (%expr;))>
+<!ELEMENT less ((%expr;), (%expr;))>
+<!ELEMENT less_eq ((%expr;), (%expr;))>
+<!ELEMENT more ((%expr;), (%expr;))>
+<!ELEMENT more_eq ((%expr;), (%expr;))>
+<!ELEMENT plus (%expr;)*>
+<!ELEMENT minus (%expr;)*>
+<!ELEMENT times (%expr;)*>
+<!ELEMENT divide (%expr;)*>
+<!ELEMENT not (%expr;)>
+<!ELEMENT if ((%expr;), (%expr;), (%expr;))>
diff --git a/setfontdirs b/setfontdirs
new file mode 100755
index 0000000..7bed787
--- /dev/null
+++ b/setfontdirs
@@ -0,0 +1,19 @@
+#!/bin/sh
+FONTDIRS=fontdirs$$
+trap "rm $FONTDIRS" 0
+sh ./findfonts > $FONTDIRS
+cp fonts.conf.in fonts.conf
+chmod +w fonts.conf
+ed fonts.conf << EOF
+/FONTPATH_END/a
+<!-- Font directories found on `date` -->
+.
++r $FONTDIRS
+a
+
+.
+/FONTPATH_START/,/FONTPATH_END/d
+w
+q
+EOF
+
diff --git a/src/Imakefile b/src/Imakefile
new file mode 100644
index 0000000..1ba4cb5
--- /dev/null
+++ b/src/Imakefile
@@ -0,0 +1,90 @@
+#include "../../libxml2/config.h"
+#if HAVE_ZLIB_H
+ZLIB=-lz
+#endif
+
+#if 0
+#define SharedLibFontconfig YES
+#endif
+
+#ifndef SharedLibFontconfig
+#define SharedLibFontconfig NO
+#endif
+
+#ifndef NormalLibFontconfig
+#define NormalLibFontconfig (!SharedLibFontConfig | ForceNormalLib)
+#endif
+
+#ifndef DebugLibFontconfig
+#define DebugLibFontconfig NO
+#endif
+
+#ifndef ProfileLibFontconfig
+#define ProfileLibFontconfig NO
+#endif
+
+#define LibHeaders NO
+
+FONTCONFIGSRC=.
+
+FALLBACK_FONTS=$(FONTDIR)/Type1
+
+#if SharedLibFontconfig
+#ifndef SharedFontconfigRev
+#define SharedFontconfigRev 1.0
+#endif
+SharedLibReferences(FONTCONFIG,Fontconfig,$(FONTCONFIGSRC),SOXLIBREV,SharedFontconfigRev)
+#else
+ProjectUnsharedLibReferences(FONTCONFIG,Fontconfig,$(FONTCONFIGSRC),BuildLibDir)
+#endif
+
+#define DoNormalLib NormalLibFontconfig
+#define DoSharedLib SharedLibFontconfig
+#define DoExtraLib SharedLibFontconfig
+#define DoDebugLib DebugLibFontconfig
+#define DoProfileLib ProfileLibFontconfig
+#define HasSharedData YES
+#define LibName fontconfig
+SOFONTCONFIGREV=1.0
+#define SoRev SOFONTCONFIGREV
+
+#include <Threads.tmpl>
+
+#if SharedLibFontconfig
+INCLUDES=-I/usr/local/include/freetype2 -I/usr/include/libxml2 -I..
+FREETYPE2REQLIB = -L/usr/local/lib -lfreetype
+XML2REQLIB=-lxml2
+#else
+INCLUDES=-I../../freetype2 -I../../libxml2/include -I..
+FREETYPE2REQLIB = ../../freetype2/libfreetype.a
+XML2REQLIB=../../libxml2/.libs/libxml2.a $(ZLIB) -lm
+#endif
+DEFINES=-DFC_FALLBACK_FONTS='"$(FALLBACK_FONTS)"'
+
+REQUIREDLIBS=$(LDPRELIBS) $(FREETYPE2REQLIB) $(XML2REQLIB)
+
+SRCS=fcblanks.c fccache.c fccfg.c fccharset.c fcdbg.c fcdefault.c fcdir.c \
+ fcfreetype.c fcfs.c fcinit.c fclist.c fcmatch.c fcmatrix.c fcname.c \
+ fcpat.c fcstr.c fcxml.c
+
+OBJS=fcblanks.o fccache.o fccfg.o fccharset.o fcdbg.o fcdefault.o fcdir.o \
+ fcfreetype.o fcfs.o fcinit.o fclist.o fcmatch.o fcmatrix.o fcname.o \
+ fcpat.o fcstr.o fcxml.o
+
+#define LibInstallBuild YES
+#undef LinkBuildLibrary
+#define LinkBuildLibrary(lib) MakeDir($(BUILDLIBDIR)) @@\
+ RemoveFile($(BUILDLIBDIR)/lib) @@\
+ cd $(BUILDLIBDIR) && $(LN) $(BUILDLIBTOP)/$(CURRENT_DIR)/lib .
+
+
+#include <Library.tmpl>
+
+#if DoSharedLib && SharedDataSeparation
+SpecialCObjectRule(sharedlib,NullParameter,$(SHLIBDEF))
+#endif
+
+MANSUFFIX = $(LIBMANSUFFIX)
+InstallManPage(fontconfig,$(LIBMANDIR))
+DependTarget()
+
diff --git a/src/fcblanks.c b/src/fcblanks.c
new file mode 100644
index 0000000..8b3a9a9
--- /dev/null
+++ b/src/fcblanks.c
@@ -0,0 +1,84 @@
+/*
+ * $XFree86$
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+
+FcBlanks *
+FcBlanksCreate (void)
+{
+ FcBlanks *b;
+
+ b = malloc (sizeof (FcBlanks));
+ if (!b)
+ return 0;
+ b->nblank = 0;
+ b->sblank = 0;
+ b->blanks = 0;
+ return b;
+}
+
+void
+FcBlanksDestroy (FcBlanks *b)
+{
+ if (b->blanks)
+ free (b->blanks);
+ free (b);
+}
+
+FcBool
+FcBlanksAdd (FcBlanks *b, FcChar32 ucs4)
+{
+ FcChar32 *c;
+ int sblank;
+
+ for (sblank = 0; sblank < b->nblank; sblank++)
+ if (b->blanks[sblank] == ucs4)
+ return FcTrue;
+
+ if (b->nblank == b->sblank)
+ {
+ sblank = b->sblank + 32;
+ if (b->blanks)
+ c = (FcChar32 *) realloc (b->blanks, sblank * sizeof (FcChar32));
+ else
+ c = (FcChar32 *) malloc (sblank * sizeof (FcChar32));
+ if (!c)
+ return FcFalse;
+ b->sblank = sblank;
+ b->blanks = c;
+ }
+ b->blanks[b->nblank++] = ucs4;
+ return FcTrue;
+}
+
+FcBool
+FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4)
+{
+ int i;
+
+ for (i = 0; i < b->nblank; i++)
+ if (b->blanks[i] == ucs4)
+ return FcTrue;
+ return FcFalse;
+}
diff --git a/src/fccache.c b/src/fccache.c
new file mode 100644
index 0000000..2251286
--- /dev/null
+++ b/src/fccache.c
@@ -0,0 +1,592 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+
+static unsigned int
+FcFileCacheHash (const char *string)
+{
+ unsigned int h = 0;
+ char c;
+
+ while ((c = *string++))
+ h = (h << 1) ^ c;
+ return h;
+}
+
+char *
+FcFileCacheFind (FcFileCache *cache,
+ const char *file,
+ int id,
+ int *count)
+{
+ unsigned int hash;
+ const char *match;
+ FcFileCacheEnt *c, *name;
+ int maxid;
+ struct stat statb;
+
+ match = file;
+
+ hash = FcFileCacheHash (match);
+ name = 0;
+ maxid = -1;
+ for (c = cache->ents[hash % FC_FILE_CACHE_HASH_SIZE]; c; c = c->next)
+ {
+ if (c->hash == hash && !strcmp (match, c->file))
+ {
+ if (c->id > maxid)
+ maxid = c->id;
+ if (c->id == id)
+ {
+ if (stat (file, &statb) < 0)
+ {
+ if (FcDebug () & FC_DBG_CACHE)
+ printf (" file missing\n");
+ return 0;
+ }
+ if (statb.st_mtime != c->time)
+ {
+ if (FcDebug () & FC_DBG_CACHE)
+ printf (" timestamp mismatch (was %d is %d)\n",
+ (int) c->time, (int) statb.st_mtime);
+ return 0;
+ }
+ if (!c->referenced)
+ {
+ cache->referenced++;
+ c->referenced = FcTrue;
+ }
+ name = c;
+ }
+ }
+ }
+ if (!name)
+ return 0;
+ *count = maxid + 1;
+ return name->name;
+}
+
+/*
+ * Cache file syntax is quite simple:
+ *
+ * "file_name" id time "font_name" \n
+ */
+
+static FcBool
+FcFileCacheReadString (FILE *f, char *dest, int len)
+{
+ int c;
+ FcBool escape;
+
+ while ((c = getc (f)) != EOF)
+ if (c == '"')
+ break;
+ if (c == EOF)
+ return FcFalse;
+ if (len == 0)
+ return FcFalse;
+
+ escape = FcFalse;
+ while ((c = getc (f)) != EOF)
+ {
+ if (!escape)
+ {
+ switch (c) {
+ case '"':
+ *dest++ = '\0';
+ return FcTrue;
+ case '\\':
+ escape = FcTrue;
+ continue;
+ }
+ }
+ if (--len <= 1)
+ return FcFalse;
+ *dest++ = c;
+ escape = FcFalse;
+ }
+ return FcFalse;
+}
+
+static FcBool
+FcFileCacheReadUlong (FILE *f, unsigned long *dest)
+{
+ unsigned long t;
+ int c;
+
+ while ((c = getc (f)) != EOF)
+ {
+ if (!isspace (c))
+ break;
+ }
+ if (c == EOF)
+ return FcFalse;
+ t = 0;
+ for (;;)
+ {
+ if (c == EOF || isspace (c))
+ break;
+ if (!isdigit (c))
+ return FcFalse;
+ t = t * 10 + (c - '0');
+ c = getc (f);
+ }
+ *dest = t;
+ return FcTrue;
+}
+
+static FcBool
+FcFileCacheReadInt (FILE *f, int *dest)
+{
+ unsigned long t;
+ FcBool ret;
+
+ ret = FcFileCacheReadUlong (f, &t);
+ if (ret)
+ *dest = (int) t;
+ return ret;
+}
+
+static FcBool
+FcFileCacheReadTime (FILE *f, time_t *dest)
+{
+ unsigned long t;
+ FcBool ret;
+
+ ret = FcFileCacheReadUlong (f, &t);
+ if (ret)
+ *dest = (time_t) t;
+ return ret;
+}
+
+static FcBool
+FcFileCacheAdd (FcFileCache *cache,
+ const char *file,
+ int id,
+ time_t time,
+ const char *name,
+ FcBool replace)
+{
+ FcFileCacheEnt *c;
+ FcFileCacheEnt **prev, *old;
+ unsigned int hash;
+
+ if (FcDebug () & FC_DBG_CACHE)
+ {
+ printf ("%s face %s/%d as %s\n", replace ? "Replace" : "Add",
+ file, id, name);
+ }
+ hash = FcFileCacheHash (file);
+ for (prev = &cache->ents[hash % FC_FILE_CACHE_HASH_SIZE];
+ (old = *prev);
+ prev = &(*prev)->next)
+ {
+ if (old->hash == hash && old->id == id && !strcmp (old->file, file))
+ break;
+ }
+ if (*prev)
+ {
+ if (!replace)
+ return FcFalse;
+
+ old = *prev;
+ if (old->referenced)
+ cache->referenced--;
+ *prev = old->next;
+ free (old);
+ cache->entries--;
+ }
+
+ c = malloc (sizeof (FcFileCacheEnt) +
+ strlen (file) + 1 +
+ strlen (name) + 1);
+ if (!c)
+ return FcFalse;
+ c->next = *prev;
+ *prev = c;
+ c->hash = hash;
+ c->file = (char *) (c + 1);
+ c->id = id;
+ c->name = c->file + strlen (file) + 1;
+ strcpy (c->file, file);
+ c->time = time;
+ c->referenced = replace;
+ strcpy (c->name, name);
+ cache->entries++;
+ return FcTrue;
+}
+
+FcFileCache *
+FcFileCacheCreate (void)
+{
+ FcFileCache *cache;
+ int h;
+
+ cache = malloc (sizeof (FcFileCache));
+ if (!cache)
+ return 0;
+ for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
+ cache->ents[h] = 0;
+ cache->entries = 0;
+ cache->referenced = 0;
+ cache->updated = FcFalse;
+ return cache;
+}
+
+void
+FcFileCacheDestroy (FcFileCache *cache)
+{
+ FcFileCacheEnt *c, *next;
+ int h;
+
+ for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
+ {
+ for (c = cache->ents[h]; c; c = next)
+ {
+ next = c->next;
+ free (c);
+ }
+ }
+ free (cache);
+}
+
+void
+FcFileCacheLoad (FcFileCache *cache,
+ const char *cache_file)
+{
+ FILE *f;
+ char file[8192];
+ int id;
+ time_t time;
+ char name[8192];
+
+ f = fopen (cache_file, "r");
+ if (!f)
+ return;
+
+ cache->updated = FcFalse;
+ while (FcFileCacheReadString (f, file, sizeof (file)) &&
+ FcFileCacheReadInt (f, &id) &&
+ FcFileCacheReadTime (f, &time) &&
+ FcFileCacheReadString (f, name, sizeof (name)))
+ {
+ (void) FcFileCacheAdd (cache, file, id, time, name, FcFalse);
+ }
+ fclose (f);
+}
+
+FcBool
+FcFileCacheUpdate (FcFileCache *cache,
+ const char *file,
+ int id,
+ const char *name)
+{
+ const char *match;
+ struct stat statb;
+ FcBool ret;
+
+ match = file;
+
+ if (stat (file, &statb) < 0)
+ return FcFalse;
+ ret = FcFileCacheAdd (cache, match, id,
+ statb.st_mtime, name, FcTrue);
+ if (ret)
+ cache->updated = FcTrue;
+ return ret;
+}
+
+static FcBool
+FcFileCacheWriteString (FILE *f, char *string)
+{
+ char c;
+
+ if (putc ('"', f) == EOF)
+ return FcFalse;
+ while ((c = *string++))
+ {
+ switch (c) {
+ case '"':
+ case '\\':
+ if (putc ('\\', f) == EOF)
+ return FcFalse;
+ /* fall through */
+ default:
+ if (putc (c, f) == EOF)
+ return FcFalse;
+ }
+ }
+ if (putc ('"', f) == EOF)
+ return FcFalse;
+ return FcTrue;
+}
+
+static FcBool
+FcFileCacheWriteUlong (FILE *f, unsigned long t)
+{
+ int pow;
+ unsigned long temp, digit;
+
+ temp = t;
+ pow = 1;
+ while (temp >= 10)
+ {
+ temp /= 10;
+ pow *= 10;
+ }
+ temp = t;
+ while (pow)
+ {
+ digit = temp / pow;
+ if (putc ((char) digit + '0', f) == EOF)
+ return FcFalse;
+ temp = temp - pow * digit;
+ pow = pow / 10;
+ }
+ return FcTrue;
+}
+
+static FcBool
+FcFileCacheWriteInt (FILE *f, int i)
+{
+ return FcFileCacheWriteUlong (f, (unsigned long) i);
+}
+
+static FcBool
+FcFileCacheWriteTime (FILE *f, time_t t)
+{
+ return FcFileCacheWriteUlong (f, (unsigned long) t);
+}
+
+FcBool
+FcFileCacheSave (FcFileCache *cache,
+ const char *cache_file)
+{
+ char *lck;
+ char *tmp;
+ FILE *f;
+ int h;
+ FcFileCacheEnt *c;
+
+ if (!cache->updated && cache->referenced == cache->entries)
+ return FcTrue;
+
+ lck = malloc (strlen (cache_file)*2 + 4);
+ if (!lck)
+ goto bail0;
+ tmp = lck + strlen (cache_file) + 2;
+ strcpy (lck, cache_file);
+ strcat (lck, "L");
+ strcpy (tmp, cache_file);
+ strcat (tmp, "T");
+ if (link (lck, cache_file) < 0 && errno != ENOENT)
+ goto bail1;
+ if (access (tmp, F_OK) == 0)
+ goto bail2;
+ f = fopen (tmp, "w");
+ if (!f)
+ goto bail2;
+
+ for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
+ {
+ for (c = cache->ents[h]; c; c = c->next)
+ {
+ if (!c->referenced)
+ continue;
+ if (!FcFileCacheWriteString (f, c->file))
+ goto bail4;
+ if (putc (' ', f) == EOF)
+ goto bail4;
+ if (!FcFileCacheWriteInt (f, c->id))
+ goto bail4;
+ if (putc (' ', f) == EOF)
+ goto bail4;
+ if (!FcFileCacheWriteTime (f, c->time))
+ goto bail4;
+ if (putc (' ', f) == EOF)
+ goto bail4;
+ if (!FcFileCacheWriteString (f, c->name))
+ goto bail4;
+ if (putc ('\n', f) == EOF)
+ goto bail4;
+ }
+ }
+
+ if (fclose (f) == EOF)
+ goto bail3;
+
+ if (rename (tmp, cache_file) < 0)
+ goto bail3;
+
+ unlink (lck);
+ cache->updated = FcFalse;
+ return FcTrue;
+
+bail4:
+ fclose (f);
+bail3:
+ unlink (tmp);
+bail2:
+ unlink (lck);
+bail1:
+ free (lck);
+bail0:
+ return FcFalse;
+}
+
+FcBool
+FcFileCacheReadDir (FcFontSet *set, const char *cache_file)
+{
+ FcPattern *font;
+ FILE *f;
+ char *path;
+ char *base;
+ char file[8192];
+ int id;
+ char name[8192];
+ FcBool ret = FcFalse;
+
+ if (FcDebug () & FC_DBG_CACHE)
+ {
+ printf ("FcFileCacheReadDir cache_file \"%s\"\n", cache_file);
+ }
+
+ f = fopen (cache_file, "r");
+ if (!f)
+ {
+ if (FcDebug () & FC_DBG_CACHE)
+ {
+ printf (" no cache file\n");
+ }
+ goto bail0;
+ }
+
+ base = strrchr (cache_file, '/');
+ if (!base)
+ goto bail1;
+ base++;
+ path = malloc (base - cache_file + 8192 + 1);
+ if (!path)
+ goto bail1;
+ memcpy (path, cache_file, base - cache_file);
+ base = path + (base - cache_file);
+
+ while (FcFileCacheReadString (f, file, sizeof (file)) &&
+ FcFileCacheReadInt (f, &id) &&
+ FcFileCacheReadString (f, name, sizeof (name)))
+ {
+ font = FcNameParse (name);
+ if (font)
+ {
+ strcpy (base, file);
+ if (FcDebug () & FC_DBG_CACHEV)
+ {
+ printf (" dir cache file \"%s\"\n", file);
+ }
+ FcPatternAddString (font, FC_FILE, path);
+ if (!FcFontSetAdd (set, font))
+ goto bail2;
+ }
+ }
+ if (FcDebug () & FC_DBG_CACHE)
+ {
+ printf (" cache loaded\n");
+ }
+
+ ret = FcTrue;
+bail2:
+ free (path);
+bail1:
+ fclose (f);
+bail0:
+ return ret;
+}
+
+FcBool
+FcFileCacheWriteDir (FcFontSet *set, const char *cache_file)
+{
+ FcPattern *font;
+ FILE *f;
+ char *name;
+ char *file, *base;
+ int n;
+ int id;
+ FcBool ret;
+
+ if (FcDebug () & FC_DBG_CACHE)
+ printf ("FcFileCacheWriteDir cache_file \"%s\"\n", cache_file);
+
+ f = fopen (cache_file, "w");
+ if (!f)
+ {
+ if (FcDebug () & FC_DBG_CACHE)
+ printf (" can't create \"%s\"\n", cache_file);
+ goto bail0;
+ }
+ for (n = 0; n < set->nfont; n++)
+ {
+ font = set->fonts[n];
+ if (FcPatternGetString (font, FC_FILE, 0, &file) != FcResultMatch)
+ goto bail1;
+ base = strrchr (file, '/');
+ if (base)
+ base = base + 1;
+ else
+ base = file;
+ if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
+ goto bail1;
+ if (FcDebug () & FC_DBG_CACHEV)
+ printf (" write file \"%s\"\n", base);
+ if (!FcFileCacheWriteString (f, base))
+ goto bail1;
+ if (putc (' ', f) == EOF)
+ goto bail1;
+ if (!FcFileCacheWriteInt (f, id))
+ goto bail1;
+ if (putc (' ', f) == EOF)
+ goto bail1;
+ name = FcNameUnparse (font);
+ if (!name)
+ goto bail1;
+ ret = FcFileCacheWriteString (f, name);
+ free (name);
+ if (!ret)
+ goto bail1;
+ if (putc ('\n', f) == EOF)
+ goto bail1;
+ }
+ if (fclose (f) == EOF)
+ goto bail0;
+
+ if (FcDebug () & FC_DBG_CACHE)
+ printf (" cache written\n");
+ return FcTrue;
+
+bail1:
+ fclose (f);
+bail0:
+ unlink (cache_file);
+ return FcFalse;
+}
diff --git a/src/fccfg.c b/src/fccfg.c
new file mode 100644
index 0000000..0280ee1
--- /dev/null
+++ b/src/fccfg.c
@@ -0,0 +1,1369 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "fcint.h"
+
+static FcConfig *fcConfig;
+
+FcConfig *
+FcConfigCreate (void)
+{
+ FcSetName set;
+ FcConfig *config;
+
+ config = malloc (sizeof (FcConfig));
+ if (!config)
+ goto bail0;
+
+ config->dirs = malloc (sizeof (char *));
+ if (!config->dirs)
+ goto bail1;
+ config->dirs[0] = 0;
+
+ config->configFiles = malloc (sizeof (char *));
+ if (!config->configFiles)
+ goto bail2;
+ config->configFiles[0] = 0;
+
+ config->cache = 0;
+ if (!FcConfigSetCache (config, "~/" FC_USER_CACHE_FILE))
+ goto bail3;
+
+ config->blanks = 0;
+
+ config->substPattern = 0;
+ config->substFont = 0;
+ config->maxObjects = 0;
+ for (set = FcSetSystem; set <= FcSetApplication; set++)
+ config->fonts[set] = 0;
+
+ return config;
+
+bail3:
+ free (config->configFiles);
+bail2:
+ free (config->dirs);
+bail1:
+ free (config);
+bail0:
+ return 0;
+}
+
+static void
+FcSubstDestroy (FcSubst *s)
+{
+ FcSubst *n;
+
+ while (s)
+ {
+ n = s->next;
+ FcTestDestroy (s->test);
+ FcEditDestroy (s->edit);
+ s = n;
+ }
+}
+
+static void
+FcConfigDestroyStrings (char **strings)
+{
+ char **s;
+
+ for (s = strings; s && *s; s++)
+ free (*s);
+ if (strings)
+ free (strings);
+}
+
+static FcBool
+FcConfigAddString (char ***strings, char *string)
+{
+ int n;
+ char **s;
+
+ n = 0;
+ for (s = *strings; s && *s; s++)
+ n++;
+ s = malloc ((n + 2) * sizeof (char *));
+ if (!s)
+ return FcFalse;
+ s[n] = string;
+ s[n+1] = 0;
+ memcpy (s, *strings, n * sizeof (char *));
+ free (*strings);
+ *strings = s;
+ return FcTrue;
+}
+
+void
+FcConfigDestroy (FcConfig *config)
+{
+ FcSetName set;
+ FcConfigDestroyStrings (config->dirs);
+ FcConfigDestroyStrings (config->configFiles);
+
+ free (config->cache);
+
+ FcSubstDestroy (config->substPattern);
+ FcSubstDestroy (config->substFont);
+ for (set = FcSetSystem; set <= FcSetApplication; set++)
+ if (config->fonts[set])
+ FcFontSetDestroy (config->fonts[set]);
+}
+
+/*
+ * Scan the current list of directories in the configuration
+ * and build the set of available fonts. Update the
+ * per-user cache file to reflect the new configuration
+ */
+
+FcBool
+FcConfigBuildFonts (FcConfig *config)
+{
+ FcFontSet *fonts;
+ FcFileCache *cache;
+ char **d;
+
+ fonts = FcFontSetCreate ();
+ if (!fonts)
+ goto bail0;
+
+ cache = FcFileCacheCreate ();
+ if (!cache)
+ goto bail1;
+
+ FcFileCacheLoad (cache, config->cache);
+
+ for (d = config->dirs; d && *d; d++)
+ {
+ if (FcDebug () & FC_DBG_FONTSET)
+ printf ("scan dir %s\n", *d);
+ FcDirScan (fonts, cache, config->blanks, *d, FcFalse);
+ }
+
+ if (FcDebug () & FC_DBG_FONTSET)
+ FcFontSetPrint (fonts);
+
+ FcFileCacheSave (cache, config->cache);
+ FcFileCacheDestroy (cache);
+
+ FcConfigSetFonts (config, fonts, FcSetSystem);
+
+ return FcTrue;
+bail1:
+ FcFontSetDestroy (fonts);
+bail0:
+ return FcFalse;
+}
+
+FcBool
+FcConfigSetCurrent (FcConfig *config)
+{
+ if (!config->fonts)
+ if (!FcConfigBuildFonts (config))
+ return FcFalse;
+
+ if (fcConfig)
+ FcConfigDestroy (fcConfig);
+ fcConfig = config;
+ return FcTrue;
+}
+
+FcConfig *
+FcConfigGetCurrent (void)
+{
+ return fcConfig;
+}
+
+FcBool
+FcConfigAddDir (FcConfig *config,
+ const char *d)
+{
+ char *dir;
+ char *h;
+
+ if (*d == '~')
+ {
+ h = getenv ("HOME");
+ if (!h)
+ return FcFalse;
+ dir = (char *) malloc (strlen (h) + strlen (d));
+ if (!dir)
+ return FcFalse;
+ strcpy (dir, h);
+ strcat (dir, d+1);
+ }
+ else
+ {
+ dir = (char *) malloc (strlen (d) + 1);
+ if (!dir)
+ return FcFalse;
+ strcpy (dir, d);
+ }
+ if (!FcConfigAddString (&config->dirs, dir))
+ {
+ free (dir);
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+char **
+FcConfigGetDirs (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->dirs;
+}
+
+FcBool
+FcConfigAddConfigFile (FcConfig *config,
+ const char *f)
+{
+ char *file;
+ file = FcConfigFilename (f);
+ if (!file)
+ return FcFalse;
+ if (!FcConfigAddString (&config->configFiles, file))
+ {
+ free (file);
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+char **
+FcConfigGetConfigFiles (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->configFiles;
+}
+
+FcBool
+FcConfigSetCache (FcConfig *config,
+ const char *c)
+{
+ char *new;
+ char *h;
+
+ if (*c == '~')
+ {
+ h = getenv ("HOME");
+ if (!h)
+ return FcFalse;
+ new = (char *) malloc (strlen (h) + strlen (c));
+ if (!new)
+ return FcFalse;
+ strcpy (new, h);
+ strcat (new, c+1);
+ }
+ else
+ {
+ new = FcStrCopy (c);
+ }
+ if (config->cache)
+ free (config->cache);
+ config->cache = new;
+ return FcTrue;
+}
+
+char *
+FcConfigGetCache (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->cache;
+}
+
+FcFontSet *
+FcConfigGetFonts (FcConfig *config,
+ FcSetName set)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->fonts[set];
+}
+
+void
+FcConfigSetFonts (FcConfig *config,
+ FcFontSet *fonts,
+ FcSetName set)
+{
+ if (config->fonts[set])
+ FcFontSetDestroy (config->fonts[set]);
+ config->fonts[set] = fonts;
+}
+
+FcBlanks *
+FcConfigGetBlanks (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->blanks;
+}
+
+FcBool
+FcConfigAddBlank (FcConfig *config,
+ FcChar32 blank)
+{
+ FcBlanks *b;
+
+ b = config->blanks;
+ if (!b)
+ {
+ b = FcBlanksCreate ();
+ if (!b)
+ return FcFalse;
+ }
+ if (!FcBlanksAdd (b, blank))
+ return FcFalse;
+ config->blanks = b;
+ return FcTrue;
+}
+
+FcBool
+FcConfigAddEdit (FcConfig *config,
+ FcTest *test,
+ FcEdit *edit,
+ FcMatchKind kind)
+{
+ FcSubst *subst, **prev;
+ FcTest *t;
+ int num;
+
+ subst = (FcSubst *) malloc (sizeof (FcSubst));
+ if (!subst)
+ return FcFalse;
+ if (kind == FcMatchPattern)
+ prev = &config->substPattern;
+ else
+ prev = &config->substFont;
+ for (; *prev; prev = &(*prev)->next);
+ *prev = subst;
+ subst->next = 0;
+ subst->test = test;
+ subst->edit = edit;
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("Add Subst ");
+ FcSubstPrint (subst);
+ }
+ num = 0;
+ for (t = test; t; t = t->next)
+ num++;
+ if (config->maxObjects < num)
+ config->maxObjects = num;
+ return FcTrue;
+}
+
+typedef struct _FcSubState {
+ FcPatternElt *elt;
+ FcValueList *value;
+} FcSubState;
+
+static const FcMatrix FcIdentityMatrix = { 1, 0, 0, 1 };
+
+static FcValue
+FcConfigPromote (FcValue v, FcValue u)
+{
+ if (v.type == FcTypeInteger)
+ {
+ v.type = FcTypeDouble;
+ v.u.d = (double) v.u.i;
+ }
+ else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
+ {
+ v.u.m = (FcMatrix *) &FcIdentityMatrix;
+ v.type = FcTypeMatrix;
+ }
+ return v;
+}
+
+FcBool
+FcConfigCompareValue (FcValue m,
+ FcOp op,
+ FcValue v)
+{
+ FcBool ret = FcFalse;
+
+ m = FcConfigPromote (m, v);
+ v = FcConfigPromote (v, m);
+ if (m.type == v.type)
+ {
+ ret = FcFalse;
+ switch (m.type) {
+ case FcTypeInteger:
+ break; /* FcConfigPromote prevents this from happening */
+ case FcTypeDouble:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ ret = m.u.d == v.u.d;
+ break;
+ case FcOpNotEqual:
+ ret = m.u.d != v.u.d;
+ break;
+ case FcOpLess:
+ ret = m.u.d < v.u.d;
+ break;
+ case FcOpLessEqual:
+ ret = m.u.d <= v.u.d;
+ break;
+ case FcOpMore:
+ ret = m.u.d > v.u.d;
+ break;
+ case FcOpMoreEqual:
+ ret = m.u.d >= v.u.d;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeBool:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ ret = m.u.b == v.u.b;
+ break;
+ case FcOpNotEqual:
+ ret = m.u.b != v.u.b;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeString:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) == 0;
+ break;
+ case FcOpNotEqual:
+ ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) != 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeMatrix:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ ret = FcMatrixEqual (m.u.m, v.u.m);
+ break;
+ case FcOpNotEqual:
+ ret = !FcMatrixEqual (m.u.m, v.u.m);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeCharSet:
+ switch (op) {
+ case FcOpContains:
+ /* m contains v if v - m is empty */
+ ret = FcCharSetSubtractCount (v.u.c, m.u.c) == 0;
+ break;
+ case FcOpEqual:
+ ret = FcCharSetEqual (m.u.c, v.u.c);
+ break;
+ case FcOpNotEqual:
+ ret = !FcCharSetEqual (m.u.c, v.u.c);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeVoid:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ ret = FcTrue;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (op == FcOpNotEqual)
+ ret = FcTrue;
+ }
+ return ret;
+}
+
+
+static FcValue
+FcConfigEvaluate (FcPattern *p, FcExpr *e)
+{
+ FcValue v, vl, vr;
+ FcResult r;
+ FcMatrix *m;
+ FcChar8 *s;
+
+ switch (e->op) {
+ case FcOpInteger:
+ v.type = FcTypeInteger;
+ v.u.i = e->u.ival;
+ break;
+ case FcOpDouble:
+ v.type = FcTypeDouble;
+ v.u.d = e->u.dval;
+ break;
+ case FcOpString:
+ v.type = FcTypeString;
+ v.u.s = e->u.sval;
+ v = FcValueSave (v);
+ break;
+ case FcOpMatrix:
+ v.type = FcTypeMatrix;
+ v.u.m = e->u.mval;
+ v = FcValueSave (v);
+ break;
+ case FcOpCharSet:
+ v.type = FcTypeCharSet;
+ v.u.c = e->u.cval;
+ v = FcValueSave (v);
+ break;
+ case FcOpBool:
+ v.type = FcTypeBool;
+ v.u.b = e->u.bval;
+ break;
+ case FcOpField:
+ r = FcPatternGet (p, e->u.field, 0, &v);
+ if (r != FcResultMatch)
+ v.type = FcTypeVoid;
+ break;
+ case FcOpConst:
+ if (FcNameConstant (e->u.constant, &v.u.i))
+ v.type = FcTypeInteger;
+ else
+ v.type = FcTypeVoid;
+ break;
+ case FcOpQuest:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ if (vl.type == FcTypeBool)
+ {
+ if (vl.u.b)
+ v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
+ else
+ v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
+ }
+ else
+ v.type = FcTypeVoid;
+ FcValueDestroy (vl);
+ break;
+ case FcOpOr:
+ case FcOpAnd:
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpNotEqual:
+ case FcOpLess:
+ case FcOpLessEqual:
+ case FcOpMore:
+ case FcOpMoreEqual:
+ case FcOpPlus:
+ case FcOpMinus:
+ case FcOpTimes:
+ case FcOpDivide:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ vr = FcConfigEvaluate (p, e->u.tree.right);
+ vl = FcConfigPromote (vl, vr);
+ vr = FcConfigPromote (vr, vl);
+ if (vl.type == vr.type)
+ {
+ switch (vl.type) {
+ case FcTypeDouble:
+ switch (e->op) {
+ case FcOpPlus:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d + vr.u.d;
+ break;
+ case FcOpMinus:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d - vr.u.d;
+ break;
+ case FcOpTimes:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d * vr.u.d;
+ break;
+ case FcOpDivide:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d / vr.u.d;
+ break;
+ case FcOpEqual:
+ case FcOpContains:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.d == vr.u.d;
+ break;
+ case FcOpNotEqual:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.d != vr.u.d;
+ break;
+ case FcOpLess:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.d < vr.u.d;
+ break;
+ case FcOpLessEqual:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.d <= vr.u.d;
+ break;
+ case FcOpMore:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.d > vr.u.d;
+ break;
+ case FcOpMoreEqual:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.d >= vr.u.d;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ if (v.type == FcTypeDouble &&
+ v.u.d == (double) (int) v.u.d)
+ {
+ v.type = FcTypeInteger;
+ v.u.i = (int) v.u.d;
+ }
+ break;
+ case FcTypeBool:
+ switch (e->op) {
+ case FcOpOr:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.b || vr.u.b;
+ break;
+ case FcOpAnd:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.b && vr.u.b;
+ break;
+ case FcOpEqual:
+ case FcOpContains:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.b == vr.u.b;
+ break;
+ case FcOpNotEqual:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.b != vr.u.b;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ case FcTypeString:
+ switch (e->op) {
+ case FcOpEqual:
+ case FcOpContains:
+ v.type = FcTypeBool;
+ v.u.b = FcStrCmpIgnoreCase (vl.u.s, vr.u.s) == 0;
+ break;
+ case FcOpNotEqual:
+ v.type = FcTypeBool;
+ v.u.b = FcStrCmpIgnoreCase (vl.u.s, vr.u.s) != 0;
+ break;
+ case FcOpPlus:
+ v.type = FcTypeString;
+ v.u.s = FcStrPlus (vl.u.s, vr.u.s);
+ if (!v.u.s)
+ v.type = FcTypeVoid;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ case FcTypeMatrix:
+ switch (e->op) {
+ case FcOpEqual:
+ case FcOpContains:
+ v.type = FcTypeBool;
+ v.u.b = FcMatrixEqual (vl.u.m, vr.u.m);
+ break;
+ case FcOpNotEqual:
+ v.type = FcTypeBool;
+ v.u.b = FcMatrixEqual (vl.u.m, vr.u.m);
+ break;
+ case FcOpTimes:
+ v.type = FcTypeMatrix;
+ m = malloc (sizeof (FcMatrix));
+ if (m)
+ {
+ FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
+ FcMatrixMultiply (m, vl.u.m, vr.u.m);
+ v.u.m = m;
+ }
+ else
+ {
+ v.type = FcTypeVoid;
+ }
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ case FcTypeCharSet:
+ switch (e->op) {
+ case FcOpContains:
+ /* vl contains vr if vr - vl is empty */
+ v.type = FcTypeBool;
+ v.u.b = FcCharSetSubtractCount (vr.u.c, vl.u.c) == 0;
+ break;
+ case FcOpEqual:
+ v.type = FcTypeBool;
+ v.u.b = FcCharSetEqual (vl.u.c, vr.u.c);
+ break;
+ case FcOpNotEqual:
+ v.type = FcTypeBool;
+ v.u.b = !FcCharSetEqual (vl.u.c, vr.u.c);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ }
+ else
+ v.type = FcTypeVoid;
+ FcValueDestroy (vl);
+ FcValueDestroy (vr);
+ break;
+ case FcOpNot:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ switch (vl.type) {
+ case FcTypeBool:
+ v.type = FcTypeBool;
+ v.u.b = !vl.u.b;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ FcValueDestroy (vl);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ return v;
+}
+
+static FcValueList *
+FcConfigMatchValueList (FcPattern *p,
+ FcTest *t,
+ FcValueList *v)
+{
+ FcValueList *ret = 0;
+ FcValue value = FcConfigEvaluate (p, t->expr);
+
+ for (; v; v = v->next)
+ {
+ if (FcConfigCompareValue (v->value, t->op, value))
+ {
+ if (!ret)
+ ret = v;
+ }
+ else
+ {
+ if (t->qual == FcQualAll)
+ {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ FcValueDestroy (value);
+ return ret;
+}
+
+static FcValueList *
+FcConfigValues (FcPattern *p, FcExpr *e)
+{
+ FcValueList *l;
+
+ if (!e)
+ return 0;
+ l = (FcValueList *) malloc (sizeof (FcValueList));
+ if (!l)
+ return 0;
+ FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
+ if (e->op == FcOpComma)
+ {
+ l->value = FcConfigEvaluate (p, e->u.tree.left);
+ l->next = FcConfigValues (p, e->u.tree.right);
+ }
+ else
+ {
+ l->value = FcConfigEvaluate (p, e);
+ l->next = 0;
+ }
+ while (l->value.type == FcTypeVoid)
+ {
+ FcValueList *next = l->next;
+
+ FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+ free (l);
+ l = next;
+ }
+ return l;
+}
+
+static FcBool
+FcConfigAdd (FcValueList **head,
+ FcValueList *position,
+ FcBool append,
+ FcValueList *new)
+{
+ FcValueList **prev, *last;
+
+ if (append)
+ {
+ if (position)
+ prev = &position->next;
+ else
+ for (prev = head; *prev; prev = &(*prev)->next)
+ ;
+ }
+ else
+ {
+ if (position)
+ {
+ for (prev = head; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == position)
+ break;
+ }
+ }
+ else
+ prev = head;
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ if (!*prev)
+ printf ("position not on list\n");
+ }
+ }
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("%s list before ", append ? "Append" : "Prepend");
+ FcValueListPrint (*head);
+ printf ("\n");
+ }
+
+ if (new)
+ {
+ last = new;
+ while (last->next)
+ last = last->next;
+
+ last->next = *prev;
+ *prev = new;
+ }
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("%s list after ", append ? "Append" : "Prepend");
+ FcValueListPrint (*head);
+ printf ("\n");
+ }
+
+ return FcTrue;
+}
+
+static void
+FcConfigDel (FcValueList **head,
+ FcValueList *position)
+{
+ FcValueList **prev;
+
+ for (prev = head; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == position)
+ {
+ *prev = position->next;
+ position->next = 0;
+ FcValueListDestroy (position);
+ break;
+ }
+ }
+}
+
+static void
+FcConfigPatternAdd (FcPattern *p,
+ const char *object,
+ FcValueList *list,
+ FcBool append)
+{
+ if (list)
+ {
+ FcPatternElt *e = FcPatternFind (p, object, FcTrue);
+
+ if (!e)
+ return;
+ FcConfigAdd (&e->values, 0, append, list);
+ }
+}
+
+/*
+ * Delete all values associated with a field
+ */
+static void
+FcConfigPatternDel (FcPattern *p,
+ const char *object)
+{
+ FcPatternElt *e = FcPatternFind (p, object, FcFalse);
+ if (!e)
+ return;
+ while (e->values)
+ FcConfigDel (&e->values, e->values);
+}
+
+static void
+FcConfigPatternCanon (FcPattern *p,
+ const char *object)
+{
+ FcPatternElt *e = FcPatternFind (p, object, FcFalse);
+ if (!e)
+ return;
+ if (!e->values)
+ FcPatternDel (p, object);
+}
+
+FcBool
+FcConfigSubstitute (FcConfig *config,
+ FcPattern *p,
+ FcMatchKind kind)
+{
+ FcSubst *s;
+ FcSubState *st;
+ int i;
+ FcTest *t;
+ FcEdit *e;
+ FcValueList *l;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+
+ st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
+ if (!st && config->maxObjects)
+ return FcFalse;
+ FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute ");
+ FcPatternPrint (p);
+ }
+ if (kind == FcMatchPattern)
+ s = config->substPattern;
+ else
+ s = config->substFont;
+ for (; s; s = s->next)
+ {
+ /*
+ * Check the tests to see if
+ * they all match the pattern
+ */
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute test ");
+ FcTestPrint (t);
+ }
+ st[i].elt = FcPatternFind (p, t->field, FcFalse);
+ /*
+ * If there's no such field in the font,
+ * then FcQualAll matches while FcQualAny does not
+ */
+ if (!st[i].elt)
+ {
+ if (t->qual == FcQualAll)
+ {
+ st[i].value = 0;
+ continue;
+ }
+ else
+ break;
+ }
+ /*
+ * Check to see if there is a match, mark the location
+ * to apply match-relative edits
+ */
+ st[i].value = FcConfigMatchValueList (p, t, st[i].elt->values);
+ if (!st[i].value)
+ break;
+ }
+ if (t)
+ {
+ if (FcDebug () & FC_DBG_EDIT)
+ printf ("No match\n");
+ continue;
+ }
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("Substitute ");
+ FcSubstPrint (s);
+ }
+ for (e = s->edit; e; e = e->next)
+ {
+ /*
+ * Evaluate the list of expressions
+ */
+ l = FcConfigValues (p, e->expr);
+ /*
+ * Locate any test associated with this field
+ */
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ if (!FcStrCmpIgnoreCase (t->field, e->field))
+ break;
+ switch (e->op) {
+ case FcOpAssign:
+ /*
+ * If there was a test, then replace the matched
+ * value with the new list of values
+ */
+ if (t)
+ {
+ FcValueList *thisValue = st[i].value;
+ FcValueList *nextValue = thisValue ? thisValue->next : 0;
+
+ /*
+ * Append the new list of values after the current value
+ */
+ FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
+ /*
+ * Adjust any pointers into the value list to ensure
+ * future edits occur at the same place
+ */
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if (st[i].value == thisValue)
+ st[i].value = nextValue;
+ }
+ /*
+ * Delete the marked value
+ */
+ FcConfigDel (&st[i].elt->values, thisValue);
+ break;
+ }
+ /* fall through ... */
+ case FcOpAssignReplace:
+ /*
+ * Delete all of the values and insert
+ * the new set
+ */
+ FcConfigPatternDel (p, e->field);
+ FcConfigPatternAdd (p, e->field, l, FcTrue);
+ /*
+ * Adjust any pointers into the value list as they no
+ * longer point to anything valid
+ */
+ if (t)
+ {
+ FcPatternElt *thisElt = st[i].elt;
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if (st[i].elt == thisElt)
+ st[i].value = 0;
+ }
+ }
+ break;
+ case FcOpPrepend:
+ if (t)
+ {
+ FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
+ break;
+ }
+ /* fall through ... */
+ case FcOpPrependFirst:
+ FcConfigPatternAdd (p, e->field, l, FcFalse);
+ break;
+ case FcOpAppend:
+ if (t)
+ {
+ FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
+ break;
+ }
+ /* fall through ... */
+ case FcOpAppendLast:
+ FcConfigPatternAdd (p, e->field, l, FcTrue);
+ break;
+ default:
+ break;
+ }
+ }
+ /*
+ * Now go through the pattern and eliminate
+ * any properties without data
+ */
+ for (e = s->edit; e; e = e->next)
+ FcConfigPatternCanon (p, e->field);
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute edit");
+ FcPatternPrint (p);
+ }
+ }
+ FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+ free (st);
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute done");
+ FcPatternPrint (p);
+ }
+ return FcTrue;
+}
+
+#ifndef FONTCONFIG_PATH
+#define FONTCONFIG_PATH "/etc/fonts"
+#endif
+
+#ifndef FONTCONFIG_FILE
+#define FONTCONFIG_FILE "fonts.conf"
+#endif
+
+static char *
+FcConfigFileExists (const char *dir, const char *file)
+{
+ char *path;
+
+ if (!dir)
+ dir = "";
+ path = malloc (strlen (dir) + 1 + strlen (file) + 1);
+ if (!path)
+ return 0;
+
+ strcpy (path, dir);
+ /* make sure there's a single separating / */
+ if ((!path[0] || path[strlen(path)-1] != '/') && file[0] != '/')
+ strcat (path, "/");
+ strcat (path, file);
+
+ if (access (path, R_OK) == 0)
+ return path;
+
+ free (path);
+ return 0;
+}
+
+static char **
+FcConfigGetPath (void)
+{
+ char **path;
+ char *env, *e, *colon;
+ char *dir;
+ int npath;
+ int i;
+
+ npath = 2; /* default dir + null */
+ env = getenv ("FONTCONFIG_PATH");
+ if (env)
+ {
+ e = env;
+ npath++;
+ while (*e)
+ if (*e++ == ':')
+ npath++;
+ }
+ path = calloc (npath, sizeof (char *));
+ if (!path)
+ goto bail0;
+ i = 0;
+
+ if (env)
+ {
+ e = env;
+ while (*e)
+ {
+ colon = strchr (e, ':');
+ if (!colon)
+ colon = e + strlen (e);
+ path[i] = malloc (colon - e + 1);
+ if (!path[i])
+ goto bail1;
+ strncpy (path[i], e, colon - e);
+ path[i][colon - e] = '\0';
+ if (*colon)
+ e = colon + 1;
+ else
+ e = colon;
+ i++;
+ }
+ }
+
+ dir = FONTCONFIG_PATH;
+ path[i] = malloc (strlen (dir) + 1);
+ if (!path[i])
+ goto bail1;
+ strcpy (path[i], dir);
+ return path;
+
+bail1:
+ for (i = 0; path[i]; i++)
+ free (path[i]);
+ free (path);
+bail0:
+ return 0;
+}
+
+static void
+FcConfigFreePath (char **path)
+{
+ char **p;
+
+ for (p = path; *p; p++)
+ free (*p);
+ free (path);
+}
+
+char *
+FcConfigFilename (const char *url)
+{
+ char *file, *dir, **path, **p;
+
+ if (!url || !*url)
+ {
+ url = getenv ("FONTCONFIG_FILE");
+ if (!url)
+ url = FONTCONFIG_FILE;
+ }
+ switch (*url) {
+ case '~':
+ dir = getenv ("HOME");
+ if (dir)
+ file = FcConfigFileExists (dir, url + 1);
+ else
+ file = 0;
+ break;
+ case '/':
+ file = FcConfigFileExists (0, url);
+ break;
+ default:
+ path = FcConfigGetPath ();
+ if (!path)
+ return 0;
+ for (p = path; *p; p++)
+ {
+ file = FcConfigFileExists (*p, url);
+ if (file)
+ break;
+ }
+ FcConfigFreePath (path);
+ break;
+ }
+ return file;
+}
+
+/*
+ * Manage the application-specific fonts
+ */
+
+FcBool
+FcConfigAppFontAddFile (FcConfig *config,
+ const char *file)
+{
+ FcFontSet *set;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+
+ set = FcConfigGetFonts (config, FcSetApplication);
+ if (!set)
+ {
+ set = FcFontSetCreate ();
+ if (!set)
+ return FcFalse;
+ FcConfigSetFonts (config, set, FcSetApplication);
+ }
+ return FcFileScan (set, 0, config->blanks, file, FcFalse);
+}
+
+FcBool
+FcConfigAppFontAddDir (FcConfig *config,
+ const char *dir)
+{
+ FcFontSet *set;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+ set = FcConfigGetFonts (config, FcSetApplication);
+ if (!set)
+ {
+ set = FcFontSetCreate ();
+ if (!set)
+ return FcFalse;
+ FcConfigSetFonts (config, set, FcSetApplication);
+ }
+ return FcDirScan (set, 0, config->blanks, dir, FcFalse);
+}
+
+void
+FcConfigAppFontClear (FcConfig *config)
+{
+ FcConfigSetFonts (config, 0, FcSetApplication);
+}
diff --git a/src/fccharset.c b/src/fccharset.c
new file mode 100644
index 0000000..b29a48a
--- /dev/null
+++ b/src/fccharset.c
@@ -0,0 +1,1521 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+/* #define CHECK */
+
+static int
+FcCharSetLevels (FcChar32 ucs4)
+{
+ if (ucs4 <= 0xff)
+ return 1;
+ if (ucs4 <= 0xffff)
+ return 2;
+ if (ucs4 <= 0xffffff)
+ return 3;
+ return 4;
+}
+
+static FcBool
+FcCharSetCheckLevel (FcCharSet *fcs, FcChar32 ucs4)
+{
+ int level = FcCharSetLevels (ucs4);
+
+ if (level <= fcs->levels)
+ return FcTrue;
+ while (fcs->levels < level)
+ {
+ if (fcs->levels == 0)
+ {
+ FcCharLeaf *leaf;
+
+ leaf = (FcCharLeaf *) calloc (1, sizeof (FcCharLeaf));
+ if (!leaf)
+ return FcFalse;
+ FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharLeaf));
+ fcs->node.leaf = leaf;
+ }
+ else
+ {
+ FcCharBranch *branch;
+
+ branch = (FcCharBranch *) calloc (1, sizeof (FcCharBranch));
+ if (!branch)
+ return FcFalse;
+ FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharBranch));
+ branch->nodes[0] = fcs->node;
+ fcs->node.branch = branch;
+ }
+ ++fcs->levels;
+ }
+ return FcTrue;
+}
+
+FcCharSet *
+FcCharSetCreate (void)
+{
+ FcCharSet *fcs;
+
+ fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
+ if (!fcs)
+ return 0;
+ FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
+ fcs->ref = 1;
+ fcs->levels = 0;
+ fcs->node.leaf = 0;
+ fcs->constant = FcFalse;
+ return fcs;
+}
+
+FcCharSet *
+FcCharSetNew (void);
+
+FcCharSet *
+FcCharSetNew (void)
+{
+ return FcCharSetCreate ();
+}
+
+static void
+FcCharNodeDestroy (FcCharNode node, int level)
+{
+ int i;
+
+ switch (level) {
+ case 0:
+ break;
+ case 1:
+ FcMemFree (FC_MEM_CHARNODE, sizeof (FcCharLeaf));
+ free (node.leaf);
+ break;
+ default:
+ for (i = 0; i < 256; i++)
+ if (node.branch->nodes[i].branch)
+ FcCharNodeDestroy (node.branch->nodes[i], level - 1);
+ FcMemFree (FC_MEM_CHARNODE, sizeof (FcCharBranch));
+ free (node.branch);
+ }
+}
+
+void
+FcCharSetDestroy (FcCharSet *fcs)
+{
+ if (fcs->constant)
+ return;
+ if (--fcs->ref <= 0)
+ {
+ FcCharNodeDestroy (fcs->node, fcs->levels);
+ FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
+ free (fcs);
+ }
+}
+
+/*
+ * Locate the leaf containing the specified char, returning
+ * null if it doesn't exist
+ */
+
+static FcCharLeaf *
+FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
+{
+ int l;
+ const FcCharNode *prev;
+ FcCharNode node;
+ FcChar8 i;
+
+ prev = &fcs->node;
+ l = fcs->levels;
+ while (--l > 0)
+ {
+ node = *prev;
+ if (!node.branch)
+ return 0;
+ i = (ucs4 >> (l << 3)) & 0xff;
+ prev = &node.branch->nodes[i];
+ }
+ return prev->leaf;
+}
+
+/*
+ * Locate the leaf containing the specified char, creating it
+ * if desired
+ */
+
+static FcCharLeaf *
+FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
+{
+ int l;
+ FcCharNode *prev, node;
+ FcChar8 i;
+
+ if (!FcCharSetCheckLevel (fcs, ucs4))
+ return FcFalse;
+ prev = &fcs->node;
+ l = fcs->levels;
+ while (--l > 0)
+ {
+ node = *prev;
+ if (!node.branch)
+ {
+ node.branch = calloc (1, sizeof (FcCharBranch));
+ if (!node.branch)
+ return 0;
+ FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharBranch));
+ *prev = node;
+ }
+ i = (ucs4 >> (l << 3)) & 0xff;
+ prev = &node.branch->nodes[i];
+ }
+ node = *prev;
+ if (!node.leaf)
+ {
+ node.leaf = calloc (1, sizeof (FcCharLeaf));
+ if (!node.leaf)
+ return 0;
+ FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharLeaf));
+ *prev = node;
+ }
+ return node.leaf;
+}
+
+FcBool
+FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
+{
+ FcCharLeaf *leaf;
+ FcChar32 *b;
+
+ if (fcs->constant)
+ return FcFalse;
+ leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+ if (!leaf)
+ return FcFalse;
+ b = &leaf->map[(ucs4 & 0xff) >> 5];
+ *b |= (1 << (ucs4 & 0x1f));
+ return FcTrue;
+}
+
+/*
+ * An iterator for the leaves of a charset
+ */
+
+typedef struct _fcCharSetIter {
+ FcCharLeaf *leaf;
+ FcChar32 ucs4;
+} FcCharSetIter;
+
+/*
+ * Find the nearest leaf at or beyond *ucs4, return 0 if no leaf
+ * exists
+ */
+static FcCharLeaf *
+FcCharSetIterLeaf (FcCharNode node, int level, FcChar32 *ucs4)
+{
+ if (level <= 1)
+ return node.leaf;
+ else if (!node.branch)
+ return 0;
+ else
+ {
+ int shift = ((level - 1) << 3);
+ FcChar32 inc = 1 << shift;
+ FcChar32 mask = ~(inc - 1);
+ FcChar8 byte = (*ucs4 >> shift) & 0xff;
+ FcCharLeaf *leaf;
+
+ for (;;)
+ {
+ leaf = FcCharSetIterLeaf (node.branch->nodes[byte],
+ level - 1,
+ ucs4);
+ if (leaf)
+ break;
+ /* step to next branch, resetting lower indices */
+ *ucs4 = (*ucs4 & mask) + inc;
+ byte++;
+ if (byte == 0)
+ break;
+ }
+ return leaf;
+ }
+}
+
+static void
+FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+ if (FcCharSetLevels (iter->ucs4) > fcs->levels)
+ iter->leaf = 0;
+ else
+ iter->leaf = FcCharSetIterLeaf (fcs->node, fcs->levels,
+ &iter->ucs4);
+ if (!iter->leaf)
+ iter->ucs4 = ~0;
+}
+
+static void
+FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+ iter->ucs4 += 0x100;
+ FcCharSetIterSet (fcs, iter);
+}
+
+static void
+FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+ iter->ucs4 = 0;
+ FcCharSetIterSet (fcs, iter);
+}
+
+FcCharSet *
+FcCharSetCopy (FcCharSet *src)
+{
+ src->ref++;
+ return src;
+}
+
+FcBool
+FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSetIter ai, bi;
+ int i;
+
+ if (a == b)
+ return FcTrue;
+ for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
+ ai.leaf && bi.leaf;
+ FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
+ {
+ if (ai.ucs4 != bi.ucs4)
+ return FcFalse;
+ for (i = 0; i < 256/32; i++)
+ if (ai.leaf->map[i] != bi.leaf->map[i])
+ return FcFalse;
+ }
+ return ai.leaf == bi.leaf;
+}
+
+static FcBool
+FcCharSetAddLeaf (FcCharSet *fcs,
+ FcChar32 ucs4,
+ FcCharLeaf *leaf)
+{
+ FcCharLeaf *new = FcCharSetFindLeafCreate (fcs, ucs4);
+ if (!new)
+ return FcFalse;
+ *new = *leaf;
+ return FcTrue;
+}
+
+static FcCharSet *
+FcCharSetOperate (const FcCharSet *a,
+ const FcCharSet *b,
+ FcBool (*overlap) (FcCharLeaf *result,
+ const FcCharLeaf *al,
+ const FcCharLeaf *bl),
+ FcBool aonly,
+ FcBool bonly)
+{
+ FcCharSet *fcs;
+ FcCharSetIter ai, bi;
+
+ fcs = FcCharSetCreate ();
+ if (!fcs)
+ goto bail0;
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while ((ai.leaf || bonly) && (bi.leaf || aonly))
+ {
+ if (ai.ucs4 < bi.ucs4)
+ {
+ if (aonly)
+ {
+ if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
+ goto bail1;
+ FcCharSetIterNext (a, &ai);
+ }
+ else
+ {
+ ai.ucs4 = bi.ucs4;
+ FcCharSetIterSet (a, &ai);
+ }
+ }
+ else if (bi.ucs4 < ai.ucs4 )
+ {
+ if (bonly)
+ {
+ if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
+ goto bail1;
+ FcCharSetIterNext (b, &bi);
+ }
+ else
+ {
+ bi.ucs4 = ai.ucs4;
+ FcCharSetIterSet (b, &bi);
+ }
+ }
+ else
+ {
+ FcCharLeaf leaf;
+
+ if ((*overlap) (&leaf, ai.leaf, bi.leaf))
+ {
+ if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
+ goto bail1;
+ }
+ FcCharSetIterNext (a, &ai);
+ FcCharSetIterNext (b, &bi);
+ }
+ }
+ return fcs;
+bail1:
+ FcCharSetDestroy (fcs);
+bail0:
+ return 0;
+}
+
+static FcBool
+FcCharSetIntersectLeaf (FcCharLeaf *result,
+ const FcCharLeaf *al,
+ const FcCharLeaf *bl)
+{
+ int i;
+ FcBool nonempty = FcFalse;
+
+ for (i = 0; i < 256/32; i++)
+ if ((result->map[i] = al->map[i] & bl->map[i]))
+ nonempty = FcTrue;
+ return nonempty;
+}
+
+FcCharSet *
+FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
+{
+ return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
+}
+
+static FcBool
+FcCharSetUnionLeaf (FcCharLeaf *result,
+ const FcCharLeaf *al,
+ const FcCharLeaf *bl)
+{
+ int i;
+
+ for (i = 0; i < 256/32; i++)
+ result->map[i] = al->map[i] | bl->map[i];
+ return FcTrue;
+}
+
+FcCharSet *
+FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
+{
+ return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
+}
+
+static FcBool
+FcCharSetSubtractLeaf (FcCharLeaf *result,
+ const FcCharLeaf *al,
+ const FcCharLeaf *bl)
+{
+ int i;
+ FcBool nonempty = FcFalse;
+
+ for (i = 0; i < 256/32; i++)
+ if ((result->map[i] = al->map[i] & ~bl->map[i]))
+ nonempty = FcTrue;
+ return nonempty;
+}
+
+FcCharSet *
+FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
+{
+ return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
+}
+
+FcBool
+FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
+{
+ FcCharLeaf *leaf = FcCharSetFindLeaf (fcs, ucs4);
+ if (!leaf)
+ return FcFalse;
+ return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0;
+}
+
+static FcChar32
+FcCharSetPopCount (FcChar32 c1)
+{
+ /* hackmem 169 */
+ FcChar32 c2 = (c1 >> 1) & 033333333333;
+ c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
+ return (((c2 + (c2 >> 3)) & 030707070707) % 077);
+}
+
+FcChar32
+FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSetIter ai, bi;
+ FcChar32 count = 0;
+
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while (ai.leaf && bi.leaf)
+ {
+ if (ai.ucs4 == bi.ucs4)
+ {
+ FcChar32 *am = ai.leaf->map;
+ FcChar32 *bm = bi.leaf->map;
+ int i = 256/32;
+ while (i--)
+ count += FcCharSetPopCount (*am++ & *bm++);
+ FcCharSetIterNext (a, &ai);
+ }
+ else if (ai.ucs4 < bi.ucs4)
+ {
+ ai.ucs4 = bi.ucs4;
+ FcCharSetIterSet (a, &ai);
+ }
+ if (bi.ucs4 < ai.ucs4)
+ {
+ bi.ucs4 = ai.ucs4;
+ FcCharSetIterSet (b, &bi);
+ }
+ }
+ return count;
+}
+
+FcChar32
+FcCharSetCount (const FcCharSet *a)
+{
+ FcCharSetIter ai;
+ FcChar32 count = 0;
+
+ for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
+ {
+ int i = 256/32;
+ FcChar32 *am = ai.leaf->map;
+
+ while (i--)
+ count += FcCharSetPopCount (*am++);
+ }
+ return count;
+}
+
+FcChar32
+FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSetIter ai, bi;
+ FcChar32 count = 0;
+
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while (ai.leaf)
+ {
+ if (ai.ucs4 <= bi.ucs4)
+ {
+ FcChar32 *am = ai.leaf->map;
+ int i = 256/32;
+ if (ai.ucs4 == bi.ucs4)
+ {
+ FcChar32 *bm = bi.leaf->map;;
+ while (i--)
+ count += FcCharSetPopCount (*am++ & ~*bm++);
+ }
+ else
+ {
+ while (i--)
+ count += FcCharSetPopCount (*am++);
+ }
+ FcCharSetIterNext (a, &ai);
+ }
+ else if (bi.leaf)
+ {
+ bi.ucs4 = ai.ucs4;
+ FcCharSetIterSet (b, &bi);
+ }
+ }
+ return count;
+}
+
+/*
+ * ASCII representation of charsets.
+ *
+ * Each leaf is represented as 9 32-bit values, the code of the first character followed
+ * by 8 32 bit values for the leaf itself. Each value is encoded as 5 ASCII characters,
+ * only 85 different values are used to avoid control characters as well as the other
+ * characters used to encode font names. 85**5 > 2^32 so things work out, but
+ * it's not exactly human readable output. As a special case, 0 is encoded as a space
+ */
+
+static FcChar8 charToValue[256] = {
+ /* "" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\b" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\020" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\030" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* " " */ 0xff, 0x00, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff,
+ /* "(" */ 0x05, 0x06, 0x07, 0x08, 0xff, 0xff, 0x09, 0x0a,
+ /* "0" */ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ /* "8" */ 0x13, 0x14, 0xff, 0x15, 0x16, 0xff, 0x17, 0x18,
+ /* "@" */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ /* "H" */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ /* "P" */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ /* "X" */ 0x31, 0x32, 0x33, 0x34, 0xff, 0x35, 0x36, 0xff,
+ /* "`" */ 0xff, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
+ /* "h" */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+ /* "p" */ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
+ /* "x" */ 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0xff,
+ /* "\200" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\210" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\220" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\230" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\240" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\250" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\260" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\270" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\300" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\310" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\320" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\330" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\340" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\350" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\360" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\370" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static FcChar8 valueToChar[0x55] = {
+ /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
+ /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
+ /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
+ /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
+ /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+ /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
+ /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
+ /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
+ /* 0x50 */ 'z', '{', '|', '}', '~',
+};
+
+static FcChar8 *
+FcCharSetParseValue (FcChar8 *string, FcChar32 *value)
+{
+ int i;
+ FcChar32 v;
+ FcChar8 c;
+
+ if (*string == ' ')
+ {
+ v = 0;
+ string++;
+ }
+ else
+ {
+ v = 0;
+ for (i = 0; i < 5; i++)
+ {
+ if (!(c = *string++))
+ return 0;
+ c = charToValue[c];
+ if (c == 0xff)
+ return 0;
+ v = v * 85 + c;
+ }
+ }
+ *value = v;
+ return string;
+}
+
+static FcBool
+FcCharSetUnparseValue (FcNameBuf *buf, FcChar32 value)
+{
+ int i;
+ if (value == 0)
+ {
+ return FcNameBufChar (buf, ' ');
+ }
+ else
+ {
+ FcChar8 string[6];
+ FcChar8 *s = string + 5;
+ string[5] = '\0';
+ for (i = 0; i < 5; i++)
+ {
+ *--s = valueToChar[value % 85];
+ value /= 85;
+ }
+ for (i = 0; i < 5; i++)
+ if (!FcNameBufChar (buf, *s++))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+FcCharSet *
+FcNameParseCharSet (FcChar8 *string)
+{
+ FcCharSet *c;
+ FcChar32 ucs4;
+ FcCharLeaf *leaf;
+ int i;
+
+ c = FcCharSetCreate ();
+ if (!c)
+ goto bail0;
+ while (*string)
+ {
+ string = FcCharSetParseValue (string, &ucs4);
+ if (!string)
+ goto bail1;
+ leaf = FcCharSetFindLeafCreate (c, ucs4);
+ if (!leaf)
+ goto bail1;
+ for (i = 0; i < 256/32; i++)
+ {
+ string = FcCharSetParseValue (string, &leaf->map[i]);
+ if (!string)
+ goto bail1;
+ }
+ }
+ return c;
+bail1:
+ FcCharSetDestroy (c);
+bail0:
+ return 0;
+}
+
+FcBool
+FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c)
+{
+ FcCharSetIter ci;
+ int i;
+#ifdef CHECK
+ int len = buf->len;
+#endif
+
+ for (FcCharSetIterStart (c, &ci);
+ ci.leaf;
+ FcCharSetIterNext (c, &ci))
+ {
+ if (!FcCharSetUnparseValue (buf, ci.ucs4))
+ return FcFalse;
+ for (i = 0; i < 256/32; i++)
+ if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
+ return FcFalse;
+ }
+#ifdef CHECK
+ {
+ FcCharSet *check;
+ FcChar32 missing;
+ FcCharSetIter ci, checki;
+
+ /* null terminate for parser */
+ FcNameBufChar (buf, '\0');
+ /* step back over null for life after test */
+ buf->len--;
+ check = FcNameParseCharSet (buf->buf + len);
+ FcCharSetIterStart (c, &ci);
+ FcCharSetIterStart (check, &checki);
+ while (ci.leaf || checki.leaf)
+ {
+ if (ci.ucs4 < checki.ucs4)
+ {
+ printf ("Missing leaf node at 0x%x\n", ci.ucs4);
+ FcCharSetIterNext (c, &ci);
+ }
+ else if (checki.ucs4 < ci.ucs4)
+ {
+ printf ("Extra leaf node at 0x%x\n", checki.ucs4);
+ FcCharSetIterNext (check, &checki);
+ }
+ else
+ {
+ int i = 256/32;
+ FcChar32 *cm = ci.leaf->map;
+ FcChar32 *checkm = checki.leaf->map;
+
+ for (i = 0; i < 256; i += 32)
+ {
+ if (*cm != *checkm)
+ printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
+ ci.ucs4 + i, *cm, *checkm);
+ cm++;
+ checkm++;
+ }
+ FcCharSetIterNext (c, &ci);
+ FcCharSetIterNext (check, &checki);
+ }
+ }
+ if ((missing = FcCharSetSubtractCount (c, check)))
+ printf ("%d missing in reparsed result\n", missing);
+ if ((missing = FcCharSetSubtractCount (check, c)))
+ printf ("%d extra in reparsed result\n", missing);
+ FcCharSetDestroy (check);
+ }
+#endif
+
+ return FcTrue;
+}
+
+#include <freetype/freetype.h>
+#include <fontconfig/fcfreetype.h>
+
+/*
+ * Figure out whether the available freetype has FT_Get_Next_Char
+ */
+
+#if FREETYPE_MAJOR > 2
+# define HAS_NEXT_CHAR
+#else
+# if FREETYPE_MAJOR == 2
+# if FREETYPE_MINOR > 0
+# define HAS_NEXT_CHAR
+# else
+# if FREETYPE_MINOR == 0
+# if FREETYPE_PATCH >= 8
+# define HAS_NEXT_CHAR
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/*
+ * For our purposes, this approximation is sufficient
+ */
+#ifndef HAS_NEXT_CHAR
+#define FT_Get_Next_Char(face, ucs4) ((ucs4) >= 0xffffff ? 0 : (ucs4) + 1)
+#warning "No FT_Get_Next_Char"
+#endif
+
+typedef struct _FcCharEnt {
+ FcChar16 bmp;
+ FcChar8 encode;
+} FcCharEnt;
+
+typedef struct _FcCharMap {
+ const FcCharEnt *ent;
+ int nent;
+} FcCharMap;
+
+typedef struct _FcFontDecode {
+ FT_Encoding encoding;
+ const FcCharMap *map;
+ FcChar32 max;
+} FcFontDecode;
+
+static const FcCharMap AppleRoman;
+static const FcCharMap AdobeSymbol;
+
+static const FcFontDecode fcFontDecoders[] = {
+ { ft_encoding_unicode, 0, (1 << 21) - 1 },
+ { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
+ { ft_encoding_apple_roman, &AppleRoman, (1 << 16) - 1 },
+};
+
+#define NUM_DECODE (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
+
+static FT_ULong
+FcFreeTypeMapChar (FcChar32 ucs4, const FcCharMap *map)
+{
+ int low, high, mid;
+ FcChar16 bmp;
+
+ low = 0;
+ high = map->nent - 1;
+ if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
+ return ~0;
+ while (high - low > 1)
+ {
+ mid = (high + low) >> 1;
+ bmp = map->ent[mid].bmp;
+ if (ucs4 == bmp)
+ return (FT_ULong) map->ent[mid].encode;
+ if (ucs4 < bmp)
+ high = mid;
+ else
+ low = mid;
+ }
+ for (mid = low; mid <= high; mid++)
+ {
+ if (ucs4 == map->ent[mid].bmp)
+ return (FT_ULong) map->ent[mid].encode;
+ }
+ return ~0;
+}
+
+/*
+ * Map a UCS4 glyph to a glyph index. Use all available encoding
+ * tables to try and find one that works. This information is expected
+ * to be cached by higher levels, so performance isn't critical
+ */
+
+FT_UInt
+FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
+{
+ int initial, offset, decode;
+ FT_UInt glyphindex;
+ FT_ULong charcode;
+
+ initial = 0;
+ /*
+ * Find the current encoding
+ */
+ if (face->charmap)
+ {
+ for (; initial < NUM_DECODE; initial++)
+ if (fcFontDecoders[initial].encoding == face->charmap->encoding)
+ break;
+ if (initial == NUM_DECODE)
+ initial = 0;
+ }
+ /*
+ * Check each encoding for the glyph, starting with the current one
+ */
+ for (offset = 0; offset < NUM_DECODE; offset++)
+ {
+ decode = (initial + offset) % NUM_DECODE;
+ if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
+ if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
+ continue;
+ if (fcFontDecoders[decode].map)
+ {
+ charcode = FcFreeTypeMapChar (ucs4, fcFontDecoders[decode].map);
+ if (charcode == ~0)
+ continue;
+ }
+ else
+ charcode = (FT_ULong) ucs4;
+ glyphindex = FT_Get_Char_Index (face, charcode);
+ if (glyphindex)
+ return glyphindex;
+ }
+ return 0;
+}
+
+static FcBool
+FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
+ FT_UInt glyph, FcBlanks *blanks)
+{
+ FT_Int load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+ FT_GlyphSlot slot;
+
+ /*
+ * When using scalable fonts, only report those glyphs
+ * which can be scaled; otherwise those fonts will
+ * only be available at some sizes, and never when
+ * transformed. Avoid this by simply reporting bitmap-only
+ * glyphs as missing
+ */
+ if (face->face_flags & FT_FACE_FLAG_SCALABLE)
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ if (FT_Load_Glyph (face, glyph, load_flags))
+ return FcFalse;
+
+ slot = face->glyph;
+ if (!glyph)
+ return FcFalse;
+
+ switch (slot->format) {
+ case ft_glyph_format_bitmap:
+ /*
+ * Bitmaps are assumed to be reasonable; if
+ * this proves to be a rash assumption, this
+ * code can be easily modified
+ */
+ return FcTrue;
+ case ft_glyph_format_outline:
+ /*
+ * Glyphs with contours are always OK
+ */
+ if (slot->outline.n_contours != 0)
+ return FcTrue;
+ /*
+ * Glyphs with no contours are only OK if
+ * they're members of the Blanks set specified
+ * in the configuration. If blanks isn't set,
+ * then allow any glyph to be blank
+ */
+ if (!blanks || FcBlanksIsMember (blanks, ucs4))
+ return FcTrue;
+ /* fall through ... */
+ default:
+ }
+ return FcFalse;
+}
+
+FcCharSet *
+FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
+{
+ FcChar32 page, off, max, ucs4;
+#ifdef CHECK
+ FcChar32 font_max = 0;
+#endif
+ FcCharSet *fcs;
+ FcCharLeaf *leaf;
+ const FcCharMap *map;
+ int o;
+ int i;
+ FT_UInt glyph;
+
+ fcs = FcCharSetCreate ();
+ if (!fcs)
+ goto bail0;
+
+ for (o = 0; o < NUM_DECODE; o++)
+ {
+ if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
+ continue;
+ map = fcFontDecoders[o].map;
+ if (map)
+ {
+ /*
+ * Non-Unicode tables are easy; there's a list of all possible
+ * characters
+ */
+ for (i = 0; i < map->nent; i++)
+ {
+ ucs4 = map->ent[i].bmp;
+ glyph = FT_Get_Char_Index (face, map->ent[i].encode);
+ if (glyph && FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks))
+ {
+ leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+ if (!leaf)
+ goto bail1;
+ leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
+#ifdef CHECK
+ if (ucs4 > font_max)
+ font_max = ucs4;
+#endif
+ }
+ }
+ }
+ else
+ {
+ max = fcFontDecoders[o].max;
+
+ /*
+ * Find the first encoded character in the font
+ */
+ ucs4 = 0;
+ if (FT_Get_Char_Index (face, 0))
+ ucs4 = 0;
+ else
+ ucs4 = FT_Get_Next_Char (face, 0);
+
+ for (;;)
+ {
+ page = ucs4 >> 8;
+ leaf = 0;
+ while ((ucs4 >> 8) == page)
+ {
+ glyph = FT_Get_Char_Index (face, ucs4);
+ if (glyph && FcFreeTypeCheckGlyph (face, ucs4,
+ glyph, blanks))
+ {
+ if (!leaf)
+ {
+ leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+ if (!leaf)
+ goto bail1;
+ }
+ off = ucs4 & 0xff;
+ leaf->map[off >> 5] |= (1 << (off & 0x1f));
+#ifdef CHECK
+ if (ucs4 > font_max)
+ font_max = ucs4;
+#endif
+ }
+ ucs4++;
+ }
+ ucs4 = FT_Get_Next_Char (face, ucs4 - 1);
+ if (!ucs4)
+ break;
+ }
+#ifdef CHECK
+ for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
+ {
+ FcBool FT_Has, FC_Has;
+
+ FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
+ FC_Has = FcCharSetHasChar (fcs, ucs4);
+ if (FT_Has != FC_Has)
+ {
+ printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
+ }
+ }
+#endif
+ }
+ }
+#ifdef CHECK
+ printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
+ for (ucs4 = 0; ucs4 <= font_max; ucs4++)
+ {
+ FcBool has_char = FcFreeTypeCharIndex (face, ucs4) != 0;
+ FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
+
+ if (has_char && !has_bit)
+ printf ("Bitmap missing char 0x%x\n", ucs4);
+ else if (!has_char && has_bit)
+ printf ("Bitmap extra char 0x%x\n", ucs4);
+ }
+#endif
+ return fcs;
+bail1:
+ FcCharSetDestroy (fcs);
+bail0:
+ return 0;
+}
+
+static const FcCharEnt AppleRomanEnt[] = {
+ { 0x0020, 0x20 }, /* SPACE */
+ { 0x0021, 0x21 }, /* EXCLAMATION MARK */
+ { 0x0022, 0x22 }, /* QUOTATION MARK */
+ { 0x0023, 0x23 }, /* NUMBER SIGN */
+ { 0x0024, 0x24 }, /* DOLLAR SIGN */
+ { 0x0025, 0x25 }, /* PERCENT SIGN */
+ { 0x0026, 0x26 }, /* AMPERSAND */
+ { 0x0027, 0x27 }, /* APOSTROPHE */
+ { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
+ { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
+ { 0x002A, 0x2A }, /* ASTERISK */
+ { 0x002B, 0x2B }, /* PLUS SIGN */
+ { 0x002C, 0x2C }, /* COMMA */
+ { 0x002D, 0x2D }, /* HYPHEN-MINUS */
+ { 0x002E, 0x2E }, /* FULL STOP */
+ { 0x002F, 0x2F }, /* SOLIDUS */
+ { 0x0030, 0x30 }, /* DIGIT ZERO */
+ { 0x0031, 0x31 }, /* DIGIT ONE */
+ { 0x0032, 0x32 }, /* DIGIT TWO */
+ { 0x0033, 0x33 }, /* DIGIT THREE */
+ { 0x0034, 0x34 }, /* DIGIT FOUR */
+ { 0x0035, 0x35 }, /* DIGIT FIVE */
+ { 0x0036, 0x36 }, /* DIGIT SIX */
+ { 0x0037, 0x37 }, /* DIGIT SEVEN */
+ { 0x0038, 0x38 }, /* DIGIT EIGHT */
+ { 0x0039, 0x39 }, /* DIGIT NINE */
+ { 0x003A, 0x3A }, /* COLON */
+ { 0x003B, 0x3B }, /* SEMICOLON */
+ { 0x003C, 0x3C }, /* LESS-THAN SIGN */
+ { 0x003D, 0x3D }, /* EQUALS SIGN */
+ { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
+ { 0x003F, 0x3F }, /* QUESTION MARK */
+ { 0x0040, 0x40 }, /* COMMERCIAL AT */
+ { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
+ { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
+ { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
+ { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
+ { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
+ { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
+ { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
+ { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
+ { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
+ { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
+ { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
+ { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
+ { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
+ { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
+ { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
+ { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
+ { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
+ { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
+ { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
+ { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
+ { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
+ { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
+ { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
+ { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
+ { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
+ { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
+ { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
+ { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
+ { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
+ { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
+ { 0x005F, 0x5F }, /* LOW LINE */
+ { 0x0060, 0x60 }, /* GRAVE ACCENT */
+ { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
+ { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
+ { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
+ { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
+ { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
+ { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
+ { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
+ { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
+ { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
+ { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
+ { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
+ { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
+ { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
+ { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
+ { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
+ { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
+ { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
+ { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
+ { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
+ { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
+ { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
+ { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
+ { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
+ { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
+ { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
+ { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
+ { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
+ { 0x007C, 0x7C }, /* VERTICAL LINE */
+ { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
+ { 0x007E, 0x7E }, /* TILDE */
+ { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
+ { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
+ { 0x00A2, 0xA2 }, /* CENT SIGN */
+ { 0x00A3, 0xA3 }, /* POUND SIGN */
+ { 0x00A5, 0xB4 }, /* YEN SIGN */
+ { 0x00A7, 0xA4 }, /* SECTION SIGN */
+ { 0x00A8, 0xAC }, /* DIAERESIS */
+ { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
+ { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
+ { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ { 0x00AC, 0xC2 }, /* NOT SIGN */
+ { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
+ { 0x00AF, 0xF8 }, /* MACRON */
+ { 0x00B0, 0xA1 }, /* DEGREE SIGN */
+ { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
+ { 0x00B4, 0xAB }, /* ACUTE ACCENT */
+ { 0x00B5, 0xB5 }, /* MICRO SIGN */
+ { 0x00B6, 0xA6 }, /* PILCROW SIGN */
+ { 0x00B7, 0xE1 }, /* MIDDLE DOT */
+ { 0x00B8, 0xFC }, /* CEDILLA */
+ { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
+ { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
+ { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
+ { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
+ { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
+ { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
+ { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
+ { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
+ { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
+ { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
+ { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
+ { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+ { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
+ { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
+ { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+ { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
+ { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
+ { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
+ { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
+ { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
+ { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
+ { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
+ { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
+ { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
+ { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
+ { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
+ { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
+ { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
+ { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
+ { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
+ { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
+ { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
+ { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
+ { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
+ { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
+ { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
+ { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
+ { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
+ { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
+ { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
+ { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
+ { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
+ { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
+ { 0x00F7, 0xD6 }, /* DIVISION SIGN */
+ { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
+ { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
+ { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
+ { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
+ { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
+ { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
+ { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
+ { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
+ { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
+ { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ { 0x02C7, 0xFF }, /* CARON */
+ { 0x02D8, 0xF9 }, /* BREVE */
+ { 0x02D9, 0xFA }, /* DOT ABOVE */
+ { 0x02DA, 0xFB }, /* RING ABOVE */
+ { 0x02DB, 0xFE }, /* OGONEK */
+ { 0x02DC, 0xF7 }, /* SMALL TILDE */
+ { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
+ { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
+ { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
+ { 0x2013, 0xD0 }, /* EN DASH */
+ { 0x2014, 0xD1 }, /* EM DASH */
+ { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
+ { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
+ { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
+ { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
+ { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
+ { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
+ { 0x2020, 0xA0 }, /* DAGGER */
+ { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
+ { 0x2022, 0xA5 }, /* BULLET */
+ { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
+ { 0x2030, 0xE4 }, /* PER MILLE SIGN */
+ { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ { 0x2044, 0xDA }, /* FRACTION SLASH */
+ { 0x20AC, 0xDB }, /* EURO SIGN */
+ { 0x2122, 0xAA }, /* TRADE MARK SIGN */
+ { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
+ { 0x2206, 0xC6 }, /* INCREMENT */
+ { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
+ { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
+ { 0x221A, 0xC3 }, /* SQUARE ROOT */
+ { 0x221E, 0xB0 }, /* INFINITY */
+ { 0x222B, 0xBA }, /* INTEGRAL */
+ { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
+ { 0x2260, 0xAD }, /* NOT EQUAL TO */
+ { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
+ { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
+ { 0x25CA, 0xD7 }, /* LOZENGE */
+ { 0xF8FF, 0xF0 }, /* Apple logo */
+ { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
+ { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
+};
+
+static const FcCharMap AppleRoman = {
+ AppleRomanEnt,
+ sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
+};
+
+static const FcCharEnt AdobeSymbolEnt[] = {
+ { 0x0020, 0x20 }, /* SPACE # space */
+ { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
+ { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
+ { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
+ { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
+ { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
+ { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
+ { 0x002B, 0x2B }, /* PLUS SIGN # plus */
+ { 0x002C, 0x2C }, /* COMMA # comma */
+ { 0x002E, 0x2E }, /* FULL STOP # period */
+ { 0x002F, 0x2F }, /* SOLIDUS # slash */
+ { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
+ { 0x0031, 0x31 }, /* DIGIT ONE # one */
+ { 0x0032, 0x32 }, /* DIGIT TWO # two */
+ { 0x0033, 0x33 }, /* DIGIT THREE # three */
+ { 0x0034, 0x34 }, /* DIGIT FOUR # four */
+ { 0x0035, 0x35 }, /* DIGIT FIVE # five */
+ { 0x0036, 0x36 }, /* DIGIT SIX # six */
+ { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
+ { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
+ { 0x0039, 0x39 }, /* DIGIT NINE # nine */
+ { 0x003A, 0x3A }, /* COLON # colon */
+ { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
+ { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
+ { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
+ { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
+ { 0x003F, 0x3F }, /* QUESTION MARK # question */
+ { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
+ { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
+ { 0x005F, 0x5F }, /* LOW LINE # underscore */
+ { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
+ { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
+ { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
+ { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
+ { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
+ { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
+ { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
+ { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
+ { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
+ { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
+ { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
+ { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
+ { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
+ { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
+ { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
+ { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
+ { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
+ { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
+ { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
+ { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
+ { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
+ { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
+ { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
+ { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
+ { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
+ { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
+ { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
+ { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
+ { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
+ { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
+ { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
+ { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
+ { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
+ { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
+ { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
+ { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
+ { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
+ { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
+ { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
+ { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
+ { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
+ { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
+ { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
+ { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
+ { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
+ { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
+ { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
+ { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
+ { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
+ { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
+ { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
+ { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
+ { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
+ { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
+ { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
+ { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
+ { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
+ { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
+ { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
+ { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
+ { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
+ { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
+ { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
+ { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
+ { 0x2022, 0xB7 }, /* BULLET # bullet */
+ { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
+ { 0x2032, 0xA2 }, /* PRIME # minute */
+ { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
+ { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
+ { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
+ { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
+ { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
+ { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
+ { 0x2126, 0x57 }, /* OHM SIGN # Omega */
+ { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
+ { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
+ { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
+ { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
+ { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
+ { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
+ { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
+ { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
+ { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
+ { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
+ { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
+ { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
+ { 0x2200, 0x22 }, /* FOR ALL # universal */
+ { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
+ { 0x2203, 0x24 }, /* THERE EXISTS # existential */
+ { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
+ { 0x2206, 0x44 }, /* INCREMENT # Delta */
+ { 0x2207, 0xD1 }, /* NABLA # gradient */
+ { 0x2208, 0xCE }, /* ELEMENT OF # element */
+ { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
+ { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
+ { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
+ { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
+ { 0x2212, 0x2D }, /* MINUS SIGN # minus */
+ { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
+ { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
+ { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
+ { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
+ { 0x221E, 0xA5 }, /* INFINITY # infinity */
+ { 0x2220, 0xD0 }, /* ANGLE # angle */
+ { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
+ { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
+ { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
+ { 0x222A, 0xC8 }, /* UNION # union */
+ { 0x222B, 0xF2 }, /* INTEGRAL # integral */
+ { 0x2234, 0x5C }, /* THEREFORE # therefore */
+ { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
+ { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
+ { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
+ { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
+ { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
+ { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
+ { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
+ { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
+ { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
+ { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
+ { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
+ { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
+ { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
+ { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
+ { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
+ { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
+ { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
+ { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
+ { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
+ { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
+ { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
+ { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
+ { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
+ { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
+ { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
+ { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
+ { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
+ { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
+ { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
+ { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
+ { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
+ { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
+ { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
+ { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
+ { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
+ { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
+ { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
+ { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
+ { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
+ { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
+ { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
+ { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
+ { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
+ { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
+ { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
+ { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
+ { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
+ { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
+ { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
+ { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
+ { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
+ { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
+ { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
+ { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
+};
+
+static const FcCharMap AdobeSymbol = {
+ AdobeSymbolEnt,
+ sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
+};
diff --git a/src/fcdbg.c b/src/fcdbg.c
new file mode 100644
index 0000000..78af630
--- /dev/null
+++ b/src/fcdbg.c
@@ -0,0 +1,272 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "fcint.h"
+
+void
+FcValuePrint (FcValue v)
+{
+ switch (v.type) {
+ case FcTypeVoid:
+ printf (" <void>");
+ break;
+ case FcTypeInteger:
+ printf (" %d", v.u.i);
+ break;
+ case FcTypeDouble:
+ printf (" %g", v.u.d);
+ break;
+ case FcTypeString:
+ printf (" \"%s\"", v.u.s);
+ break;
+ case FcTypeBool:
+ printf (" %s", v.u.b ? "FcTrue" : "FcFalse");
+ break;
+ case FcTypeMatrix:
+ printf (" (%f %f; %f %f)", v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
+ break;
+ case FcTypeCharSet: /* XXX */
+ printf (" set");
+ break;
+ }
+}
+
+void
+FcValueListPrint (FcValueList *l)
+{
+ for (; l; l = l->next)
+ FcValuePrint (l->value);
+}
+
+void
+FcPatternPrint (FcPattern *p)
+{
+ int i;
+ FcPatternElt *e;
+
+ if (!p)
+ {
+ printf ("Null pattern\n");
+ return;
+ }
+ printf ("Pattern %d of %d\n", p->num, p->size);
+ for (i = 0; i < p->num; i++)
+ {
+ e = &p->elts[i];
+ printf ("\t%s:", e->object);
+ FcValueListPrint (e->values);
+ printf ("\n");
+ }
+ printf ("\n");
+}
+
+void
+FcOpPrint (FcOp op)
+{
+ switch (op) {
+ case FcOpInteger: printf ("Integer"); break;
+ case FcOpDouble: printf ("Double"); break;
+ case FcOpString: printf ("String"); break;
+ case FcOpMatrix: printf ("Matrix"); break;
+ case FcOpBool: printf ("Bool"); break;
+ case FcOpCharSet: printf ("CharSet"); break;
+ case FcOpField: printf ("Field"); break;
+ case FcOpConst: printf ("Const"); break;
+ case FcOpAssign: printf ("Assign"); break;
+ case FcOpAssignReplace: printf ("AssignReplace"); break;
+ case FcOpPrepend: printf ("Prepend"); break;
+ case FcOpPrependFirst: printf ("PrependFirst"); break;
+ case FcOpAppend: printf ("Append"); break;
+ case FcOpAppendLast: printf ("AppendLast"); break;
+ case FcOpQuest: printf ("Quest"); break;
+ case FcOpOr: printf ("Or"); break;
+ case FcOpAnd: printf ("And"); break;
+ case FcOpEqual: printf ("Equal"); break;
+ case FcOpContains: printf ("Contains"); break;
+ case FcOpNotEqual: printf ("NotEqual"); break;
+ case FcOpLess: printf ("Less"); break;
+ case FcOpLessEqual: printf ("LessEqual"); break;
+ case FcOpMore: printf ("More"); break;
+ case FcOpMoreEqual: printf ("MoreEqual"); break;
+ case FcOpPlus: printf ("Plus"); break;
+ case FcOpMinus: printf ("Minus"); break;
+ case FcOpTimes: printf ("Times"); break;
+ case FcOpDivide: printf ("Divide"); break;
+ case FcOpNot: printf ("Not"); break;
+ case FcOpNil: printf ("Nil"); break;
+ case FcOpComma: printf ("Comma"); break;
+ case FcOpInvalid: printf ("Invalid"); break;
+ }
+}
+
+void
+FcExprPrint (FcExpr *expr)
+{
+ switch (expr->op) {
+ case FcOpInteger: printf ("%d", expr->u.ival); break;
+ case FcOpDouble: printf ("%g", expr->u.dval); break;
+ case FcOpString: printf ("\"%s\"", expr->u.sval); break;
+ case FcOpMatrix: printf ("[%g %g %g %g]",
+ expr->u.mval->xx,
+ expr->u.mval->xy,
+ expr->u.mval->yx,
+ expr->u.mval->yy);
+ case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break;
+ case FcOpField: printf ("%s", expr->u.field); break;
+ case FcOpQuest:
+ FcExprPrint (expr->u.tree.left);
+ printf (" quest ");
+ FcExprPrint (expr->u.tree.right->u.tree.left);
+ printf (" colon ");
+ FcExprPrint (expr->u.tree.right->u.tree.right);
+ break;
+ case FcOpOr:
+ case FcOpAnd:
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpNotEqual:
+ case FcOpLess:
+ case FcOpLessEqual:
+ case FcOpMore:
+ case FcOpMoreEqual:
+ case FcOpPlus:
+ case FcOpMinus:
+ case FcOpTimes:
+ case FcOpDivide:
+ FcExprPrint (expr->u.tree.left);
+ printf (" ");
+ switch (expr->op) {
+ case FcOpOr: printf ("Or"); break;
+ case FcOpAnd: printf ("And"); break;
+ case FcOpEqual: printf ("Equal"); break;
+ case FcOpContains: printf ("Contains"); break;
+ case FcOpNotEqual: printf ("NotEqual"); break;
+ case FcOpLess: printf ("Less"); break;
+ case FcOpLessEqual: printf ("LessEqual"); break;
+ case FcOpMore: printf ("More"); break;
+ case FcOpMoreEqual: printf ("MoreEqual"); break;
+ case FcOpPlus: printf ("Plus"); break;
+ case FcOpMinus: printf ("Minus"); break;
+ case FcOpTimes: printf ("Times"); break;
+ case FcOpDivide: printf ("Divide"); break;
+ default: break;
+ }
+ printf (" ");
+ FcExprPrint (expr->u.tree.right);
+ break;
+ case FcOpNot:
+ printf ("Not ");
+ FcExprPrint (expr->u.tree.left);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+FcTestPrint (FcTest *test)
+{
+ switch (test->qual) {
+ case FcQualAny:
+ printf ("any ");
+ break;
+ case FcQualAll:
+ printf ("all ");
+ break;
+ }
+ printf ("%s ", test->field);
+ FcOpPrint (test->op);
+ printf (" ");
+ FcExprPrint (test->expr);
+ printf ("\n");
+}
+
+void
+FcEditPrint (FcEdit *edit)
+{
+ printf ("Edit %s ", edit->field);
+ FcOpPrint (edit->op);
+ printf (" ");
+ FcExprPrint (edit->expr);
+}
+
+void
+FcSubstPrint (FcSubst *subst)
+{
+ FcEdit *e;
+ FcTest *t;
+
+ printf ("match\n");
+ for (t = subst->test; t; t = t->next)
+ {
+ printf ("\t");
+ FcTestPrint (t);
+ }
+ printf ("edit\n");
+ for (e = subst->edit; e; e = e->next)
+ {
+ printf ("\t");
+ FcEditPrint (e);
+ printf (";\n");
+ }
+ printf ("\n");
+}
+
+void
+FcFontSetPrint (FcFontSet *s)
+{
+ int i;
+
+ printf ("FontSet %d of %d\n", s->nfont, s->sfont);
+ for (i = 0; i < s->nfont; i++)
+ {
+ printf ("Font %d ", i);
+ FcPatternPrint (s->fonts[i]);
+ }
+}
+
+int
+FcDebug (void)
+{
+ static int initialized;
+ static int debug;
+
+ if (!initialized)
+ {
+ char *e;
+
+ initialized = 1;
+ e = getenv ("FC_DEBUG");
+ if (e)
+ {
+ printf ("FC_DEBUG=%s\n", e);
+ debug = atoi (e);
+ if (debug < 0)
+ debug = 0;
+ }
+ }
+ return debug;
+}
diff --git a/src/fcdefault.c b/src/fcdefault.c
new file mode 100644
index 0000000..365595d
--- /dev/null
+++ b/src/fcdefault.c
@@ -0,0 +1,87 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+
+static struct {
+ char *field;
+ FcBool value;
+} FcBoolDefaults[] = {
+ { FC_HINTING, FcTrue }, /* !FT_LOAD_NO_HINTING */
+ { FC_VERTICAL_LAYOUT, FcFalse }, /* FC_LOAD_VERTICAL_LAYOUT */
+ { FC_AUTOHINT, FcFalse }, /* FC_LOAD_FORCE_AUTOHINT */
+ { FC_GLOBAL_ADVANCE, FcTrue }, /* !FC_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
+};
+
+#define NUM_FC_BOOL_DEFAULTS (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
+
+void
+FcDefaultSubstitute (FcPattern *pattern)
+{
+ FcValue v;
+ int i;
+
+ if (FcPatternGet (pattern, FC_STYLE, 0, &v) == FcResultNoMatch)
+ {
+ if (FcPatternGet (pattern, FC_WEIGHT, 0, &v) == FcResultNoMatch )
+ {
+ FcPatternAddInteger (pattern, FC_WEIGHT, FC_WEIGHT_MEDIUM);
+ }
+ if (FcPatternGet (pattern, FC_SLANT, 0, &v) == FcResultNoMatch)
+ {
+ FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN);
+ }
+ }
+
+ for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
+ if (FcPatternGet (pattern, FcBoolDefaults[i].field, 0, &v) == FcResultNoMatch)
+ FcPatternAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
+
+ if (FcPatternGet (pattern, FC_PIXEL_SIZE, 0, &v) == FcResultNoMatch)
+ {
+ double dpi, size, scale;
+
+ if (FcPatternGetDouble (pattern, FC_SIZE, 0, &size) != FcResultMatch)
+ {
+ size = 12.0;
+ (void) FcPatternDel (pattern, FC_SIZE);
+ FcPatternAddDouble (pattern, FC_SIZE, size);
+ }
+ if (FcPatternGetDouble (pattern, FC_SCALE, 0, &scale) != FcResultMatch)
+ {
+ scale = 1.0;
+ (void) FcPatternDel (pattern, FC_SCALE);
+ FcPatternAddDouble (pattern, FC_SCALE, scale);
+ }
+ size *= scale;
+ if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) != FcResultMatch)
+ {
+ dpi = 75.0;
+ (void) FcPatternDel (pattern, FC_DPI);
+ FcPatternAddDouble (pattern, FC_DPI, dpi);
+ }
+ size *= dpi / 72.0;
+ FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
+ }
+}
diff --git a/src/fcdir.c b/src/fcdir.c
new file mode 100644
index 0000000..a49cb54
--- /dev/null
+++ b/src/fcdir.c
@@ -0,0 +1,178 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fcint.h"
+
+#define FC_INVALID_FONT_FILE "."
+
+FcBool
+FcFileScan (FcFontSet *set,
+ FcFileCache *cache,
+ FcBlanks *blanks,
+ const char *file,
+ FcBool force)
+{
+ int id;
+ char *name;
+ FcPattern *font;
+ FcBool ret = FcTrue;
+ int count;
+
+ id = 0;
+ do
+ {
+ if (!force && cache)
+ name = FcFileCacheFind (cache, file, id, &count);
+ else
+ name = 0;
+ if (name)
+ {
+ /* "." means the file doesn't contain a font */
+ if (strcmp (name, FC_INVALID_FONT_FILE) != 0)
+ {
+ font = FcNameParse (name);
+ if (font)
+ FcPatternAddString (font, FC_FILE, file);
+ }
+ else
+ font = 0;
+ }
+ else
+ {
+ if (FcDebug () & FC_DBG_SCAN)
+ {
+ printf ("\tScanning file %s...", file);
+ fflush (stdout);
+ }
+ font = FcFreeTypeQuery (file, id, blanks, &count);
+ if (FcDebug () & FC_DBG_SCAN)
+ printf ("done\n");
+ if (!force && cache)
+ {
+ if (font)
+ {
+ FcChar8 *unparse;
+
+ unparse = FcNameUnparse (font);
+ if (unparse)
+ {
+ (void) FcFileCacheUpdate (cache, file, id, unparse);
+ free (unparse);
+ }
+ }
+ else
+ {
+ /* negative cache files not containing fonts */
+ FcFileCacheUpdate (cache, file, id, FC_INVALID_FONT_FILE);
+ }
+ }
+ }
+ if (font)
+ {
+ if (!FcFontSetAdd (set, font))
+ {
+ FcPatternDestroy (font);
+ font = 0;
+ ret = FcFalse;
+ }
+ }
+ id++;
+ } while (font && ret && id < count);
+ return ret;
+}
+
+FcBool
+FcDirScan (FcFontSet *set,
+ FcFileCache *cache,
+ FcBlanks *blanks,
+ const char *dir,
+ FcBool force)
+{
+ DIR *d;
+ struct dirent *e;
+ char *file;
+ char *base;
+ FcBool ret = FcTrue;
+
+ file = (char *) malloc (strlen (dir) + 1 + 256 + 1);
+ if (!file)
+ return FcFalse;
+
+ strcpy (file, dir);
+ strcat (file, "/");
+ base = file + strlen (file);
+ if (!force)
+ {
+ strcpy (base, FC_DIR_CACHE_FILE);
+
+ if (FcFileCacheReadDir (set, file))
+ {
+ free (file);
+ return FcTrue;
+ }
+ }
+
+ d = opendir (dir);
+ if (!d)
+ {
+ free (file);
+ return FcFalse;
+ }
+ while (ret && (e = readdir (d)))
+ {
+ if (e->d_name[0] != '.')
+ {
+ strcpy (base, e->d_name);
+ FcFileScan (set, cache, blanks, file, force);
+ }
+ }
+ free (file);
+ closedir (d);
+ return ret;
+}
+
+FcBool
+FcDirSave (FcFontSet *set, const char *dir)
+{
+ char *file;
+ char *base;
+ FcBool ret;
+
+ file = (char *) malloc (strlen (dir) + 1 + 256 + 1);
+ if (!file)
+ return FcFalse;
+
+ strcpy (file, dir);
+ strcat (file, "/");
+ base = file + strlen (file);
+ strcpy (base, FC_DIR_CACHE_FILE);
+ ret = FcFileCacheWriteDir (set, file);
+ free (file);
+ return ret;
+}
+
diff --git a/src/fcfreetype.c b/src/fcfreetype.c
new file mode 100644
index 0000000..788b85a
--- /dev/null
+++ b/src/fcfreetype.c
@@ -0,0 +1,236 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "fcint.h"
+#include <freetype/freetype.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/tttables.h>
+#include <fontconfig/fcfreetype.h>
+
+static const struct {
+ int bit;
+ char *name;
+} FcCodePageRange[] = {
+ { 0, FC_LANG_LATIN_1 },
+ { 1, FC_LANG_LATIN_2_EASTERN_EUROPE },
+ { 2, FC_LANG_CYRILLIC },
+ { 3, FC_LANG_GREEK },
+ { 4, FC_LANG_TURKISH },
+ { 5, FC_LANG_HEBREW },
+ { 6, FC_LANG_ARABIC },
+ { 7, FC_LANG_WINDOWS_BALTIC },
+ { 8, FC_LANG_VIETNAMESE },
+/* 9-15 reserved for Alternate ANSI */
+ { 16, FC_LANG_THAI },
+ { 17, FC_LANG_JAPANESE },
+ { 18, FC_LANG_SIMPLIFIED_CHINESE },
+ { 19, FC_LANG_KOREAN_WANSUNG },
+ { 20, FC_LANG_TRADITIONAL_CHINESE },
+ { 21, FC_LANG_KOREAN_JOHAB },
+/* 22-28 reserved for Alternate ANSI & OEM */
+ { 29, FC_LANG_MACINTOSH },
+ { 30, FC_LANG_OEM },
+ { 31, FC_LANG_SYMBOL },
+/* 32-47 reserved for OEM */
+ { 48, FC_LANG_IBM_GREEK },
+ { 49, FC_LANG_MSDOS_RUSSIAN },
+ { 50, FC_LANG_MSDOS_NORDIC },
+ { 51, FC_LANG_ARABIC_864 },
+ { 52, FC_LANG_MSDOS_CANADIAN_FRENCH },
+ { 53, FC_LANG_HEBREW_862 },
+ { 54, FC_LANG_MSDOS_ICELANDIC },
+ { 55, FC_LANG_MSDOS_PORTUGUESE },
+ { 56, FC_LANG_IBM_TURKISH },
+ { 57, FC_LANG_IBM_CYRILLIC },
+ { 58, FC_LANG_LATIN_2 },
+ { 59, FC_LANG_MSDOS_BALTIC },
+ { 60, FC_LANG_GREEK_437_G },
+ { 61, FC_LANG_ARABIC_ASMO_708 },
+ { 62, FC_LANG_WE_LATIN_1 },
+ { 63, FC_LANG_US },
+};
+
+#define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
+
+FcPattern *
+FcFreeTypeQuery (const char *file,
+ int id,
+ FcBlanks *blanks,
+ int *count)
+{
+ FT_Face face;
+ FcPattern *pat;
+ int slant;
+ int weight;
+ int i;
+ FcCharSet *cs;
+ FT_Library ftLibrary;
+ const char *family;
+ TT_OS2 *os2;
+
+ if (FT_Init_FreeType (&ftLibrary))
+ return 0;
+
+ if (FT_New_Face (ftLibrary, file, id, &face))
+ goto bail;
+
+ *count = face->num_faces;
+
+ pat = FcPatternCreate ();
+ if (!pat)
+ goto bail0;
+
+ if (!FcPatternAddBool (pat, FC_OUTLINE,
+ (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
+ goto bail1;
+
+ if (!FcPatternAddBool (pat, FC_SCALABLE,
+ (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
+ goto bail1;
+
+
+ slant = FC_SLANT_ROMAN;
+ if (face->style_flags & FT_STYLE_FLAG_ITALIC)
+ slant = FC_SLANT_ITALIC;
+
+ if (!FcPatternAddInteger (pat, FC_SLANT, slant))
+ goto bail1;
+
+ weight = FC_WEIGHT_MEDIUM;
+ if (face->style_flags & FT_STYLE_FLAG_BOLD)
+ weight = FC_WEIGHT_BOLD;
+
+ if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
+ goto bail1;
+
+ family = face->family_name;
+ if (!family)
+ {
+ family = strrchr (file, '/');
+ if (family)
+ family++;
+ else
+ family = file;
+ }
+ if (!FcPatternAddString (pat, FC_FAMILY, family))
+ goto bail1;
+
+ if (face->style_name)
+ {
+ if (!FcPatternAddString (pat, FC_STYLE, face->style_name))
+ goto bail1;
+ }
+
+ if (!FcPatternAddString (pat, FC_FILE, file))
+ goto bail1;
+
+ if (!FcPatternAddInteger (pat, FC_INDEX, id))
+ goto bail1;
+
+ if (!FcPatternAddString (pat, FC_SOURCE, "FreeType"))
+ goto bail1;
+
+#if 0
+ if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
+ if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
+ goto bail1;
+#endif
+
+ cs = FcFreeTypeCharSet (face, blanks);
+ if (!cs)
+ goto bail1;
+
+ /*
+ * Skip over PCF fonts that have no encoded characters; they're
+ * usually just Unicode fonts transcoded to some legacy encoding
+ */
+ if (FcCharSetCount (cs) == 0)
+ {
+ if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
+ goto bail2;
+ }
+
+ if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
+ goto bail2;
+ /*
+ * Drop our reference to the charset
+ */
+ FcCharSetDestroy (cs);
+
+ if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
+ {
+ for (i = 0; i < face->num_fixed_sizes; i++)
+ if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
+ (double) face->available_sizes[i].height))
+ goto bail1;
+ if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
+ goto bail1;
+ }
+
+ /*
+ * Get the OS/2 table and poke about
+ */
+ os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
+ if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
+ {
+ for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
+ {
+ FT_ULong bits;
+ int bit;
+ if (FcCodePageRange[i].bit < 32)
+ {
+ bits = os2->ulCodePageRange1;
+ bit = FcCodePageRange[i].bit;
+ }
+ else
+ {
+ bits = os2->ulCodePageRange2;
+ bit = FcCodePageRange[i].bit - 32;
+ }
+ if (bits & (1 << bit))
+ {
+ if (!FcPatternAddString (pat, FC_LANG,
+ FcCodePageRange[i].name))
+ goto bail1;
+ }
+ }
+ }
+
+ FT_Done_Face (face);
+ FT_Done_FreeType (ftLibrary);
+ return pat;
+
+bail2:
+ FcCharSetDestroy (cs);
+bail1:
+ FcPatternDestroy (pat);
+bail0:
+ FT_Done_Face (face);
+bail:
+ FT_Done_FreeType (ftLibrary);
+ return 0;
+}
diff --git a/src/fcfs.c b/src/fcfs.c
new file mode 100644
index 0000000..afc071f
--- /dev/null
+++ b/src/fcfs.c
@@ -0,0 +1,82 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+FcFontSet *
+FcFontSetCreate (void)
+{
+ FcFontSet *s;
+
+ s = (FcFontSet *) malloc (sizeof (FcFontSet));
+ if (!s)
+ return 0;
+ FcMemAlloc (FC_MEM_FONTSET, sizeof (FcFontSet));
+ s->nfont = 0;
+ s->sfont = 0;
+ s->fonts = 0;
+ return s;
+}
+
+void
+FcFontSetDestroy (FcFontSet *s)
+{
+ int i;
+
+ for (i = 0; i < s->nfont; i++)
+ FcPatternDestroy (s->fonts[i]);
+ if (s->fonts)
+ {
+ FcMemFree (FC_MEM_FONTPTR, s->sfont * sizeof (FcPattern *));
+ free (s->fonts);
+ }
+ FcMemFree (FC_MEM_FONTSET, sizeof (FcFontSet));
+ free (s);
+}
+
+FcBool
+FcFontSetAdd (FcFontSet *s, FcPattern *font)
+{
+ FcPattern **f;
+ int sfont;
+
+ if (s->nfont == s->sfont)
+ {
+ sfont = s->sfont + 32;
+ if (s->fonts)
+ f = (FcPattern **) realloc (s->fonts, sfont * sizeof (FcPattern *));
+ else
+ f = (FcPattern **) malloc (sfont * sizeof (FcPattern *));
+ if (!f)
+ return FcFalse;
+ if (s->sfont)
+ FcMemFree (FC_MEM_FONTPTR, s->sfont * sizeof (FcPattern *));
+ FcMemAlloc (FC_MEM_FONTPTR, sfont * sizeof (FcPattern *));
+ s->sfont = sfont;
+ s->fonts = f;
+ }
+ s->fonts[s->nfont++] = font;
+ return FcTrue;
+}
diff --git a/src/fcinit.c b/src/fcinit.c
new file mode 100644
index 0000000..f82e018
--- /dev/null
+++ b/src/fcinit.c
@@ -0,0 +1,174 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+FcBool
+FcInitFonts (void)
+{
+ FcConfig *config;
+
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+
+ if (FcConfigGetFonts (config, FcSetSystem))
+ return FcTrue;
+
+ return FcConfigBuildFonts (config);
+}
+
+static FcBool
+FcInitFallbackConfig (void)
+{
+ FcConfig *config;
+
+ config = FcConfigCreate ();
+ if (!config)
+ goto bail0;
+ if (!FcConfigAddDir (config, FC_FALLBACK_FONTS))
+ goto bail1;
+ FcConfigSetCurrent (config);
+ return FcTrue;
+
+bail1:
+ FcConfigDestroy (config);
+bail0:
+ return FcFalse;
+}
+
+/*
+ * Locate and parse the configuration file
+ */
+FcBool
+FcInitConfig (void)
+{
+ FcConfig *config;
+
+ if (FcConfigGetCurrent ())
+ return FcTrue;
+
+ config = FcConfigCreate ();
+ if (!config)
+ return FcFalse;
+
+ if (!FcConfigParseAndLoad (config, 0, FcTrue))
+ {
+ FcConfigDestroy (config);
+ return FcInitFallbackConfig ();
+ }
+
+ FcConfigSetCurrent (config);
+ return FcTrue;
+}
+
+FcBool
+FcInit (void)
+{
+ return FcInitConfig () && FcInitFonts ();
+}
+
+static struct {
+ char *name;
+ int alloc_count;
+ int alloc_mem;
+ int free_count;
+ int free_mem;
+} FcInUse[FC_MEM_NUM] = {
+ { "charset", 0, 0 },
+ { "charnode", 0 ,0 },
+ { "fontset", 0, 0 },
+ { "fontptr", 0, 0 },
+ { "objectset", 0, 0 },
+ { "objectptr", 0, 0 },
+ { "matrix", 0, 0 },
+ { "pattern", 0, 0 },
+ { "patelt", 0, 0 },
+ { "vallist", 0, 0 },
+ { "substate", 0, 0 },
+ { "string", 0, 0 },
+ { "listbuck", 0, 0 },
+};
+
+static int FcAllocCount, FcAllocMem;
+static int FcFreeCount, FcFreeMem;
+
+static int FcMemNotice = 1*1024*1024;
+
+static int FcAllocNotify, FcFreeNotify;
+
+void
+FcMemReport (void)
+{
+ int i;
+ printf ("Fc Memory Usage:\n");
+ printf ("\t Which Alloc Free Active\n");
+ printf ("\t count bytes count bytes count bytes\n");
+ for (i = 0; i < FC_MEM_NUM; i++)
+ printf ("\t%8.8s%8d%8d%8d%8d%8d%8d\n",
+ FcInUse[i].name,
+ FcInUse[i].alloc_count, FcInUse[i].alloc_mem,
+ FcInUse[i].free_count, FcInUse[i].free_mem,
+ FcInUse[i].alloc_count - FcInUse[i].free_count,
+ FcInUse[i].alloc_mem - FcInUse[i].free_mem);
+ printf ("\t%8.8s%8d%8d%8d%8d%8d%8d\n",
+ "Total",
+ FcAllocCount, FcAllocMem,
+ FcFreeCount, FcFreeMem,
+ FcAllocCount - FcFreeCount,
+ FcAllocMem - FcFreeMem);
+ FcAllocNotify = 0;
+ FcFreeNotify = 0;
+}
+
+void
+FcMemAlloc (int kind, int size)
+{
+ if (FcDebug() & FC_DBG_MEMORY)
+ {
+ FcInUse[kind].alloc_count++;
+ FcInUse[kind].alloc_mem += size;
+ FcAllocCount++;
+ FcAllocMem += size;
+ FcAllocNotify += size;
+ if (FcAllocNotify > FcMemNotice)
+ FcMemReport ();
+ }
+}
+
+void
+FcMemFree (int kind, int size)
+{
+ if (FcDebug() & FC_DBG_MEMORY)
+ {
+ FcInUse[kind].free_count++;
+ FcInUse[kind].free_mem += size;
+ FcFreeCount++;
+ FcFreeMem += size;
+ FcFreeNotify += size;
+ if (FcFreeNotify > FcMemNotice)
+ FcMemReport ();
+ }
+}
diff --git a/src/fcint.h b/src/fcint.h
new file mode 100644
index 0000000..139df3b
--- /dev/null
+++ b/src/fcint.h
@@ -0,0 +1,480 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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.
+ */
+
+#ifndef _FCINT_H_
+#define _FCINT_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libxml/parserInternals.h>
+#include <fontconfig/fontconfig.h>
+#include <fontconfig/fcprivate.h>
+#include <fontconfig/fcxml.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef struct _FcMatcher {
+ char *object;
+ double (*compare) (char *object, FcValue value1, FcValue value2);
+} FcMatcher;
+
+typedef struct _FcSymbolic {
+ const char *name;
+ int value;
+} FcSymbolic;
+
+#ifndef FC_CONFIG_PATH
+#define FC_CONFIG_PATH "fonts.conf"
+#endif
+
+#define FC_DBG_MATCH 1
+#define FC_DBG_MATCHV 2
+#define FC_DBG_EDIT 4
+#define FC_DBG_FONTSET 8
+#define FC_DBG_CACHE 16
+#define FC_DBG_CACHEV 32
+#define FC_DBG_PARSE 64
+#define FC_DBG_SCAN 128
+#define FC_DBG_MEMORY 512
+
+#define FC_MEM_CHARSET 0
+#define FC_MEM_CHARNODE 1
+#define FC_MEM_FONTSET 2
+#define FC_MEM_FONTPTR 3
+#define FC_MEM_OBJECTSET 4
+#define FC_MEM_OBJECTPTR 5
+#define FC_MEM_MATRIX 6
+#define FC_MEM_PATTERN 7
+#define FC_MEM_PATELT 8
+#define FC_MEM_VALLIST 9
+#define FC_MEM_SUBSTATE 10
+#define FC_MEM_STRING 11
+#define FC_MEM_LISTBUCK 12
+#define FC_MEM_NUM 13
+
+typedef struct _FcValueList {
+ struct _FcValueList *next;
+ FcValue value;
+} FcValueList;
+
+typedef struct _FcPatternElt {
+ const char *object;
+ FcValueList *values;
+} FcPatternElt;
+
+struct _FcPattern {
+ int num;
+ int size;
+ FcPatternElt *elts;
+};
+
+typedef enum _FcOp {
+ FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpBool, FcOpCharSet,
+ FcOpNil,
+ FcOpField, FcOpConst,
+ FcOpAssign, FcOpAssignReplace,
+ FcOpPrependFirst, FcOpPrepend, FcOpAppend, FcOpAppendLast,
+ FcOpQuest,
+ FcOpOr, FcOpAnd, FcOpEqual, FcOpNotEqual, FcOpContains,
+ FcOpLess, FcOpLessEqual, FcOpMore, FcOpMoreEqual,
+ FcOpPlus, FcOpMinus, FcOpTimes, FcOpDivide,
+ FcOpNot, FcOpComma, FcOpInvalid
+} FcOp;
+
+typedef struct _FcExpr {
+ FcOp op;
+ union {
+ int ival;
+ double dval;
+ char *sval;
+ FcMatrix *mval;
+ FcBool bval;
+ FcCharSet *cval;
+ char *field;
+ char *constant;
+ struct {
+ struct _FcExpr *left, *right;
+ } tree;
+ } u;
+} FcExpr;
+
+typedef enum _FcQual {
+ FcQualAny, FcQualAll
+} FcQual;
+
+typedef struct _FcTest {
+ struct _FcTest *next;
+ FcQual qual;
+ const char *field;
+ FcOp op;
+ FcExpr *expr;
+} FcTest;
+
+typedef struct _FcEdit {
+ struct _FcEdit *next;
+ const char *field;
+ FcOp op;
+ FcExpr *expr;
+} FcEdit;
+
+typedef struct _FcSubst {
+ struct _FcSubst *next;
+ FcTest *test;
+ FcEdit *edit;
+} FcSubst;
+
+typedef struct _FcCharLeaf FcCharLeaf;
+typedef struct _FcCharBranch FcCharBranch;
+typedef union _FcCharNode FcCharNode;
+
+struct _FcCharLeaf {
+ FcChar32 map[256/32];
+};
+
+union _FcCharNode {
+ FcCharBranch *branch;
+ FcCharLeaf *leaf;
+};
+
+struct _FcCharBranch {
+ FcCharNode nodes[256];
+};
+
+struct _FcCharSet {
+ int levels;
+ int ref; /* reference count */
+ FcBool constant; /* shared constant */
+ FcCharNode node;
+};
+
+typedef struct _FcNameBuf {
+ FcChar8 *buf;
+ FcBool allocated;
+ FcBool failed;
+ int len;
+ int size;
+} FcNameBuf;
+
+typedef struct _FcFileCacheEnt {
+ struct _FcFileCacheEnt *next;
+ unsigned int hash;
+ char *file;
+ int id;
+ time_t time;
+ char *name;
+ FcBool referenced;
+} FcFileCacheEnt;
+
+#define FC_FILE_CACHE_HASH_SIZE 509
+
+struct _FcFileCache {
+ FcFileCacheEnt *ents[FC_FILE_CACHE_HASH_SIZE];
+ FcBool updated;
+ int entries;
+ int referenced;
+};
+
+struct _FcBlanks {
+ int nblank;
+ int sblank;
+ FcChar32 *blanks;
+};
+
+struct _FcConfig {
+ /*
+ * File names loaded from the configuration -- saved here as the
+ * cache file must be consulted before the directories are scanned,
+ * and those directives may occur in any order
+ */
+ char **dirs; /* directories containing fonts */
+ char *cache; /* name of per-user cache file */
+ /*
+ * Set of allowed blank chars -- used to
+ * trim fonts of bogus glyphs
+ */
+ FcBlanks *blanks;
+ /*
+ * Names of all of the configuration files used
+ * to create this configuration
+ */
+ char **configFiles; /* config files loaded */
+ /*
+ * Substitution instructions for patterns and fonts;
+ * maxObjects is used to allocate appropriate intermediate storage
+ * while performing a whole set of substitutions
+ */
+ FcSubst *substPattern; /* substitutions for patterns */
+ FcSubst *substFont; /* substitutions for fonts */
+ int maxObjects; /* maximum number of tests in all substs */
+ /*
+ * The set of fonts loaded from the listed directories; the
+ * order within the set does not determine the font selection,
+ * except in the case of identical matches in which case earlier fonts
+ * match preferrentially
+ */
+ FcFontSet *fonts[FcSetApplication + 1];
+};
+
+/* fcblanks.c */
+
+/* fccache.c */
+
+FcFileCache *
+FcFileCacheCreate (void);
+
+char *
+FcFileCacheFind (FcFileCache *cache,
+ const char *file,
+ int id,
+ int *count);
+
+void
+FcFileCacheDestroy (FcFileCache *cache);
+
+void
+FcFileCacheLoad (FcFileCache *cache,
+ const char *cache_file);
+
+FcBool
+FcFileCacheUpdate (FcFileCache *cache,
+ const char *file,
+ int id,
+ const char *name);
+
+FcBool
+FcFileCacheSave (FcFileCache *cache,
+ const char *cache_file);
+
+FcBool
+FcFileCacheReadDir (FcFontSet *set, const char *cache_file);
+
+FcBool
+FcFileCacheWriteDir (FcFontSet *set, const char *cache_file);
+
+/* fccfg.c */
+
+FcBool
+FcConfigAddDir (FcConfig *config,
+ const char *d);
+
+FcBool
+FcConfigAddConfigFile (FcConfig *config,
+ const char *f);
+
+FcBool
+FcConfigSetCache (FcConfig *config,
+ const char *c);
+
+FcBool
+FcConfigAddBlank (FcConfig *config,
+ FcChar32 blank);
+
+FcBool
+FcConfigAddEdit (FcConfig *config,
+ FcTest *test,
+ FcEdit *edit,
+ FcMatchKind kind);
+
+void
+FcConfigSetFonts (FcConfig *config,
+ FcFontSet *fonts,
+ FcSetName set);
+
+FcBool
+FcConfigCompareValue (const FcValue m,
+ FcOp op,
+ const FcValue v);
+
+/* fccharset.c */
+FcBool
+FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c);
+
+FcCharSet *
+FcNameParseCharSet (FcChar8 *string);
+
+/* fcdbg.c */
+void
+FcValuePrint (FcValue v);
+
+void
+FcValueListPrint (FcValueList *l);
+
+void
+FcPatternPrint (FcPattern *p);
+
+void
+FcOpPrint (FcOp op);
+
+void
+FcTestPrint (FcTest *test);
+
+void
+FcExprPrint (FcExpr *expr);
+
+void
+FcEditPrint (FcEdit *edit);
+
+void
+FcSubstPrint (FcSubst *subst);
+
+void
+FcFontSetPrint (FcFontSet *s);
+
+int
+FcDebug (void);
+
+/* fcdir.c */
+FcBool
+FcFileScan (FcFontSet *set,
+ FcFileCache *cache,
+ FcBlanks *blanks,
+ const char *file,
+ FcBool force);
+
+FcBool
+FcDirScan (FcFontSet *set,
+ FcFileCache *cache,
+ FcBlanks *blanks,
+ const char *dir,
+ FcBool force);
+
+FcBool
+FcDirSave (FcFontSet *set, const char *dir);
+
+/* fcfont.c */
+int
+FcFontDebug (void);
+
+/* fcfs.c */
+/* fcgram.y */
+int
+FcConfigparse (void);
+
+int
+FcConfigwrap (void);
+
+void
+FcConfigerror (char *fmt, ...);
+
+char *
+FcConfigSaveField (const char *field);
+
+FcTest *
+FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr);
+
+void
+FcTestDestroy (FcTest *test);
+
+FcExpr *
+FcExprCreateInteger (int i);
+
+FcExpr *
+FcExprCreateDouble (double d);
+
+FcExpr *
+FcExprCreateString (const char *s);
+
+FcExpr *
+FcExprCreateMatrix (const FcMatrix *m);
+
+FcExpr *
+FcExprCreateBool (FcBool b);
+
+FcExpr *
+FcExprCreateNil (void);
+
+FcExpr *
+FcExprCreateField (const char *field);
+
+FcExpr *
+FcExprCreateConst (const char *constant);
+
+FcExpr *
+FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right);
+
+void
+FcExprDestroy (FcExpr *e);
+
+FcEdit *
+FcEditCreate (const char *field, FcOp op, FcExpr *expr);
+
+void
+FcEditDestroy (FcEdit *e);
+
+/* fcinit.c */
+
+void
+FcMemReport (void);
+
+void
+FcMemAlloc (int kind, int size);
+
+void
+FcMemFree (int kind, int size);
+
+/* fclist.c */
+
+/* fcmatch.c */
+
+/* fcname.c */
+FcBool
+FcNameConstant (char *string, int *result);
+
+FcBool
+FcNameBool (char *v, FcBool *result);
+
+FcBool
+FcNameBufChar (FcNameBuf *buf, FcChar8 c);
+
+FcBool
+FcNameBufString (FcNameBuf *buf, const FcChar8 *s);
+
+/* fcpat.c */
+void
+FcValueListDestroy (FcValueList *l);
+
+FcPatternElt *
+FcPatternFind (FcPattern *p, const char *object, FcBool insert);
+
+/* fcrender.c */
+
+/* fcmatrix.c */
+void
+FcMatrixFree (FcMatrix *mat);
+
+/* fcstr.c */
+char *
+FcStrPlus (const char *s1, const char *s2);
+
+void
+FcStrFree (char *s);
+
+#endif /* _FC_INT_H_ */
diff --git a/src/fclist.c b/src/fclist.c
new file mode 100644
index 0000000..4cbfed2
--- /dev/null
+++ b/src/fclist.c
@@ -0,0 +1,442 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+FcObjectSet *
+FcObjectSetCreate (void)
+{
+ FcObjectSet *os;
+
+ os = (FcObjectSet *) malloc (sizeof (FcObjectSet));
+ if (!os)
+ return 0;
+ FcMemAlloc (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
+ os->nobject = 0;
+ os->sobject = 0;
+ os->objects = 0;
+ return os;
+}
+
+FcBool
+FcObjectSetAdd (FcObjectSet *os, const char *object)
+{
+ int s;
+ const char **objects;
+
+ if (os->nobject == os->sobject)
+ {
+ s = os->sobject + 4;
+ if (os->objects)
+ objects = (const char **) realloc ((void *) os->objects,
+ s * sizeof (const char *));
+ else
+ objects = (const char **) malloc (s * sizeof (const char *));
+ if (!objects)
+ return FcFalse;
+ if (os->sobject)
+ FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
+ FcMemAlloc (FC_MEM_OBJECTPTR, s * sizeof (const char *));
+ os->objects = objects;
+ os->sobject = s;
+ }
+ os->objects[os->nobject++] = object;
+ return FcTrue;
+}
+
+void
+FcObjectSetDestroy (FcObjectSet *os)
+{
+ if (os->objects)
+ {
+ FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
+ free ((void *) os->objects);
+ }
+ FcMemFree (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
+ free (os);
+}
+
+FcObjectSet *
+FcObjectSetVaBuild (const char *first, va_list va)
+{
+ FcObjectSet *ret;
+
+ FcObjectSetVapBuild (ret, first, va);
+ return ret;
+}
+
+FcObjectSet *
+FcObjectSetBuild (const char *first, ...)
+{
+ va_list va;
+ FcObjectSet *os;
+
+ va_start (va, first);
+ FcObjectSetVapBuild (os, first, va);
+ va_end (va);
+ return os;
+}
+
+static FcBool
+FcListValueListMatchAny (FcValueList *v1orig,
+ FcValueList *v2orig)
+{
+ FcValueList *v1, *v2;
+
+ for (v1 = v1orig; v1; v1 = v1->next)
+ for (v2 = v2orig; v2; v2 = v2->next)
+ if (FcConfigCompareValue (v2->value, FcOpContains, v1->value))
+ return FcTrue;
+ return FcFalse;
+}
+
+static FcBool
+FcListValueListEqual (FcValueList *v1orig,
+ FcValueList *v2orig)
+{
+ FcValueList *v1, *v2;
+
+ for (v1 = v1orig; v1; v1 = v1->next)
+ {
+ for (v2 = v2orig; v2; v2 = v2->next)
+ if (FcConfigCompareValue (v1->value, FcOpEqual, v2->value))
+ break;
+ if (!v2)
+ return FcFalse;
+ }
+ for (v2 = v2orig; v2; v2 = v2->next)
+ {
+ for (v1 = v1orig; v1; v1 = v1->next)
+ if (FcConfigCompareValue (v1->value, FcOpEqual, v2->value))
+ break;
+ if (!v1)
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+/*
+ * FcTrue iff all objects in "p" match "font"
+ */
+
+static FcBool
+FcListPatternMatchAny (FcPattern *p,
+ FcPattern *font)
+{
+ int i;
+ FcPatternElt *e;
+
+ for (i = 0; i < p->num; i++)
+ {
+ e = FcPatternFind (font, p->elts[i].object, FcFalse);
+ if (!e)
+ return FcFalse;
+ if (!FcListValueListMatchAny (p->elts[i].values, e->values))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+static FcBool
+FcListPatternEqual (FcPattern *p1,
+ FcPattern *p2,
+ FcObjectSet *os)
+{
+ int i;
+ FcPatternElt *e1, *e2;
+
+ for (i = 0; i < os->nobject; i++)
+ {
+ e1 = FcPatternFind (p1, os->objects[i], FcFalse);
+ e2 = FcPatternFind (p2, os->objects[i], FcFalse);
+ if (!e1 && !e2)
+ return FcTrue;
+ if (!e1 || !e2)
+ return FcFalse;
+ if (!FcListValueListEqual (e1->values, e2->values))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+static FcChar32
+FcListStringHash (const FcChar8 *s)
+{
+ FcChar32 h = 0;
+ FcChar8 c;
+
+ while ((c = *s++))
+ {
+ c = FcToLower (c);
+ h = ((h << 3) ^ (h >> 3)) ^ c;
+ }
+ return h;
+}
+
+static FcChar32
+FcListMatrixHash (const FcMatrix *m)
+{
+ int xx = (int) (m->xx * 100),
+ xy = (int) (m->xy * 100),
+ yx = (int) (m->yx * 100),
+ yy = (int) (m->yy * 100);
+
+ return ((FcChar32) xx) ^ ((FcChar32) xy) ^ ((FcChar32) yx) ^ ((FcChar32) yy);
+}
+
+static FcChar32
+FcListValueHash (FcValue v)
+{
+ switch (v.type) {
+ case FcTypeVoid:
+ return 0;
+ case FcTypeInteger:
+ return (FcChar32) v.u.i;
+ case FcTypeDouble:
+ return (FcChar32) (int) v.u.d;
+ case FcTypeString:
+ return FcListStringHash (v.u.s);
+ case FcTypeBool:
+ return (FcChar32) v.u.b;
+ case FcTypeMatrix:
+ return FcListMatrixHash (v.u.m);
+ case FcTypeCharSet:
+ return FcCharSetCount (v.u.c);
+ }
+ return 0;
+}
+
+static FcChar32
+FcListValueListHash (FcValueList *list)
+{
+ FcChar32 h = 0;
+
+ while (list)
+ {
+ h = h ^ FcListValueHash (list->value);
+ list = list->next;
+ }
+ return h;
+}
+
+static FcChar32
+FcListPatternHash (FcPattern *font,
+ FcObjectSet *os)
+{
+ int n;
+ FcPatternElt *e;
+ FcChar32 h = 0;
+
+ for (n = 0; n < os->nobject; n++)
+ {
+ e = FcPatternFind (font, os->objects[n], FcFalse);
+ if (e)
+ h = h ^ FcListValueListHash (e->values);
+ }
+ return h;
+}
+
+typedef struct _FcListBucket {
+ struct _FcListBucket *next;
+ FcChar32 hash;
+ FcPattern *pattern;
+} FcListBucket;
+
+#define FC_LIST_HASH_SIZE 4099
+
+typedef struct _FcListHashTable {
+ int entries;
+ FcListBucket *buckets[FC_LIST_HASH_SIZE];
+} FcListHashTable;
+
+static void
+FcListHashTableInit (FcListHashTable *table)
+{
+ table->entries = 0;
+ memset (table->buckets, '\0', sizeof (table->buckets));
+}
+
+static void
+FcListHashTableCleanup (FcListHashTable *table)
+{
+ int i;
+ FcListBucket *bucket, *next;
+
+ for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+ {
+ for (bucket = table->buckets[i]; bucket; bucket = next)
+ {
+ next = bucket->next;
+ FcPatternDestroy (bucket->pattern);
+ FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ free (bucket);
+ }
+ table->buckets[i] = 0;
+ }
+ table->entries = 0;
+}
+
+static FcBool
+FcListAppend (FcListHashTable *table,
+ FcPattern *font,
+ FcObjectSet *os)
+{
+ int o;
+ FcPatternElt *e;
+ FcValueList *v;
+ FcChar32 hash;
+ FcListBucket **prev, *bucket;
+
+ hash = FcListPatternHash (font, os);
+ for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE];
+ (bucket = *prev); prev = &(bucket->next))
+ {
+ if (bucket->hash == hash &&
+ FcListPatternEqual (bucket->pattern, font, os))
+ return FcTrue;
+ }
+ bucket = (FcListBucket *) malloc (sizeof (FcListBucket));
+ if (!bucket)
+ goto bail0;
+ FcMemAlloc (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ bucket->next = 0;
+ bucket->hash = hash;
+ bucket->pattern = FcPatternCreate ();
+ if (!bucket->pattern)
+ goto bail1;
+
+ for (o = 0; o < os->nobject; o++)
+ {
+ e = FcPatternFind (font, os->objects[o], FcFalse);
+ if (e)
+ {
+ for (v = e->values; v; v = v->next)
+ {
+ if (!FcPatternAdd (bucket->pattern,
+ os->objects[o],
+ v->value, FcTrue))
+ goto bail2;
+ }
+ }
+ }
+ *prev = bucket;
+ ++table->entries;
+
+ return FcTrue;
+
+bail2:
+ FcPatternDestroy (bucket->pattern);
+bail1:
+ FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ free (bucket);
+bail0:
+ return FcFalse;
+}
+
+FcFontSet *
+FcFontList (FcConfig *config,
+ FcPattern *p,
+ FcObjectSet *os)
+{
+ FcFontSet *ret;
+ FcFontSet *s;
+ int f;
+ FcSetName set;
+ FcListHashTable table;
+ int i;
+ FcListBucket *bucket;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ goto bail0;
+ }
+ FcListHashTableInit (&table);
+ /*
+ * Walk all available fonts adding those that
+ * match to the hash table
+ */
+ for (set = FcSetSystem; set <= FcSetApplication; set++)
+ {
+ s = config->fonts[set];
+ if (!s)
+ continue;
+ for (f = 0; f < s->nfont; f++)
+ if (FcListPatternMatchAny (p, s->fonts[f]))
+ if (!FcListAppend (&table, s->fonts[f], os))
+ goto bail1;
+ }
+#if 0
+ {
+ int max = 0;
+ int full = 0;
+ int ents = 0;
+ int len;
+ for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+ {
+ if ((bucket = table.buckets[i]))
+ {
+ len = 0;
+ for (; bucket; bucket = bucket->next)
+ {
+ ents++;
+ len++;
+ }
+ if (len > max)
+ max = len;
+ full++;
+ }
+ }
+ printf ("used: %d max: %d avg: %g\n", full, max,
+ (double) ents / FC_LIST_HASH_SIZE);
+ }
+#endif
+ /*
+ * Walk the hash table and build
+ * a font set
+ */
+ ret = FcFontSetCreate ();
+ if (!ret)
+ goto bail0;
+ for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+ while ((bucket = table.buckets[i]))
+ {
+ if (!FcFontSetAdd (ret, bucket->pattern))
+ goto bail2;
+ table.buckets[i] = bucket->next;
+ FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ free (bucket);
+ }
+
+ return ret;
+
+bail2:
+ FcFontSetDestroy (ret);
+bail1:
+ FcListHashTableCleanup (&table);
+bail0:
+ return 0;
+}
diff --git a/src/fcmatch.c b/src/fcmatch.c
new file mode 100644
index 0000000..069f69f
--- /dev/null
+++ b/src/fcmatch.c
@@ -0,0 +1,347 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include "fcint.h"
+#include <stdio.h>
+
+static double
+FcCompareInteger (char *object, FcValue value1, FcValue value2)
+{
+ int v;
+
+ if (value2.type != FcTypeInteger || value1.type != FcTypeInteger)
+ return -1.0;
+ v = value2.u.i - value1.u.i;
+ if (v < 0)
+ v = -v;
+ return (double) v;
+}
+
+static double
+FcCompareString (char *object, FcValue value1, FcValue value2)
+{
+ if (value2.type != FcTypeString || value1.type != FcTypeString)
+ return -1.0;
+ return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
+}
+
+static double
+FcCompareBool (char *object, FcValue value1, FcValue value2)
+{
+ if (value2.type != FcTypeBool || value1.type != FcTypeBool)
+ return -1.0;
+ return (double) value2.u.b != value1.u.b;
+}
+
+static double
+FcCompareCharSet (char *object, FcValue value1, FcValue value2)
+{
+ if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
+ return -1.0;
+ return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
+}
+
+static double
+FcCompareSize (char *object, FcValue value1, FcValue value2)
+{
+ double v1, v2, v;
+
+ switch (value1.type) {
+ case FcTypeInteger:
+ v1 = value1.u.i;
+ break;
+ case FcTypeDouble:
+ v1 = value1.u.d;
+ break;
+ default:
+ return -1;
+ }
+ switch (value2.type) {
+ case FcTypeInteger:
+ v2 = value2.u.i;
+ break;
+ case FcTypeDouble:
+ v2 = value2.u.d;
+ break;
+ default:
+ return -1;
+ }
+ if (v2 == 0)
+ return 0;
+ v = v2 - v1;
+ if (v < 0)
+ v = -v;
+ return v;
+}
+
+/*
+ * Order is significant, it defines the precedence of
+ * each value, earlier values are more significant than
+ * later values
+ */
+static FcMatcher _FcMatchers [] = {
+ { FC_FOUNDRY, FcCompareString, },
+ { FC_CHARSET, FcCompareCharSet },
+ { FC_ANTIALIAS, FcCompareBool, },
+ { FC_LANG, FcCompareString },
+ { FC_FAMILY, FcCompareString, },
+ { FC_SPACING, FcCompareInteger, },
+ { FC_PIXEL_SIZE, FcCompareSize, },
+ { FC_STYLE, FcCompareString, },
+ { FC_SLANT, FcCompareInteger, },
+ { FC_WEIGHT, FcCompareInteger, },
+ { FC_RASTERIZER, FcCompareString, },
+ { FC_OUTLINE, FcCompareBool, },
+};
+
+#define NUM_MATCHER (sizeof _FcMatchers / sizeof _FcMatchers[0])
+
+static FcBool
+FcCompareValueList (const char *object,
+ FcValueList *v1orig, /* pattern */
+ FcValueList *v2orig, /* target */
+ FcValue *bestValue,
+ double *value,
+ FcResult *result)
+{
+ FcValueList *v1, *v2;
+ double v, best;
+ int j;
+ int i;
+
+ for (i = 0; i < NUM_MATCHER; i++)
+ {
+ if (!FcStrCmpIgnoreCase (_FcMatchers[i].object, object))
+ break;
+ }
+ if (i == NUM_MATCHER)
+ {
+ if (bestValue)
+ *bestValue = v2orig->value;
+ return FcTrue;
+ }
+
+ best = 1e99;
+ j = 0;
+ for (v1 = v1orig; v1; v1 = v1->next)
+ {
+ for (v2 = v2orig; v2; v2 = v2->next)
+ {
+ v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
+ v1->value,
+ v2->value);
+ if (v < 0)
+ {
+ *result = FcResultTypeMismatch;
+ return FcFalse;
+ }
+ if (FcDebug () & FC_DBG_MATCHV)
+ printf (" v %g j %d ", v, j);
+ v = v * 100 + j;
+ if (v < best)
+ {
+ if (bestValue)
+ *bestValue = v2->value;
+ best = v;
+ }
+ }
+ j++;
+ }
+ if (FcDebug () & FC_DBG_MATCHV)
+ {
+ printf (" %s: %g ", object, best);
+ FcValueListPrint (v1orig);
+ printf (", ");
+ FcValueListPrint (v2orig);
+ printf ("\n");
+ }
+ value[i] += best;
+ return FcTrue;
+}
+
+/*
+ * Return a value indicating the distance between the two lists of
+ * values
+ */
+
+static FcBool
+FcCompare (FcPattern *pat,
+ FcPattern *fnt,
+ double *value,
+ FcResult *result)
+{
+ int i, i1, i2;
+
+ for (i = 0; i < NUM_MATCHER; i++)
+ value[i] = 0.0;
+
+ for (i1 = 0; i1 < pat->num; i1++)
+ {
+ for (i2 = 0; i2 < fnt->num; i2++)
+ {
+ if (!FcStrCmpIgnoreCase (pat->elts[i1].object,
+ fnt->elts[i2].object))
+ {
+ if (!FcCompareValueList (pat->elts[i1].object,
+ pat->elts[i1].values,
+ fnt->elts[i2].values,
+ 0,
+ value,
+ result))
+ return FcFalse;
+ break;
+ }
+ }
+#if 0
+ /*
+ * Overspecified patterns are slightly penalized in
+ * case some other font includes the requested field
+ */
+ if (i2 == fnt->num)
+ {
+ for (i2 = 0; i2 < NUM_MATCHER; i2++)
+ {
+ if (!FcStrCmpIgnoreCase (_FcMatchers[i2].object,
+ pat->elts[i1].object))
+ {
+ value[i2] = 1.0;
+ break;
+ }
+ }
+ }
+#endif
+ }
+ return FcTrue;
+}
+
+FcPattern *
+FcFontMatch (FcConfig *config,
+ FcPattern *p,
+ FcResult *result)
+{
+ double score[NUM_MATCHER], bestscore[NUM_MATCHER];
+ int f;
+ FcFontSet *s;
+ FcPattern *best;
+ FcPattern *new;
+ FcPatternElt *fe, *pe;
+ FcValue v;
+ int i;
+ FcSetName set;
+
+ for (i = 0; i < NUM_MATCHER; i++)
+ bestscore[i] = 0;
+ best = 0;
+ if (FcDebug () & FC_DBG_MATCH)
+ {
+ printf ("Match ");
+ FcPatternPrint (p);
+ }
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ for (set = FcSetSystem; set <= FcSetApplication; set++)
+ {
+ s = config->fonts[set];
+ if (!s)
+ continue;
+ for (f = 0; f < s->nfont; f++)
+ {
+ if (FcDebug () & FC_DBG_MATCHV)
+ {
+ printf ("Font %d ", f);
+ FcPatternPrint (s->fonts[f]);
+ }
+ if (!FcCompare (p, s->fonts[f], score, result))
+ return 0;
+ if (FcDebug () & FC_DBG_MATCHV)
+ {
+ printf ("Score");
+ for (i = 0; i < NUM_MATCHER; i++)
+ {
+ printf (" %g", score[i]);
+ }
+ printf ("\n");
+ }
+ for (i = 0; i < NUM_MATCHER; i++)
+ {
+ if (best && bestscore[i] < score[i])
+ break;
+ if (!best || score[i] < bestscore[i])
+ {
+ for (i = 0; i < NUM_MATCHER; i++)
+ bestscore[i] = score[i];
+ best = s->fonts[f];
+ break;
+ }
+ }
+ }
+ }
+ if (FcDebug () & FC_DBG_MATCH)
+ {
+ printf ("Best score");
+ for (i = 0; i < NUM_MATCHER; i++)
+ printf (" %g", bestscore[i]);
+ FcPatternPrint (best);
+ }
+ if (!best)
+ {
+ *result = FcResultNoMatch;
+ return 0;
+ }
+ new = FcPatternCreate ();
+ if (!new)
+ return 0;
+ for (i = 0; i < best->num; i++)
+ {
+ fe = &best->elts[i];
+ pe = FcPatternFind (p, fe->object, FcFalse);
+ if (pe)
+ {
+ if (!FcCompareValueList (pe->object, pe->values,
+ fe->values, &v, score, result))
+ {
+ FcPatternDestroy (new);
+ return 0;
+ }
+ }
+ else
+ v = fe->values->value;
+ FcPatternAdd (new, fe->object, v, FcTrue);
+ }
+ for (i = 0; i < p->num; i++)
+ {
+ pe = &p->elts[i];
+ fe = FcPatternFind (best, pe->object, FcFalse);
+ if (!fe)
+ FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
+ }
+ FcConfigSubstitute (config, new, FcMatchFont);
+ return new;
+}
diff --git a/src/fcmatrix.c b/src/fcmatrix.c
new file mode 100644
index 0000000..d2a9f1e
--- /dev/null
+++ b/src/fcmatrix.c
@@ -0,0 +1,112 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Tuomas J. Lukka
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Tuomas Lukka not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Tuomas Lukka makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * TUOMAS LUKKA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL TUOMAS LUKKA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "fcint.h"
+
+FcMatrix *
+FcMatrixCopy (const FcMatrix *mat)
+{
+ FcMatrix *r;
+ if(!mat)
+ return 0;
+ r = (FcMatrix *) malloc (sizeof (*r) );
+ if (!r)
+ return 0;
+ FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
+ *r = *mat;
+ return r;
+}
+
+void
+FcMatrixFree (FcMatrix *mat)
+{
+ FcMemFree (FC_MEM_MATRIX, sizeof (FcMatrix));
+ free (mat);
+}
+
+FcBool
+FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2)
+{
+ if(mat1 == mat2) return FcTrue;
+ if(mat1 == 0 || mat2 == 0) return FcFalse;
+ return mat1->xx == mat2->xx &&
+ mat1->xy == mat2->xy &&
+ mat1->yx == mat2->yx &&
+ mat1->yy == mat2->yy;
+}
+
+void
+FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b)
+{
+ FcMatrix r;
+
+ r.xx = a->xx * b->xx + a->xy * b->yx;
+ r.xy = a->xx * b->xy + a->xy * b->yy;
+ r.yx = a->yx * b->xx + a->yy * b->yx;
+ r.yy = a->yx * b->xy + a->yy * b->yy;
+ *result = r;
+}
+
+void
+FcMatrixRotate (FcMatrix *m, double c, double s)
+{
+ FcMatrix r;
+
+ /*
+ * X Coordinate system is upside down, swap to make
+ * rotations counterclockwise
+ */
+ r.xx = c;
+ r.xy = -s;
+ r.yx = s;
+ r.yy = c;
+ FcMatrixMultiply (m, &r, m);
+}
+
+void
+FcMatrixScale (FcMatrix *m, double sx, double sy)
+{
+ FcMatrix r;
+
+ r.xx = sx;
+ r.xy = 0;
+ r.yx = 0;
+ r.yy = sy;
+ FcMatrixMultiply (m, &r, m);
+}
+
+void
+FcMatrixShear (FcMatrix *m, double sh, double sv)
+{
+ FcMatrix r;
+
+ r.xx = 1;
+ r.xy = sh;
+ r.yx = sv;
+ r.yy = 1;
+ FcMatrixMultiply (m, &r, m);
+}
diff --git a/src/fcname.c b/src/fcname.c
new file mode 100644
index 0000000..ed7c6c5
--- /dev/null
+++ b/src/fcname.c
@@ -0,0 +1,621 @@
+/*
+ * $XFree86: xc/lib/Fc/xftname.c,v 1.10 2001/03/30 18:50:18 keithp Exp $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "fcint.h"
+
+static const FcObjectType _FcBaseObjectTypes[] = {
+ { FC_FAMILY, FcTypeString, },
+ { FC_STYLE, FcTypeString, },
+ { FC_SLANT, FcTypeInteger, },
+ { FC_WEIGHT, FcTypeInteger, },
+ { FC_SIZE, FcTypeDouble, },
+ { FC_PIXEL_SIZE, FcTypeDouble, },
+ { FC_SPACING, FcTypeInteger, },
+ { FC_FOUNDRY, FcTypeString, },
+/* { FC_CORE, FcTypeBool, }, */
+ { FC_ANTIALIAS, FcTypeBool, },
+/* { FC_XLFD, FcTypeString, }, */
+ { FC_FILE, FcTypeString, },
+ { FC_INDEX, FcTypeInteger, },
+ { FC_RASTERIZER, FcTypeString, },
+ { FC_OUTLINE, FcTypeBool, },
+ { FC_SCALABLE, FcTypeBool, },
+ { FC_RGBA, FcTypeInteger, },
+ { FC_SCALE, FcTypeDouble, },
+/* { FC_RENDER, FcTypeBool, },*/
+ { FC_MINSPACE, FcTypeBool, },
+ { FC_CHAR_WIDTH, FcTypeInteger },
+ { FC_CHAR_HEIGHT, FcTypeInteger },
+ { FC_MATRIX, FcTypeMatrix },
+ { FC_CHARSET, FcTypeCharSet },
+ { FC_LANG, FcTypeString },
+};
+
+#define NUM_OBJECT_TYPES (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
+
+typedef struct _FcObjectTypeList FcObjectTypeList;
+
+struct _FcObjectTypeList {
+ const FcObjectTypeList *next;
+ const FcObjectType *types;
+ int ntypes;
+};
+
+static const FcObjectTypeList _FcBaseObjectTypesList = {
+ 0,
+ _FcBaseObjectTypes,
+ NUM_OBJECT_TYPES
+};
+
+static const FcObjectTypeList *_FcObjectTypes = &_FcBaseObjectTypesList;
+
+FcBool
+FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
+{
+ FcObjectTypeList *l;
+
+ l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
+ if (!l)
+ return FcFalse;
+ l->types = types;
+ l->ntypes = ntypes;
+ l->next = _FcObjectTypes;
+ _FcObjectTypes = l;
+ return FcTrue;
+}
+
+FcBool
+FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
+{
+ const FcObjectTypeList *l, **prev;
+
+ for (prev = &_FcObjectTypes;
+ (l = *prev);
+ prev = (const FcObjectTypeList **) &(l->next))
+ {
+ if (l->types == types && l->ntypes == ntypes)
+ {
+ *prev = l->next;
+ free ((void *) l);
+ return FcTrue;
+ }
+ }
+ return FcFalse;
+}
+
+const FcObjectType *
+FcNameGetObjectType (const char *object)
+{
+ int i;
+ const FcObjectTypeList *l;
+ const FcObjectType *t;
+
+ for (l = _FcObjectTypes; l; l = l->next)
+ {
+ for (i = 0; i < l->ntypes; i++)
+ {
+ t = &l->types[i];
+ if (!FcStrCmpIgnoreCase (object, t->object))
+ return t;
+ }
+ }
+ return 0;
+}
+
+static const FcConstant _FcBaseConstants[] = {
+ { "light", "weight", FC_WEIGHT_LIGHT, },
+ { "medium", "weight", FC_WEIGHT_MEDIUM, },
+ { "demibold", "weight", FC_WEIGHT_DEMIBOLD, },
+ { "bold", "weight", FC_WEIGHT_BOLD, },
+ { "black", "weight", FC_WEIGHT_BLACK, },
+
+ { "roman", "slant", FC_SLANT_ROMAN, },
+ { "italic", "slant", FC_SLANT_ITALIC, },
+ { "oblique", "slant", FC_SLANT_OBLIQUE, },
+
+ { "proportional", "spacing", FC_PROPORTIONAL, },
+ { "mono", "spacing", FC_MONO, },
+ { "charcell", "spacing", FC_CHARCELL, },
+
+ { "rgb", "rgba", FC_RGBA_RGB, },
+ { "bgr", "rgba", FC_RGBA_BGR, },
+ { "vrgb", "rgba", FC_RGBA_VRGB },
+ { "vbgr", "rgba", FC_RGBA_VBGR },
+};
+
+#define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
+
+typedef struct _FcConstantList FcConstantList;
+
+struct _FcConstantList {
+ const FcConstantList *next;
+ const FcConstant *consts;
+ int nconsts;
+};
+
+static const FcConstantList _FcBaseConstantList = {
+ 0,
+ _FcBaseConstants,
+ NUM_FC_CONSTANTS
+};
+
+static const FcConstantList *_FcConstants = &_FcBaseConstantList;
+
+FcBool
+FcNameRegisterConstants (const FcConstant *consts, int nconsts)
+{
+ FcConstantList *l;
+
+ l = (FcConstantList *) malloc (sizeof (FcConstantList));
+ if (!l)
+ return FcFalse;
+ l->consts = consts;
+ l->nconsts = nconsts;
+ l->next = _FcConstants;
+ _FcConstants = l;
+ return FcTrue;
+}
+
+FcBool
+FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
+{
+ const FcConstantList *l, **prev;
+
+ for (prev = &_FcConstants;
+ (l = *prev);
+ prev = (const FcConstantList **) &(l->next))
+ {
+ if (l->consts == consts && l->nconsts == nconsts)
+ {
+ *prev = l->next;
+ free ((void *) l);
+ return FcTrue;
+ }
+ }
+ return FcFalse;
+}
+
+const FcConstant *
+FcNameGetConstant (char *string)
+{
+ const FcConstantList *l;
+ int i;
+
+ for (l = _FcConstants; l; l = l->next)
+ {
+ for (i = 0; i < l->nconsts; i++)
+ if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
+ return &l->consts[i];
+ }
+ return 0;
+}
+
+FcBool
+FcNameConstant (char *string, int *result)
+{
+ const FcConstant *c;
+
+ if ((c = FcNameGetConstant(string)))
+ {
+ *result = c->value;
+ return FcTrue;
+ }
+ return FcFalse;
+}
+
+FcBool
+FcNameBool (char *v, FcBool *result)
+{
+ char c0, c1;
+
+ c0 = *v;
+ if (isupper (c0))
+ c0 = tolower (c0);
+ if (c0 == 't' || c0 == 'y' || c0 == '1')
+ {
+ *result = FcTrue;
+ return FcTrue;
+ }
+ if (c0 == 'f' || c0 == 'n' || c0 == '0')
+ {
+ *result = FcFalse;
+ return FcTrue;
+ }
+ if (c0 == 'o')
+ {
+ c1 = v[1];
+ if (isupper (c1))
+ c1 = tolower (c1);
+ if (c1 == 'n')
+ {
+ *result = FcTrue;
+ return FcTrue;
+ }
+ if (c1 == 'f')
+ {
+ *result = FcFalse;
+ return FcTrue;
+ }
+ }
+ return FcFalse;
+}
+
+static FcValue
+FcNameConvert (FcType type, char *string, FcMatrix *m)
+{
+ FcValue v;
+
+ v.type = type;
+ switch (v.type) {
+ case FcTypeInteger:
+ if (!FcNameConstant (string, &v.u.i))
+ v.u.i = atoi (string);
+ break;
+ case FcTypeString:
+ v.u.s = string;
+ break;
+ case FcTypeBool:
+ if (!FcNameBool (string, &v.u.b))
+ v.u.b = FcFalse;
+ break;
+ case FcTypeDouble:
+ v.u.d = strtod (string, 0);
+ break;
+ case FcTypeMatrix:
+ v.u.m = m;
+ sscanf (string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
+ break;
+ case FcTypeCharSet:
+ v.u.c = FcNameParseCharSet (string);
+ break;
+ default:
+ break;
+ }
+ return v;
+}
+
+static const char *
+FcNameFindNext (const char *cur, const char *delim, char *save, char *last)
+{
+ char c;
+
+ while ((c = *cur))
+ {
+ if (c == '\\')
+ {
+ ++cur;
+ if (!(c = *cur))
+ break;
+ }
+ else if (strchr (delim, c))
+ break;
+ ++cur;
+ *save++ = c;
+ }
+ *save = 0;
+ *last = *cur;
+ if (*cur)
+ cur++;
+ return cur;
+}
+
+FcPattern *
+FcNameParse (const char *name)
+{
+ char *save;
+ FcPattern *pat;
+ double d;
+ char *e;
+ char delim;
+ FcValue v;
+ FcMatrix m;
+ const FcObjectType *t;
+ const FcConstant *c;
+
+ save = malloc (strlen (name) + 1);
+ if (!save)
+ goto bail0;
+ pat = FcPatternCreate ();
+ if (!pat)
+ goto bail1;
+
+ for (;;)
+ {
+ name = FcNameFindNext (name, "-,:", save, &delim);
+ if (save[0])
+ {
+ if (!FcPatternAddString (pat, FC_FAMILY, save))
+ goto bail2;
+ }
+ if (delim != ',')
+ break;
+ }
+ if (delim == '-')
+ {
+ for (;;)
+ {
+ name = FcNameFindNext (name, "-,:", save, &delim);
+ d = strtod (save, &e);
+ if (e != save)
+ {
+ if (!FcPatternAddDouble (pat, FC_SIZE, d))
+ goto bail2;
+ }
+ if (delim != ',')
+ break;
+ }
+ }
+ while (delim == ':')
+ {
+ name = FcNameFindNext (name, "=_:", save, &delim);
+ if (save[0])
+ {
+ if (delim == '=' || delim == '_')
+ {
+ t = FcNameGetObjectType (save);
+ for (;;)
+ {
+ name = FcNameFindNext (name, ":,", save, &delim);
+ if (save[0] && t)
+ {
+ v = FcNameConvert (t->type, save, &m);
+ if (!FcPatternAdd (pat, t->object, v, FcTrue))
+ {
+ if (v.type == FcTypeCharSet)
+ FcCharSetDestroy ((FcCharSet *) v.u.c);
+ goto bail2;
+ }
+ if (v.type == FcTypeCharSet)
+ FcCharSetDestroy ((FcCharSet *) v.u.c);
+ }
+ if (delim != ',')
+ break;
+ }
+ }
+ else
+ {
+ if ((c = FcNameGetConstant (save)))
+ {
+ if (!FcPatternAddInteger (pat, c->object, c->value))
+ goto bail2;
+ }
+ }
+ }
+ }
+
+ free (save);
+ return pat;
+
+bail2:
+ FcPatternDestroy (pat);
+bail1:
+ free (save);
+bail0:
+ return 0;
+}
+
+static void
+FcNameBufInit (FcNameBuf *buf, FcChar8 *init, int size)
+{
+ buf->buf = init;
+ buf->allocated = FcFalse;
+ buf->failed = FcFalse;
+ buf->len = 0;
+ buf->size = size;
+}
+
+static void
+FcNameBufDestroy (FcNameBuf *buf)
+{
+ if (buf->allocated)
+ free (buf->buf);
+}
+
+static FcChar8 *
+FcNameBufDone (FcNameBuf *buf)
+{
+ FcChar8 *ret;
+
+ ret = malloc (buf->len + 1);
+ if (ret)
+ {
+ memcpy (ret, buf->buf, buf->len);
+ ret[buf->len] = '\0';
+ }
+ FcNameBufDestroy (buf);
+ return ret;
+}
+
+FcBool
+FcNameBufChar (FcNameBuf *buf, FcChar8 c)
+{
+ if (buf->len == buf->size)
+ {
+ FcChar8 *new;
+ int size;
+
+ if (buf->allocated)
+ {
+ size = buf->size * 2;
+ new = realloc (buf->buf, size);
+ }
+ else
+ {
+ size = buf->size + 1024;
+ new = malloc (size);
+ if (new)
+ {
+ buf->allocated = FcTrue;
+ memcpy (new, buf->buf, buf->len);
+ }
+ }
+ if (!new)
+ {
+ buf->failed = FcTrue;
+ return FcFalse;
+ }
+ buf->size = size;
+ buf->buf = new;
+ }
+ buf->buf[buf->len++] = c;
+ return FcTrue;
+}
+
+FcBool
+FcNameBufString (FcNameBuf *buf, const FcChar8 *s)
+{
+ FcChar8 c;
+ while ((c = *s++))
+ if (!FcNameBufChar (buf, c))
+ return FcFalse;
+ return FcTrue;
+}
+
+static FcBool
+FcNameUnparseString (FcNameBuf *buf,
+ const FcChar8 *string,
+ const FcChar8 *escape)
+{
+ FcChar8 c;
+ while ((c = *string++))
+ {
+ if (escape && strchr ((char *) escape, (char) c))
+ {
+ if (!FcNameBufChar (buf, escape[0]))
+ return FcFalse;
+ }
+ if (!FcNameBufChar (buf, c))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+static FcBool
+FcNameUnparseValue (FcNameBuf *buf,
+ FcValue v,
+ FcChar8 *escape)
+{
+ FcChar8 temp[1024];
+
+ switch (v.type) {
+ case FcTypeVoid:
+ return FcTrue;
+ case FcTypeInteger:
+ sprintf ((char *) temp, "%d", v.u.i);
+ return FcNameUnparseString (buf, temp, 0);
+ case FcTypeDouble:
+ sprintf ((char *) temp, "%g", v.u.d);
+ return FcNameUnparseString (buf, temp, 0);
+ case FcTypeString:
+ return FcNameUnparseString (buf, v.u.s, escape);
+ case FcTypeBool:
+ return FcNameUnparseString (buf, v.u.b ? "True" : "False", 0);
+ case FcTypeMatrix:
+ sprintf ((char *) temp, "%g %g %g %g",
+ v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
+ return FcNameUnparseString (buf, temp, 0);
+ case FcTypeCharSet:
+ return FcNameUnparseCharSet (buf, v.u.c);
+ }
+ return FcFalse;
+}
+
+static FcBool
+FcNameUnparseValueList (FcNameBuf *buf,
+ FcValueList *v,
+ char *escape)
+{
+ while (v)
+ {
+ if (!FcNameUnparseValue (buf, v->value, escape))
+ return FcFalse;
+ if ((v = v->next))
+ if (!FcNameUnparseString (buf, ",", 0))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+#define FC_ESCAPE_FIXED "\\-:,"
+#define FC_ESCAPE_VARIABLE "\\=_:,"
+
+FcChar8 *
+FcNameUnparse (FcPattern *pat)
+{
+ FcNameBuf buf;
+ FcChar8 buf_static[8192];
+ int i;
+ FcPatternElt *e;
+ const FcObjectTypeList *l;
+ const FcObjectType *o;
+
+ FcNameBufInit (&buf, buf_static, sizeof (buf_static));
+ e = FcPatternFind (pat, FC_FAMILY, FcFalse);
+ if (e)
+ {
+ if (!FcNameUnparseValueList (&buf, e->values, FC_ESCAPE_FIXED))
+ goto bail0;
+ }
+ e = FcPatternFind (pat, FC_SIZE, FcFalse);
+ if (e)
+ {
+ if (!FcNameUnparseString (&buf, "-", 0))
+ goto bail0;
+ if (!FcNameUnparseValueList (&buf, e->values, FC_ESCAPE_FIXED))
+ goto bail0;
+ }
+ for (l = _FcObjectTypes; l; l = l->next)
+ {
+ for (i = 0; i < l->ntypes; i++)
+ {
+ o = &l->types[i];
+ if (!strcmp (o->object, FC_FAMILY) ||
+ !strcmp (o->object, FC_SIZE) ||
+ !strcmp (o->object, FC_FILE))
+ continue;
+
+ e = FcPatternFind (pat, o->object, FcFalse);
+ if (e)
+ {
+ if (!FcNameUnparseString (&buf, ":", 0))
+ goto bail0;
+ if (!FcNameUnparseString (&buf, o->object, FC_ESCAPE_VARIABLE))
+ goto bail0;
+ if (!FcNameUnparseString (&buf, "=", 0))
+ goto bail0;
+ if (!FcNameUnparseValueList (&buf, e->values,
+ FC_ESCAPE_VARIABLE))
+ goto bail0;
+ }
+ }
+ }
+ return FcNameBufDone (&buf);
+bail0:
+ FcNameBufDestroy (&buf);
+ return 0;
+}
diff --git a/src/fcpat.c b/src/fcpat.c
new file mode 100644
index 0000000..a1fd774
--- /dev/null
+++ b/src/fcpat.c
@@ -0,0 +1,491 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "fcint.h"
+
+FcPattern *
+FcPatternCreate (void)
+{
+ FcPattern *p;
+
+ p = (FcPattern *) malloc (sizeof (FcPattern));
+ if (!p)
+ return 0;
+ FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
+ p->num = 0;
+ p->size = 0;
+ p->elts = 0;
+ return p;
+}
+
+void
+FcValueDestroy (FcValue v)
+{
+ switch (v.type) {
+ case FcTypeString:
+ FcStrFree ((FcChar8 *) v.u.s);
+ break;
+ case FcTypeMatrix:
+ FcMatrixFree ((FcMatrix *) v.u.m);
+ break;
+ case FcTypeCharSet:
+ FcCharSetDestroy ((FcCharSet *) v.u.c);
+ break;
+ default:
+ break;
+ }
+}
+
+FcValue
+FcValueSave (FcValue v)
+{
+ switch (v.type) {
+ case FcTypeString:
+ v.u.s = FcStrCopy (v.u.s);
+ if (!v.u.s)
+ v.type = FcTypeVoid;
+ break;
+ case FcTypeMatrix:
+ v.u.m = FcMatrixCopy (v.u.m);
+ if (!v.u.m)
+ v.type = FcTypeVoid;
+ break;
+ case FcTypeCharSet:
+ v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
+ if (!v.u.c)
+ v.type = FcTypeVoid;
+ break;
+ default:
+ break;
+ }
+ return v;
+}
+
+void
+FcValueListDestroy (FcValueList *l)
+{
+ FcValueList *next;
+ for (; l; l = next)
+ {
+ switch (l->value.type) {
+ case FcTypeString:
+ FcStrFree ((FcChar8 *) l->value.u.s);
+ break;
+ case FcTypeMatrix:
+ FcMatrixFree ((FcMatrix *) l->value.u.m);
+ break;
+ case FcTypeCharSet:
+ FcCharSetDestroy ((FcCharSet *) l->value.u.c);
+ break;
+ default:
+ break;
+ }
+ next = l->next;
+ FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+ free (l);
+ }
+}
+
+void
+FcPatternDestroy (FcPattern *p)
+{
+ int i;
+
+ for (i = 0; i < p->num; i++)
+ FcValueListDestroy (p->elts[i].values);
+
+ p->num = 0;
+ if (p->elts)
+ {
+ FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
+ free (p->elts);
+ p->elts = 0;
+ }
+ p->size = 0;
+ FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
+ free (p);
+}
+
+FcPatternElt *
+FcPatternFind (FcPattern *p, const char *object, FcBool insert)
+{
+ int i;
+ int s;
+ FcPatternElt *e;
+
+ /* match existing */
+ for (i = 0; i < p->num; i++)
+ {
+ if (!FcStrCmpIgnoreCase (object, p->elts[i].object))
+ return &p->elts[i];
+ }
+
+ if (!insert)
+ return FcFalse;
+
+ /* grow array */
+ if (i == p->size)
+ {
+ s = p->size + 16;
+ if (p->elts)
+ e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
+ else
+ e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
+ if (!e)
+ return FcFalse;
+ p->elts = e;
+ if (p->size)
+ FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
+ FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
+ while (p->size < s)
+ {
+ p->elts[p->size].object = 0;
+ p->elts[p->size].values = 0;
+ p->size++;
+ }
+ }
+
+ /* bump count */
+ p->num++;
+
+ p->elts[i].object = object;
+
+ return &p->elts[i];
+}
+
+FcBool
+FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
+{
+ FcPatternElt *e;
+ FcValueList *new, **prev;
+
+ new = (FcValueList *) malloc (sizeof (FcValueList));
+ if (!new)
+ goto bail0;
+
+ FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
+ /* dup string */
+ value = FcValueSave (value);
+ if (value.type == FcTypeVoid)
+ goto bail1;
+
+ new->value = value;
+ new->next = 0;
+
+ e = FcPatternFind (p, object, FcTrue);
+ if (!e)
+ goto bail2;
+
+ if (append)
+ {
+ for (prev = &e->values; *prev; prev = &(*prev)->next);
+ *prev = new;
+ }
+ else
+ {
+ new->next = e->values;
+ e->values = new;
+ }
+
+ return FcTrue;
+
+bail2:
+ switch (value.type) {
+ case FcTypeString:
+ FcStrFree ((FcChar8 *) value.u.s);
+ break;
+ case FcTypeMatrix:
+ FcMatrixFree ((FcMatrix *) value.u.m);
+ break;
+ case FcTypeCharSet:
+ FcCharSetDestroy ((FcCharSet *) value.u.c);
+ break;
+ default:
+ break;
+ }
+bail1:
+ FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+ free (new);
+bail0:
+ return FcFalse;
+}
+
+FcBool
+FcPatternDel (FcPattern *p, const char *object)
+{
+ FcPatternElt *e;
+ int i;
+
+ e = FcPatternFind (p, object, FcFalse);
+ if (!e)
+ return FcFalse;
+
+ i = e - p->elts;
+
+ /* destroy value */
+ FcValueListDestroy (e->values);
+
+ /* shuffle existing ones down */
+ memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
+ p->num--;
+ p->elts[p->num].object = 0;
+ p->elts[p->num].values = 0;
+ return FcTrue;
+}
+
+FcBool
+FcPatternAddInteger (FcPattern *p, const char *object, int i)
+{
+ FcValue v;
+
+ v.type = FcTypeInteger;
+ v.u.i = i;
+ return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddDouble (FcPattern *p, const char *object, double d)
+{
+ FcValue v;
+
+ v.type = FcTypeDouble;
+ v.u.d = d;
+ return FcPatternAdd (p, object, v, FcTrue);
+}
+
+
+FcBool
+FcPatternAddString (FcPattern *p, const char *object, const char *s)
+{
+ FcValue v;
+
+ v.type = FcTypeString;
+ v.u.s = (char *) s;
+ return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
+{
+ FcValue v;
+
+ v.type = FcTypeMatrix;
+ v.u.m = (FcMatrix *) s;
+ return FcPatternAdd (p, object, v, FcTrue);
+}
+
+
+FcBool
+FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
+{
+ FcValue v;
+
+ v.type = FcTypeBool;
+ v.u.b = b;
+ return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
+{
+ FcValue v;
+
+ v.type = FcTypeCharSet;
+ v.u.c = (FcCharSet *) c;
+ return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcResult
+FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
+{
+ FcPatternElt *e;
+ FcValueList *l;
+
+ e = FcPatternFind (p, object, FcFalse);
+ if (!e)
+ return FcResultNoMatch;
+ for (l = e->values; l; l = l->next)
+ {
+ if (!id)
+ {
+ *v = l->value;
+ return FcResultMatch;
+ }
+ id--;
+ }
+ return FcResultNoId;
+}
+
+FcResult
+FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
+{
+ FcValue v;
+ FcResult r;
+
+ r = FcPatternGet (p, object, id, &v);
+ if (r != FcResultMatch)
+ return r;
+ switch (v.type) {
+ case FcTypeDouble:
+ *i = (int) v.u.d;
+ break;
+ case FcTypeInteger:
+ *i = v.u.i;
+ break;
+ default:
+ return FcResultTypeMismatch;
+ }
+ return FcResultMatch;
+}
+
+FcResult
+FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
+{
+ FcValue v;
+ FcResult r;
+
+ r = FcPatternGet (p, object, id, &v);
+ if (r != FcResultMatch)
+ return r;
+ switch (v.type) {
+ case FcTypeDouble:
+ *d = v.u.d;
+ break;
+ case FcTypeInteger:
+ *d = (double) v.u.i;
+ break;
+ default:
+ return FcResultTypeMismatch;
+ }
+ return FcResultMatch;
+}
+
+FcResult
+FcPatternGetString (FcPattern *p, const char *object, int id, char ** s)
+{
+ FcValue v;
+ FcResult r;
+
+ r = FcPatternGet (p, object, id, &v);
+ if (r != FcResultMatch)
+ return r;
+ if (v.type != FcTypeString)
+ return FcResultTypeMismatch;
+ *s = (char *) v.u.s;
+ return FcResultMatch;
+}
+
+FcResult
+FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
+{
+ FcValue v;
+ FcResult r;
+
+ r = FcPatternGet (p, object, id, &v);
+ if (r != FcResultMatch)
+ return r;
+ if (v.type != FcTypeMatrix)
+ return FcResultTypeMismatch;
+ *m = (FcMatrix *) v.u.m;
+ return FcResultMatch;
+}
+
+
+FcResult
+FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
+{
+ FcValue v;
+ FcResult r;
+
+ r = FcPatternGet (p, object, id, &v);
+ if (r != FcResultMatch)
+ return r;
+ if (v.type != FcTypeBool)
+ return FcResultTypeMismatch;
+ *b = v.u.b;
+ return FcResultMatch;
+}
+
+FcResult
+FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
+{
+ FcValue v;
+ FcResult r;
+
+ r = FcPatternGet (p, object, id, &v);
+ if (r != FcResultMatch)
+ return r;
+ if (v.type != FcTypeCharSet)
+ return FcResultTypeMismatch;
+ *c = (FcCharSet *) v.u.c;
+ return FcResultMatch;
+}
+
+FcPattern *
+FcPatternDuplicate (FcPattern *orig)
+{
+ FcPattern *new;
+ int i;
+ FcValueList *l;
+
+ new = FcPatternCreate ();
+ if (!new)
+ goto bail0;
+
+ for (i = 0; i < orig->num; i++)
+ {
+ for (l = orig->elts[i].values; l; l = l->next)
+ if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
+ goto bail1;
+ }
+
+ return new;
+
+bail1:
+ FcPatternDestroy (new);
+bail0:
+ return 0;
+}
+
+FcPattern *
+FcPatternVaBuild (FcPattern *orig, va_list va)
+{
+ FcPattern *ret;
+
+ FcPatternVapBuild (ret, orig, va);
+ return ret;
+}
+
+FcPattern *
+FcPatternBuild (FcPattern *orig, ...)
+{
+ va_list va;
+
+ va_start (va, orig);
+ FcPatternVapBuild (orig, orig, va);
+ va_end (va);
+ return orig;
+}
diff --git a/src/fcstr.c b/src/fcstr.c
new file mode 100644
index 0000000..658890e
--- /dev/null
+++ b/src/fcstr.c
@@ -0,0 +1,188 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "fcint.h"
+
+char *
+FcStrCopy (const char *s)
+{
+ char *r;
+
+ if (!s)
+ return 0;
+ r = (char *) malloc (strlen (s) + 1);
+ if (!r)
+ return 0;
+ FcMemAlloc (FC_MEM_STRING, strlen (s) + 1);
+ strcpy (r, s);
+ return r;
+}
+
+char *
+FcStrPlus (const char *s1, const char *s2)
+{
+ int l = strlen (s1) + strlen (s2) + 1;
+ char *s = malloc (l);
+
+ if (!s)
+ return 0;
+ FcMemAlloc (FC_MEM_STRING, l);
+ strcpy (s, s1);
+ strcat (s, s2);
+ return s;
+}
+
+void
+FcStrFree (char *s)
+{
+ FcMemFree (FC_MEM_STRING, strlen (s) + 1);
+ free (s);
+}
+
+int
+FcStrCmpIgnoreCase (const char *s1, const char *s2)
+{
+ char c1, c2;
+
+ for (;;)
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+ if (!c1 || !c2)
+ break;
+ c1 = FcToLower (c1);
+ c2 = FcToLower (c2);
+ if (c1 != c2)
+ break;
+ }
+ return (int) c2 - (int) c1;
+}
+
+int
+FcUtf8ToUcs4 (FcChar8 *src_orig,
+ FcChar32 *dst,
+ int len)
+{
+ FcChar8 *src = src_orig;
+ FcChar8 s;
+ int extra;
+ FcChar32 result;
+
+ if (len == 0)
+ return 0;
+
+ s = *src++;
+ len--;
+
+ if (!(s & 0x80))
+ {
+ result = s;
+ extra = 0;
+ }
+ else if (!(s & 0x40))
+ {
+ return -1;
+ }
+ else if (!(s & 0x20))
+ {
+ result = s & 0x1f;
+ extra = 1;
+ }
+ else if (!(s & 0x10))
+ {
+ result = s & 0xf;
+ extra = 2;
+ }
+ else if (!(s & 0x08))
+ {
+ result = s & 0x07;
+ extra = 3;
+ }
+ else if (!(s & 0x04))
+ {
+ result = s & 0x03;
+ extra = 4;
+ }
+ else if ( ! (s & 0x02))
+ {
+ result = s & 0x01;
+ extra = 5;
+ }
+ else
+ {
+ return -1;
+ }
+ if (extra > len)
+ return -1;
+
+ while (extra--)
+ {
+ result <<= 6;
+ s = *src++;
+
+ if ((s & 0xc0) != 0x80)
+ return -1;
+
+ result |= s & 0x3f;
+ }
+ *dst = result;
+ return src - src_orig;
+}
+
+FcBool
+FcUtf8Len (FcChar8 *string,
+ int len,
+ int *nchar,
+ int *wchar)
+{
+ int n;
+ int clen;
+ FcChar32 c;
+ FcChar32 max;
+
+ n = 0;
+ max = 0;
+ while (len)
+ {
+ clen = FcUtf8ToUcs4 (string, &c, len);
+ if (clen <= 0) /* malformed UTF8 string */
+ return FcFalse;
+ if (c > max)
+ max = c;
+ string += clen;
+ len -= clen;
+ n++;
+ }
+ *nchar = n;
+ if (max >= 0x10000)
+ *wchar = 4;
+ else if (max > 0x100)
+ *wchar = 2;
+ else
+ *wchar = 1;
+ return FcTrue;
+}
diff --git a/src/fcxml.c b/src/fcxml.c
new file mode 100644
index 0000000..07e24df
--- /dev/null
+++ b/src/fcxml.c
@@ -0,0 +1,1032 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdarg.h>
+#include "fcint.h"
+
+static xmlParserInputPtr
+FcEntityLoader (const char *url, const char *id, xmlParserCtxtPtr ctxt)
+{
+ xmlParserInputPtr ret;
+ char *file;
+
+ file = FcConfigFilename (url);
+ if (!file)
+ return 0;
+ ret = xmlNewInputFromFile (ctxt, file);
+ free (file);
+ return ret;
+}
+
+xmlDocPtr
+FcConfigLoad (const char *file)
+{
+ xmlDocPtr doc;
+ xmlExternalEntityLoader previous;
+
+ previous = xmlGetExternalEntityLoader ();
+ xmlSetExternalEntityLoader (FcEntityLoader);
+ doc = xmlParseFile (file);
+ xmlSetExternalEntityLoader (previous);
+ return doc;
+}
+
+#if 0
+int
+FcConfigSave (char *file, xmlDocPtr doc)
+{
+}
+#endif
+
+FcTest *
+FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr)
+{
+ FcTest *test = (FcTest *) malloc (sizeof (FcTest));;
+
+ if (test)
+ {
+ test->next = 0;
+ test->qual = qual;
+ test->field = FcStrCopy (field);
+ test->op = compare;
+ test->expr = expr;
+ }
+ return test;
+}
+
+void
+FcTestDestroy (FcTest *test)
+{
+ if (test->next)
+ FcTestDestroy (test->next);
+ FcExprDestroy (test->expr);
+ FcStrFree ((FcChar8 *) test->field);
+ free (test);
+}
+
+FcExpr *
+FcExprCreateInteger (int i)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpInteger;
+ e->u.ival = i;
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateDouble (double d)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpDouble;
+ e->u.dval = d;
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateString (const char *s)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpString;
+ e->u.sval = FcStrCopy (s);
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateMatrix (const FcMatrix *m)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpMatrix;
+ e->u.mval = FcMatrixCopy (m);
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateBool (FcBool b)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpBool;
+ e->u.bval = b;
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateNil (void)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpNil;
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateField (const char *field)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpField;
+ e->u.field = FcStrCopy (field);
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateConst (const char *constant)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = FcOpConst;
+ e->u.constant = FcStrCopy (constant);
+ }
+ return e;
+}
+
+FcExpr *
+FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
+{
+ FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+ if (e)
+ {
+ e->op = op;
+ e->u.tree.left = left;
+ e->u.tree.right = right;
+ }
+ return e;
+}
+
+void
+FcExprDestroy (FcExpr *e)
+{
+ switch (e->op) {
+ case FcOpInteger:
+ break;
+ case FcOpDouble:
+ break;
+ case FcOpString:
+ FcStrFree (e->u.sval);
+ break;
+ case FcOpMatrix:
+ FcMatrixFree (e->u.mval);
+ break;
+ case FcOpCharSet:
+ FcCharSetDestroy (e->u.cval);
+ break;
+ case FcOpBool:
+ break;
+ case FcOpField:
+ FcStrFree (e->u.field);
+ break;
+ case FcOpConst:
+ FcStrFree (e->u.constant);
+ break;
+ case FcOpAssign:
+ case FcOpAssignReplace:
+ case FcOpPrepend:
+ case FcOpPrependFirst:
+ case FcOpAppend:
+ case FcOpAppendLast:
+ break;
+ case FcOpOr:
+ case FcOpAnd:
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpNotEqual:
+ case FcOpLess:
+ case FcOpLessEqual:
+ case FcOpMore:
+ case FcOpMoreEqual:
+ case FcOpPlus:
+ case FcOpMinus:
+ case FcOpTimes:
+ case FcOpDivide:
+ case FcOpQuest:
+ case FcOpComma:
+ FcExprDestroy (e->u.tree.right);
+ /* fall through */
+ case FcOpNot:
+ FcExprDestroy (e->u.tree.left);
+ break;
+ case FcOpNil:
+ case FcOpInvalid:
+ break;
+ }
+ free (e);
+}
+
+FcEdit *
+FcEditCreate (const char *field, FcOp op, FcExpr *expr)
+{
+ FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
+
+ if (e)
+ {
+ e->next = 0;
+ e->field = field; /* already saved in grammar */
+ e->op = op;
+ e->expr = expr;
+ }
+ return e;
+}
+
+void
+FcEditDestroy (FcEdit *e)
+{
+ if (e->next)
+ FcEditDestroy (e->next);
+ FcStrFree ((FcChar8 *) e->field);
+ if (e->expr)
+ FcExprDestroy (e->expr);
+}
+
+char *
+FcConfigSaveField (const char *field)
+{
+ return FcStrCopy (field);
+}
+
+static void
+FcConfigParseError (char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ fprintf (stderr, "font configuration error: ");
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+static char *
+FcConfigContent (xmlDocPtr doc,
+ xmlNodePtr node)
+{
+ char *content;
+
+ content = xmlNodeListGetString (doc, node->children, 1);
+ if (!content)
+ {
+ FcConfigParseError ("<%s> must have content",
+ node->name);
+ return FcFalse;
+ }
+ return content;
+}
+
+static char *
+FcConfigAttr (xmlDocPtr doc,
+ xmlAttrPtr attr)
+{
+ char *content;
+
+ content = xmlNodeListGetString (doc, attr->children, 1);
+ if (!content)
+ {
+ FcConfigParseError ("attribute %s must have a value",
+ attr->name);
+ return FcFalse;
+ }
+ return content;
+}
+
+static struct {
+ char *name;
+ FcOp op;
+} fcOps[] = {
+ { "int", FcOpInteger },
+ { "double", FcOpDouble },
+ { "string", FcOpString },
+ { "matrix", FcOpMatrix },
+ { "bool", FcOpBool },
+ { "charset", FcOpCharSet },
+ { "name", FcOpField },
+ { "const", FcOpConst },
+ { "field", FcOpField },
+ { "if", FcOpQuest },
+ { "or", FcOpOr },
+ { "and", FcOpAnd },
+ { "eq", FcOpEqual },
+ { "not_eq", FcOpNotEqual },
+ { "less", FcOpLess },
+ { "less_eq", FcOpLessEqual },
+ { "more", FcOpMore },
+ { "more_eq", FcOpMoreEqual },
+ { "plus", FcOpPlus },
+ { "minus", FcOpMinus },
+ { "times", FcOpTimes },
+ { "divide", FcOpDivide },
+ { "not", FcOpNot },
+ { "assign", FcOpAssign },
+ { "assign_replace", FcOpAssignReplace },
+ { "prepend", FcOpPrepend },
+ { "prepend_first", FcOpPrependFirst },
+ { "append", FcOpAppend },
+ { "append_last", FcOpAppendLast },
+};
+
+#define NUM_OPS (sizeof fcOps / sizeof fcOps[0])
+
+static FcOp
+FcConfigLexOp (const char *op)
+{
+ int i;
+
+ for (i = 0; i < NUM_OPS; i++)
+ if (!strcmp (op, fcOps[i].name)) return fcOps[i].op;
+ return FcOpInvalid;
+}
+
+static FcBool
+FcConfigLexBool (const char *bool)
+{
+ if (*bool == 't' || *bool == 'T')
+ return FcTrue;
+ if (*bool == 'y' || *bool == 'Y')
+ return FcTrue;
+ if (*bool == '1')
+ return FcTrue;
+ return FcFalse;
+}
+
+static FcBool
+FcConfigParseDir (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr dir)
+{
+ char *content = FcConfigContent (doc, dir);
+
+ if (!content)
+ return FcFalse;
+ return FcConfigAddDir (config, content);
+}
+
+static FcBool
+FcConfigParseCache (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr dir)
+{
+ char *content = FcConfigContent (doc, dir);
+
+ if (!content)
+ return FcFalse;
+ return FcConfigSetCache (config, content);
+}
+
+static FcBool
+FcConfigParseInclude (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr inc)
+{
+ char *content = FcConfigContent (doc, inc);
+ xmlAttr *attr;
+ FcBool complain = FcTrue;
+
+ if (!content)
+ return FcFalse;
+
+ for (attr = inc->properties; attr; attr = attr->next)
+ {
+ if (attr->type != XML_ATTRIBUTE_NODE)
+ continue;
+ if (!strcmp (attr->name, "ignore_missing"))
+ complain = !FcConfigLexBool (FcConfigAttr (doc, attr));
+ }
+ return FcConfigParseAndLoad (config, content, complain);
+}
+
+static FcBool
+FcConfigParseBlank (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr blank)
+{
+ xmlNode *node;
+ FcChar32 ucs4;
+
+ for (node = blank->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp (node->name, "int"))
+ {
+ ucs4 = (FcChar32) strtol (FcConfigContent (doc, node), 0, 0);
+ if (!config->blanks)
+ {
+ config->blanks = FcBlanksCreate ();
+ if (!config->blanks)
+ break;
+ }
+ if (!FcBlanksAdd (config->blanks, ucs4))
+ break;
+ }
+ }
+ if (node)
+ return FcFalse;
+ return FcTrue;
+}
+
+static FcBool
+FcConfigParseConfig (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr cfg)
+{
+ xmlNode *node;
+
+ for (node = cfg->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp (node->name, "blank"))
+ {
+ if (!FcConfigParseBlank (config, doc, node))
+ break;
+ }
+ }
+ if (node)
+ return FcFalse;
+ return FcTrue;
+}
+
+static FcMatrix *
+FcConfigParseMatrix (xmlDocPtr doc,
+ xmlNodePtr node)
+{
+ static FcMatrix m;
+ enum { m_xx, m_xy, m_yx, m_yy, m_done } matrix_state = m_xx;
+ double v;
+ char *text;
+
+ FcMatrixInit (&m);
+
+ for (; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (strcmp (node->name, "double"))
+ continue;
+ text = FcConfigContent (doc, node);
+ if (!text)
+ continue;
+ v = strtod (text, 0);
+ switch (matrix_state) {
+ case m_xx: m.xx = v; break;
+ case m_xy: m.xy = v; break;
+ case m_yx: m.yx = v; break;
+ case m_yy: m.yy = v; break;
+ default: break;
+ }
+ matrix_state++;
+ }
+
+ return &m;
+}
+
+static FcExpr *
+FcConfigParseExpr (xmlDocPtr doc,
+ xmlNodePtr expr)
+{
+ FcOp op = FcConfigLexOp (expr->name);
+ xmlNodePtr node;
+ FcExpr *l = 0, *e = 0, *r = 0, *c = 0;
+
+ switch (op) {
+ case FcOpInteger:
+ l = FcExprCreateInteger (strtol (FcConfigContent (doc, expr), 0, 0));
+ break;
+ case FcOpDouble:
+ l = FcExprCreateDouble (strtod (FcConfigContent (doc, expr), 0));
+ break;
+ case FcOpString:
+ l = FcExprCreateString (FcConfigContent (doc, expr));
+ break;
+ case FcOpMatrix:
+ l = FcExprCreateMatrix (FcConfigParseMatrix (doc, expr));
+ break;
+ case FcOpBool:
+ l = FcExprCreateBool (FcConfigLexBool(FcConfigContent (doc, expr)));
+ break;
+ case FcOpCharSet:
+ /* not sure what to do here yet */
+ break;
+ case FcOpField:
+ l = FcExprCreateField (FcConfigContent (doc, expr));
+ break;
+ case FcOpConst:
+ l = FcExprCreateConst (FcConfigContent (doc, expr));
+ break;
+ case FcOpQuest:
+ for (node = expr->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ e = FcConfigParseExpr (doc, node);
+ if (!e)
+ break;
+ if (!l)
+ l = e;
+ else if (!c)
+ c = e;
+ else if (!r)
+ r = e;
+ else
+ FcExprDestroy (e);
+ }
+ e = 0;
+ if (!node && l && c && r)
+ {
+ e = FcExprCreateOp (c, FcOpQuest, r);
+ if (e)
+ {
+ r = e;
+ c = 0;
+ e = FcExprCreateOp (l, FcOpQuest, r);
+ }
+ if (!e)
+ node = expr->children;
+ }
+ if (node || !l || !c || !r || !e)
+ {
+ if (l)
+ FcExprDestroy (l);
+ if (c)
+ FcExprDestroy (c);
+ if (r)
+ FcExprDestroy (r);
+ return 0;
+ }
+ break;
+ default:
+ for (node = expr->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ e = FcConfigParseExpr (doc, node);
+ if (!e)
+ break;
+ if (!l)
+ l = e;
+ else
+ {
+ r = e;
+ e = FcExprCreateOp (l, op, r);
+ if (!e)
+ {
+ FcExprDestroy (r);
+ break;
+ }
+ l = e;
+ }
+ }
+ if (node || !l)
+ {
+ if (l)
+ FcExprDestroy (l);
+ return 0;
+ }
+ /*
+ * Special case for unary ops
+ */
+ if (!r)
+ {
+ e = FcExprCreateOp (l, op, 0);
+ if (!e)
+ {
+ FcExprDestroy (l);
+ return 0;
+ }
+ }
+ break;
+
+ case FcOpInvalid:
+ return 0;
+ }
+ return l;
+}
+
+static FcTest *
+FcConfigParseTest (xmlDocPtr doc,
+ xmlNodePtr test)
+{
+ xmlNodePtr node;
+ xmlAttrPtr attr;
+ FcQual qual = FcQualAny;
+ FcOp op = FcOpEqual;
+ char *field = 0;
+ FcExpr *expr = 0;
+
+ for (attr = test->properties; attr; attr = attr->next)
+ {
+ if (attr->type != XML_ATTRIBUTE_NODE)
+ continue;
+ if (!strcmp (attr->name, "qual"))
+ {
+ char *qual_name = FcConfigAttr (doc, attr);
+ if (!qual_name)
+ ;
+ else if (!strcmp (qual_name, "any"))
+ qual = FcQualAny;
+ else if (!strcmp (qual_name, "all"))
+ qual = FcQualAll;
+ }
+ else if (!strcmp (attr->name, "name"))
+ {
+ field = FcConfigAttr (doc, attr);
+ }
+ else if (!strcmp (attr->name, "compare"))
+ {
+ char *compare = FcConfigAttr (doc, attr);
+
+ if (!compare || (op = FcConfigLexOp (compare)) == FcOpInvalid)
+ {
+ FcConfigParseError ("Invalid comparison %s",
+ compare ? compare : "<missing>");
+ return 0;
+ }
+ }
+ }
+ if (attr)
+ return 0;
+
+ for (node = test->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ expr = FcConfigParseExpr (doc, node);
+ if (!expr)
+ return 0;
+ break;
+ }
+
+ if (!expr)
+ {
+ FcConfigParseError ("Missing test expression");
+ return 0;
+ }
+
+ return FcTestCreate (qual, field, op, expr);
+}
+
+static FcExpr *
+FcConfigParseExprList (xmlDocPtr doc,
+ xmlNodePtr expr)
+{
+ FcExpr *l, *e, *r;
+
+ if (!expr)
+ return 0;
+
+ e = FcConfigParseExprList (doc, expr->next);
+
+ if (expr->type == XML_ELEMENT_NODE)
+ {
+ r = e;
+ l = FcConfigParseExpr (doc, expr);
+ if (!l)
+ goto bail;
+ if (r)
+ {
+ e = FcExprCreateOp (l, FcOpComma, r);
+ if (!e)
+ goto bail;
+ }
+ else
+ e = l;
+ }
+
+ return e;
+bail:
+ if (l)
+ FcExprDestroy (l);
+ if (r)
+ FcExprDestroy (r);
+ return 0;
+}
+
+static FcEdit *
+FcConfigParseEdit (xmlDocPtr doc,
+ xmlNodePtr edit)
+{
+ xmlAttrPtr attr;
+ char *name = 0;
+ FcOp mode = FcOpAssign;
+ FcExpr *e;
+ FcEdit *ed;
+
+ for (attr = edit->properties; attr; attr = attr->next)
+ {
+ if (attr->type != XML_ATTRIBUTE_NODE)
+ continue;
+ if (!strcmp (attr->name, "name"))
+ name = FcConfigAttr (doc, attr);
+ else if (!strcmp (attr->name, "mode"))
+ mode = FcConfigLexOp (FcConfigAttr (doc, attr));
+ }
+
+ e = FcConfigParseExprList (doc, edit->children);
+
+ ed = FcEditCreate (name, mode, e);
+ if (!ed)
+ FcExprDestroy (e);
+ return ed;
+}
+
+static FcBool
+FcConfigParseMatch (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr match)
+{
+ xmlNodePtr node;
+ xmlAttrPtr attr;
+ FcTest *tests = 0, **prevTest = &tests, *test;
+ FcEdit *edits = 0, **prevEdit = &edits, *edit;
+ FcMatchKind kind;
+ FcBool found_kind = FcFalse;
+
+ for (node = match->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp (node->name, "test"))
+ {
+ test = FcConfigParseTest (doc, node);
+ if (!test)
+ break;
+ *prevTest = test;
+ prevTest = &test->next;
+ }
+ else if (!strcmp (node->name, "edit"))
+ {
+ edit = FcConfigParseEdit (doc, node);
+ if (!edit)
+ break;
+ *prevEdit = edit;
+ prevEdit = &edit->next;
+ }
+ }
+
+ for (attr = match->properties; attr; attr = attr->next)
+ {
+ if (attr->type != XML_ATTRIBUTE_NODE)
+ continue;
+ if (!strcmp (attr->name, "target"))
+ {
+ char *target = FcConfigAttr (doc, attr);
+ if (!target)
+ {
+ FcConfigParseError ("Missing match target");
+ break;
+ }
+ else if (!strcmp (target, "pattern"))
+ {
+ kind = FcMatchPattern;
+ found_kind = FcTrue;
+ }
+ else if (!strcmp (target, "font"))
+ {
+ kind = FcMatchFont;
+ found_kind = FcTrue;
+ }
+ }
+ }
+
+ if (node || attr || !found_kind ||
+ !FcConfigAddEdit (config, tests, edits, kind))
+ {
+ if (tests)
+ FcTestDestroy (tests);
+ if (edits)
+ FcEditDestroy (edits);
+ return FcFalse;
+ }
+
+ return FcTrue;
+}
+
+static FcExpr *
+FcConfigParseFamilies (xmlDocPtr doc,
+ xmlNodePtr family)
+{
+ FcExpr *next = 0, *this = 0, *expr = 0;
+
+ if (!family)
+ return 0;
+ next = FcConfigParseFamilies (doc, family->next);
+
+ if (family->type == XML_ELEMENT_NODE && !strcmp (family->name, "family"))
+ {
+ this = FcExprCreateString (FcConfigContent (doc, family));
+ if (!this)
+ goto bail;
+ if (next)
+ {
+ expr = FcExprCreateOp (this, FcOpComma, next);
+ if (!expr)
+ goto bail;
+ }
+ else
+ expr = this;
+ }
+ else
+ expr = next;
+ return expr;
+
+bail:
+ if (expr)
+ FcExprDestroy (expr);
+ if (this)
+ FcExprDestroy (this);
+ if (next)
+ FcExprDestroy (next);
+ return 0;
+}
+
+static FcBool
+FcConfigParseAlias (FcConfig *config,
+ xmlDocPtr doc,
+ xmlNodePtr alias)
+{
+ xmlNodePtr node;
+ FcExpr *prefer = 0, *accept = 0, *def = 0;
+ FcExpr *family;
+ FcEdit *edit = 0, *next;
+ FcTest *test;
+
+ for (node = alias->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp (node->name, "family"))
+ family = FcExprCreateString (FcConfigContent (doc, node));
+ else if (!strcmp (node->name, "prefer"))
+ prefer = FcConfigParseFamilies (doc, node->children);
+ else if (!strcmp (node->name, "accept"))
+ accept = FcConfigParseFamilies (doc, node->children);
+ else if (!strcmp (node->name, "default"))
+ def = FcConfigParseFamilies (doc, node->children);
+ }
+
+ if (prefer)
+ {
+ edit = FcEditCreate (FcConfigSaveField ("family"),
+ FcOpPrepend,
+ prefer);
+ if (edit)
+ edit->next = 0;
+ }
+ if (accept)
+ {
+ next = edit;
+ edit = FcEditCreate (FcConfigSaveField ("family"),
+ FcOpAppend,
+ accept);
+ if (edit)
+ edit->next = next;
+ }
+ if (def)
+ {
+ next = edit;
+ edit = FcEditCreate (FcConfigSaveField ("family"),
+ FcOpAppendLast,
+ def);
+ if (edit)
+ edit->next = next;
+ }
+ if (edit)
+ {
+ test = FcTestCreate (FcQualAny,
+ FcConfigSaveField ("family"),
+ FcOpEqual,
+ family);
+ if (test)
+ FcConfigAddEdit (config, test, edit, FcMatchPattern);
+ }
+ return FcTrue;
+}
+
+FcBool
+FcConfigParse (FcConfig *config,
+ xmlDocPtr doc)
+{
+ xmlNodePtr cur;
+ xmlNodePtr node;
+
+ cur = xmlDocGetRootElement (doc);
+
+ for (node = cur->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp (node->name, "dir"))
+ {
+ if (!FcConfigParseDir (config, doc, node))
+ break;
+ }
+ else if (!strcmp (node->name, "cache"))
+ {
+ if (!FcConfigParseCache (config, doc, node))
+ break;
+ }
+ else if (!strcmp (node->name, "include"))
+ {
+ if (!FcConfigParseInclude (config, doc, node))
+ break;
+ }
+ else if (!strcmp (node->name, "config"))
+ {
+ if (!FcConfigParseConfig (config, doc, node))
+ break;
+ }
+ else if (!strcmp (node->name, "match"))
+ {
+ if (!FcConfigParseMatch (config, doc, node))
+ break;
+ }
+ else if (!strcmp (node->name, "alias"))
+ {
+ if (!FcConfigParseAlias (config, doc, node))
+ break;
+ }
+ else
+ {
+ FcConfigParseError ("invalid element %s", node->name);
+ break;
+ }
+ }
+ if (node)
+ return FcFalse;
+ return FcTrue;
+}
+
+FcBool
+FcConfigParseAndLoad (FcConfig *config,
+ const char *file,
+ FcBool complain)
+{
+ xmlDocPtr doc;
+ FcBool ret;
+
+ doc = FcConfigLoad (file);
+ if (doc)
+ {
+ ret = FcConfigAddConfigFile (config, file);
+ if (ret)
+ ret = FcConfigParse (config, doc);
+ xmlFreeDoc (doc);
+ return ret;
+ }
+ if (complain)
+ {
+ if (file)
+ FcConfigParseError ("Cannot load config file \"%s\"", file);
+ else
+ FcConfigParseError ("Cannot load default config file");
+ return FcFalse;
+ }
+ return FcTrue;
+}
diff --git a/src/fontconfig.man b/src/fontconfig.man
new file mode 100644
index 0000000..eb9915f
--- /dev/null
+++ b/src/fontconfig.man
@@ -0,0 +1,1113 @@
+.\"
+.\" $XFree86: fontconfig.man,v 1.2 2000/11/30 06:59:45 keithp Exp $
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission. Keith Packard makes no
+.\" representations about the suitability of this software for any purpose. It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" 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.
+.\"
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH FONTCONFIG 3 "Version 1.0" "XFree86"
+
+.SH NAME
+fontconfig \- Font configuration and customization library
+
+.SH SYNOPSIS
+.nf
+.B #include <fontconfig/fontconfig.h>
+.B #include <fontconfig/fcfreetype.h>
+.B #include <fontconfig/fcxml.h>
+.fi
+.SH DESCRIPTION
+.B Fontconfig
+is a library designed to provide system-wide font configuration,
+customization and application access.
+
+.SH FUNCTIONAL OVERVIEW
+Fontconfig contains two essential modules, the configuration module which
+builds an internal configuration from XML files and the matching module
+which accepts font patterns and returns the nearest matching font.
+
+.SS FONT CONFIGURATION
+The configuration module consists of the FcConfig datatype, libxml2 and
+FcConfigParse which walks over an XML tree and ammends a configuration with
+data found within. From an external perspective, configuration of the
+library consists of generating a valid XML tree and feeding that to
+FcConfigParse. The only other mechanism provided to applications for
+changing the running configuration is to add fonts and directories to the
+list of application-provided font files.
+.P
+The intent is to make font configurations relatively static, and shared by
+as many applications as possible. It is hoped that this will lead to more
+stable font selection when passing names from one application to another.
+XML was chosen as a configuration file format because it provides a format
+which is easy for external agents to edit while retaining the correct
+structure and syntax.
+.P
+Font configuration is separate from font matching; applications needing to
+do their own matching can access the available fonts from the library and
+perform private matching. The intent is to permit applications to pick and
+choose appropriate functionality from the library instead of forcing them to
+choose between this library and a private configuration mechanism. The hope
+is that this will ensure that configuration of fonts for all applications
+can be centralized in one place. Centralizing font configuration will make
+simplify and regularize font installation and customization.
+
+.SS FONT PROPERTIES
+While font patterns may contain essentially any properties, there are some
+well known properties with associated types. Fontconfig uses some of these
+properties for font matching and font completion. Others are provided as a
+convenience for the applications rendering mechanism.
+.sp
+.nf
+.ta 1i 2.75i 3.5i 5.5i
+.lc \(em
+Property CPP symbol Type Description
+
+family FC_FAMILY String Font family name
+style FC_STYLE String Font style. Overrides weight and slant
+slant FC_SLANT Int Italic, oblique or roman
+weight FC_WEIGHT Int Light, medium, demibold, bold or black
+size FC_SIZE Double Point size
+pixelsize FC_PIXEL_SIZE Double Pixel size
+spacing FC_SPACING Int Proportional, monospace or charcell
+foundry FC_FOUNDRY String Font foundry name
+antialias FC_ANTIALIAS Bool Whether glyphs can be antialiased
+hinting FC_HINTING Bool Whether the rasterizer should use hinting
+verticallayout FC_VERTICAL_LAYOUT Bool Use vertical layout
+globaladvance FC_GLOBAL_ADVANCE Bool Use font global advance data
+file FC_FILE String The filename holding the font
+index FC_INDEX Int The index of the font within the file
+rasterizer FC_RASTERIZER String Which rasterizer is in use
+outline FC_OUTLINE Bool Whether the glyphs are outlines
+scalable FC_SCALABLE Bool Whether glyphs can be scaled
+scale FC_SCALE Double Scale factor for point->pixel conversions
+dpi FC_DPI Double Target dots per inch
+rgba FC_RGBA Int rgb, bgr, vrgb, vbgr - subpixel geometry
+minspace FC_MINSPACE Bool Eliminate leading from line spacing
+charset FC_CHARSET CharSet Unicode chars encoded by the font
+lang FC_LANG String List of language groups this font is designed for
+.DT
+.fi
+
+.SS FONT MATCHING
+Fontconfig performs matching by measuring the distance from a provided
+pattern to all of the available fonts in the system. The closest matching
+font is selected. This ensures that a font will always be returned, but
+doesn't ensure that it is anything like the requested pattern.
+.P
+Font matching starts with an application constructed pattern. The desired
+attributes of the resulting font are collected together in an FcPattern
+object. Each property of the pattern can contain one or more values; these
+are listed in priority order; matches earlier in the list are considered
+"closer" than matches later in the list.
+.P
+The initial pattern is modified by applying the list of editing instructions
+specific to patterns found in the configuration; each consists of a match
+predicate and a set of editing operations. They are executed in the order
+they appeared in the configuration. Each match causes the associated
+sequence of editing operations to be applied.
+.P
+After the pattern has been edited, a sequence of default substitutions are
+performed to canonicalize the set of available properties; this avoids the
+need for the lower layers to constantly provide default values for various
+font properties during rendering.
+.P
+The canonical font pattern is finally matched against all available fonts.
+The distance from the pattern to the font is measured for each of several
+properties: foundry, charset, antialias, family, spacing, pixelsize, style,
+slant, weight, rasterizer and outline. This list is in priority order --
+results of comparing earlier elements of this list weigh more heavily than
+later elements.
+.P
+The pattern representing that font is augmented to include any properties
+found in the pattern but not found in the font itself; this permits the
+application to pass rendering instructions or any other data through the
+matching system. Finally, the list of editing instructions specific to
+fonts found in the configuration are applied to the pattern. This modified
+pattern is returned to the application.
+.P
+The return value contains sufficient information to locate and rasterize the
+font, including the file name, pixel size and other rendering data. As
+none of the information involved pertains to the FreeType library,
+applications are free to use any rasterization engine or even to take
+the identified font file and access it directly.
+.P
+The match/edit sequences in the configuration are performed in two passes
+because there are essentially two different operations necessary -- the
+first is to modify how fonts are selected; aliasing families and adding
+suitable defaults. The second is to modify how the selected fonts are
+rasterized. Those must apply to the selected font, not the original pattern
+as false matches will often occur.
+.SS FONT NAMES
+Fontconfig provides a textual representation for patterns that the library
+can both accept and generate. The representation is in three parts, first a
+list of family names, second a list of point sizes and finally a list of
+additional properties:
+.nf
+ <families>-<point sizes>:<name1>=<values1>:<name2>=<values2>...
+.fi
+Values in a list are separated with commas. The name needn't include either
+families or point sizes; they can be elided. In addition, there are
+symbolic constants that simultaneously indicate both a name and a value.
+Here are some examples:
+.sp
+.nf
+.ta 1i 3i
+ Times-12 12 point Times Roman
+ Times-12:bold 12 point Times Bold
+ Courier:italic Courier Italic in the default size
+ Monospace:matrix=1 .1 0 1 The users preferred monospace font
+ with artificial obliquing
+.fi
+.DT
+
+.SH DATATYPES
+
+.TP
+.B FcChar8
+.TQ
+.B FcChar16
+.TQ
+.B FcChar32
+.TQ
+.B FcBool
+These are primitive datatypes; the FcChar* types hold precisely the number
+of bits stated (if supported by the C implementation). FcBool holds
+one of two CPP symbols: FcFalse or FcTrue.
+
+.TP
+.B FcMatrix
+An FcMatrix holds an affine transformation, usually used to reshape glyphs.
+A small set of matrix operations are provided to manipulate these.
+.sp
+.nf
+ typedef struct _FcMatrix {
+ double xx, xy, yx, yy;
+ } FcMatrix;
+.fi
+
+.TP
+.B FcCharSet
+An FcCharSet is an abstract type that holds the set of encoded unicode chars
+in a font. Operations to build and compare these sets are provided.
+
+.TP
+.B FcType
+Tags the kind of data stored in an FcValue.
+
+.TP
+.B FcValue
+An FcValue object holds a single value with one of a number of different
+types. The 'type' tag indicates which member is valid.
+.sp
+.nf
+ typedef struct _FcValue {
+ FcType type;
+ union {
+ const FcChar8 *s;
+ int i;
+ FcBool b;
+ double d;
+ const FcMatrix *m;
+ const FcCharSet *c;
+ } u;
+ } FcValue;
+.fi
+.P
+.ta 1i 2i 3i 4i
+.nf
+.lc \(em
+ type Union member Datatype
+ 
+ FcTypeVoid (none) (none)
+ FcTypeInteger i int
+ FcTypeDouble d double
+ FcTypeString s char *
+ FcTypeBool b b
+ FcTypeMatrix m FcMatrix *
+ FcTypeCharSet c FcCharSet *
+.fi
+.DT
+.TP
+.B FcPattern
+holds a set of names with associated value lists; each name refers to a
+property of a font. FcPatterns are used as inputs to the matching code as
+well as holding information about specific fonts. Each property can hold
+one or more values; conventionally all of the same type, although the
+interface doesn't demand that.
+
+.TP
+.B FcFontSet
+.sp
+.nf
+ typedef struct _FcFontSet {
+ int nfont;
+ int sfont;
+ FcPattern **fonts;
+ } FcFontSet;
+.fi
+An FcFontSet contains a list of FcPatterns. Internally fontconfig uses this
+data structure to hold sets of fonts. Externally, fontconfig returns the
+results of listing fonts in this format. 'nfont' holds the number of
+patterns in the 'fonts' array; 'sfont' is used to indicate the size of that
+array.
+
+.TP
+.B FcObjectSet
+.sp
+.nf
+ typedef struct _FcObjectSet {
+ int nobject;
+ int sobject;
+ const char **objects;
+ } FcObjectSet;
+.fi
+holds a set of names and is used to specify which fields from fonts are
+placed in the the list of returned patterns when listing fonts.
+
+.TP
+.B FcBlanks
+holds a list of Unicode chars which are expected to be blank; unexpectedly
+blank chars are assumed to be invalid and are elided from the charset
+associated with the font.
+
+.TP
+.B FcFileCache
+holds the per-user cache information for use while loading the font
+database. This is built automatically for the current configuration when
+that is loaded. Applications must always pass '0' when one is requested.
+
+.TP
+.B FcConfig
+holds a complete configuration of the library; there is one default
+configuration, other can be constructed from XML data structures. All
+public entry points that need global data can take an optional FcConfig*
+argument; passing 0 uses the default configuration. FcConfig objects hold two
+sets of fonts, the first contains those specified by the configuration, the
+second set holds those added by the application at run-time. Interfaces
+that need to reference a particulat set use one of the FcSetName enumerated
+values.
+
+.TP
+.B FcSetName
+Specifies one of the two sets of fonts available in a configuration;
+FcSetSystem for those fonts specified in the configuration and
+FcSetApplication which holds fonts provided by the application.
+
+.TP
+.B FcResult
+Used as a return type for functions manipulating FcPattern objects.
+.P
+.ta 1i 3i 4i
+.lc \(em
+ Result code Meaning
+.br
+ 
+.br
+ FcResultMatch Object exists with the specified ID
+.br
+ FcResultNoMatch Object doesn't exist at all
+.br
+ FcResultTypeMismatch Object exists, but the type doesn't match
+.br
+ FcResultNoId Object exists, but has fewer values than specified
+.br
+.DT
+
+.SH FUNCTIONS
+
+.SS FcMatrix
+FcMatrix structures hold an affine transformation in matrix form.
+.TP
+#define FcMatrixInit(m) ((m)->xx = (m)->yy = 1, (m)->xy = (m)->yx = 0)
+Initializes a matrix to the identify transformation.
+
+.TP
+FcMatrix *FcMatrixCopy (const FcMatrix *mat)
+Allocates a new FcMatrix and copies 'mat' into it.
+
+.TP
+FcBool FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2)
+Returns FcTrue if 'mat1' and 'mat2' are equal, else FcFalse.
+
+.TP
+void FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b)
+Multiplies 'a' and 'b' together, placing the result in
+'result'. 'result' may refer to the sam matrix as either 'a' or 'b'.
+
+.TP
+void FcMatrixRotate (FcMatrix *m, double c, double s)
+If 'c' is cos(angle) and 's' is sin(angle), FcMatrixRotate rotates the
+matrix by 'angle'.
+
+.TP
+void FcMatrixScale (FcMatrix *m, double sx, double sy)
+Scales 'm' by 'sx' in the horizontal dimension and 'sy' in the
+vertical dimension.
+
+.TP
+void FcMatrixShear (FcMatrix *m, double sh, double sv)
+Shears 'm' by 'sh' in the horizontal direction and 'sv' in the
+vertical direction.
+
+.SS FcCharSet
+An FcCharSet is a boolean array indicating a set of unicode chars. Those
+associated with a font are marked constant and cannot be edited.
+FcCharSets may be reference counted internally to reduce memory consumption;
+this may be visible to applications as the result of FcCharSetCopy may
+return it's argument, and that CharSet may remain unmodifiable.
+
+.TP
+FcCharSet *FcCharSetCreate (void)
+Creates an empty FcCharSet object.
+
+.TP
+void FcCharSetDestroy (FcCharSet *fcs)
+Frees an FcCharSet object.
+
+.TP
+FcBool FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
+Adds a single unicode char to the set, returning FcFalse on
+failure, either as a result of a constant set or from running out of memory.
+
+.TP
+FcCharSet *FcCharSetCopy (FcCharSet *src)
+Makes a copy of 'src'; note that this may not actually do anything more than
+increment the reference count on 'src'.
+
+.TP
+FcBool FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
+Returns whether 'a' and 'b' contain the same set of unicode chars.
+
+.TP
+FcCharSet *FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
+Returns a set including only those chars found in both 'a' and 'b'.
+
+.TP
+FcCharSet *FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
+Returns a set including only those chars found in either 'a' or 'b'.
+
+.TP
+FcCharSet *FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
+Returns a set including only those chars found in 'a' but not 'b'.
+
+.TP
+FcBool FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
+Returns whether 'fcs' contains the char 'ucs4'.
+
+.TP
+FcChar32 FcCharSetCount (const FcCharSet *a)
+Returns the total number of unicode chars in 'a'.
+
+.TP
+FcChar32 FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
+Returns the number of chars that are in both 'a' and 'b'.
+
+.TP
+FcChar32 FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
+Returns the number of chars that are in 'a' but not in 'b'.
+
+.SS FcValue
+FcValue is a structure containing a type tag and a union of all possible
+datatypes. The tag is an enum of type
+.B FcType
+and is intended to provide a measure of run-time
+typechecking, although that depends on careful programming.
+
+.TP
+void FcValueDestroy (FcValue v)
+Frees any memory referenced by `v'. Values of type FcTypeString,
+FcTypeMatrix and FcTypeCharSet reference memory, the other types do not.
+
+.TP
+FcValue FcValueSave (FcValue v)
+Returns a copy of `v' duplicating any object referenced by it so that `v'
+may be safely destroyed without harming the new value.
+
+.SS FcPattern
+An FcPattern is an opaque type that holds both patterns to match against the
+available fonts, as well as the information about each font.
+
+.TP
+FcPattern *FcPatternCreate (void)
+Creates a pattern with no properties; used to build patterns from scratch.
+
+.TP
+void FcPatternDestroy (FcPattern *p)
+Destroys a pattern, in the process destroying all related values.
+
+.TP
+FcBool FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
+Adds a single value to the list of values associated with the property named
+`object'. If `append' is FcTrue, the value is added at the end of any
+existing list, otherwise it is inserted at the begining. `value' is saved
+(with FcValueSave) when inserted into the pattern so that the library
+retains no reference to any application-supplied data structure.
+
+.TP
+FcBool FcPatternAddInteger (FcPattern *p, const char *object, int i)
+.TQ
+FcBool FcPatternAddDouble (FcPattern *p, const char *object, double d)
+.TQ
+FcBool FcPatternAddString (FcPattern *p, const char *object, const char *s)
+.TQ
+FcBool FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
+.TQ
+FcBool FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
+.TQ
+FcBool FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
+These are all convenience functions that insert objects of the specified
+type into the pattern. Use these in preference to FcPatternAdd as they
+will provide compile-time typechecking. These all append values to
+any existing list of values.
+
+.TP
+FcResult FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
+Returns in `v' the `id'th value associated with the property `object'.
+The value returned is not a copy, but rather refers to the data stored
+within the pattern directly. Applications must not free this value.
+
+.TP
+FcResult FcPatternGetInteger (FcPattern *p, const char *object, int n, int *i);
+.TQ
+FcResult FcPatternGetDouble (FcPattern *p, const char *object, int n, double *d);
+.TQ
+FcResult FcPatternGetString (FcPattern *p, const char *object, int n, char **const s);
+.TQ
+FcResult FcPatternGetMatrix (FcPattern *p, const char *object, int n, FcMatrix **s);
+.TQ
+FcResult FcPatternGetCharSet (FcPattern *p, const char *object, int n, FcCharSet **c);
+.TQ
+FcResult FcPatternGetBool (FcPattern *p, const char *object, int n, FcBool *b);
+These are convenience functions that call FcPatternGet and verify that the
+returned data is of the expected type. They return FcResultTypeMismatch if
+this is not the case. Note that these (like FcPatternGet) do not make a
+copy of any data structure referenced by the return value. Use these
+in preference to FcPatternGet to provide compile-time typechecking.
+
+.TP
+FcPattern *FcPatternBuild (FcPattern *orig, ...);
+.TQ
+FcPattern *FcPatternVaBuild (FcPattern *orig, va_list va)
+Builds a pattern using a list of objects, types and values. Each
+value to be entered in the pattern is specified with three arguments:
+.IP
+1. Object name, a string describing the property to be added.
+.IP
+2. Object type, one of the FcType enumerated values
+.IP
+3. Value, not an FcValue, but the raw type as passed to any of the
+FcPatternAdd<type> functions. Must match the type of the second argument.
+.IP
+The argument list is terminated by a null object name, no object type nor
+value need be passed for this. The values are added to `pattern', if
+`pattern' is null, a new pattern is created. In either case, the pattern is
+returned. Example:
+.RS
+.IP
+pattern = FcPatternBuild (0, FC_FAMILY, FtTypeString, "Times", (char *) 0);
+.RE
+.IP
+FcPatternVaBuild is used when the arguments are already in the form of a
+varargs value.
+
+.TP
+FcBool FcPatternDel (FcPattern *p, const char *object)
+Deletes all values associated with the property `object', returning
+whether the property existed or not.
+
+.TP
+void FcPatternPrint (FcPattern *p)
+Prints an easily readable version of the pattern to stdout. There is
+no provision for reparsing data in this format, it's just for diagnostics
+and debugging.
+
+.TP
+void FcDefaultSubstitute (FcPattern *pattern)
+Supplies default values for underspecified font patterns:
+.RS
+.IP \(bu
+Patterns without a specified style or weight are set to Medium
+.IP \(bu
+Patterns without a specified style or slant are set to Roman
+.IP \(bu
+Patterns without a specified pixel size are given one computed from
+any specified point size (default 12), dpi (default 75) and scale (default
+1).
+.RE
+
+.TP
+FcPattern *FcNameParse (const char *name)
+Converts 'name' from the standard text format described above into a pattern.
+
+.TP
+FcChar8 *FcNameUnparse (FcPattern *pat)
+Converts the given pattern into the standard text format described above.
+The return value is not static, but instead refers to newly allocated memory
+which should be freed by the caller.
+
+.SS FcFontSet
+An FcFontSet simply holds a list of patterns; these are used to return the
+results of listing available fonts.
+.TP
+FcFontSet *FcFontSetCreate (void)
+Creates an empty font set.
+
+.TP
+void FcFontSetDestroy (FcFontSet *s);
+Destroys a font set. Note that this destroys any referenced patterns as
+well.
+
+.TP
+FcBool FcFontSetAdd (FcFontSet *s, FcPattern *font)
+Adds a pattern to a font set. Note that the pattern is not copied before
+being inserted into the set.
+
+.SS FcObjectSet
+An FcObjectSet holds a list of pattern property names; it is used to
+indiciate which properties are to be returned in the patterns from
+FcFontList.
+
+.TP
+FcObjectSet *FcObjectSetCreate (void)
+Creates an empty set.
+
+.TP
+FcBool FcObjectSetAdd (FcObjectSet *os, const char *object)
+Adds a proprety name to the set.
+
+.TP
+void FcObjectSetDestroy (FcObjectSet *os)
+Destroys an object set.
+
+
+.TP
+FcObjectSet *FcObjectSetBuild (const char *first, ...)
+.TQ
+FcObjectSet *FcObjectSetVaBuild (const char *first, va_list va)
+These build an object set from a null-terminated list of property names.
+
+.SS FcBlanks
+An FcBlanks object holds a list of Unicode chars which are expected to
+be blank when drawn. When scanning new fonts, any glyphs which are
+empty and not in this list will be assumed to be broken and not placed in
+the FcCharSet associated with the font. This provides a significantly more
+accurate CharSet for applications.
+
+.TP
+FcBlanks *FcBlanksCreate (void)
+Creates an empty FcBlanks object.
+
+.TP
+void FcBlanksDestroy (FcBlanks *b)
+Destroys an FcBlanks object, freeing any associated memory.
+
+.TP
+FcBool FcBlanksAdd (FcBlanks *b, FcChar32 ucs4)
+Adds a single character to an FcBlanks object, returning FcFalse
+if this process ran out of memory.
+
+.TP
+FcBool FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4)
+Returns whether the specified FcBlanks object contains the indicated Unicode
+value.
+
+.SS FcConfig
+An FcConfig object holds the internal representation of a configuration.
+There is a default configuration which applications may use by passing 0 to
+any function using the data within an FcConfig.
+
+.TP
+FcConfig *FcConfigCreate (void)
+Creates an empty configuration.
+
+.TP
+void FcConfigDestroy (FcConfig *config)
+Destroys a configuration and any data associated with it. Note that calling
+this function with the return from FcConfigGetCurrent will place the library
+in an indeterminate state.
+
+.TP
+FcBool FcConfigSetCurrent (FcConfig *config)
+Sets the current default configuration to 'config'. Implicitly calls
+FcConfigBuildFonts if necessary, returning FcFalse if that call fails.
+
+.TP
+FcConfig *FcConfigGetCurrent (void)
+Returns the current default configuration.
+
+.TP
+FcBool FcConfigBuildFonts (FcConfig *config)
+Builds the set of available fonts for the given configuration. Note that
+any changes to the configuration after this call have indeterminate effects.
+Returns FcFalse if this operation runs out of memory.
+
+.TP
+char **FcConfigGetDirs (FcConfig *config)
+Returns the list of font directories specified in 'config'.
+
+.TP
+char **FcConfigGetConfigFiles (FcConfig *config)
+Returns the list of known configuration files used to generate 'config'.
+Note that this will not include any configuration done with FcConfigParse.
+
+.TP
+char *FcConfigGetCache (FcConfig *config)
+Returns the name of the file used to store per-user font information.
+
+.TP
+FcFontSet *FcConfigGetFonts (FcConfig *config, FcSetName set)
+Returns one of the two sets of fonts from the configuration as specified
+by 'set'.
+
+.TP
+FcBlanks *FcConfigGetBlanks (FcConfig *config)
+Returns the FcBlanks object associated with the given configuration, if no
+blanks were present in the configuration, this function will return 0.
+
+.TP
+FcBool FcConfigAppFontAddFile (FcConfig *config, const char *file)
+Adds an application-specific font to the configuration.
+
+.TP
+FcBool FcConfigAppFontAddDir (FcConfig *config, const char *dir)
+Scans the specified directory for fonts, adding each one found to the
+application-specific set of fonts.
+
+.TP
+void FcConfigAppFontClear (FcConfig *config)
+Clears the set of application-specific fonts.
+
+.TP
+FcBool FcConfigSubstitute (FcConfig *config, FcPattern *p, FcMatchKind kind)
+Performs the sequence of pattern modification operations, if 'kind' is
+FcMatchPattern, then those tagged as pattern operations are applied, else
+if 'kind' is FcMatchFont, those tagged as font operations are applied.
+
+.TP
+FcPattern *FcFontMatch (FcConfig *config, FcPattern *p, FcResult *result)
+Returns the font in 'config' most close matching 'p'. This function
+should be called only after FcConfigSubstitute and FcDefaultSubstitute have
+been called; otherwise the results will be less useful.
+
+.TP
+FcFontSet *FcFontList (FcConfig *config, FcPattern *p, FcObjectSet *os)
+Selects fonts matching 'p', creates patterns from those fonts containing
+only the objects in 'os' and returns the set of unique such patterns.
+
+.TP
+char *FcConfigFilename (const char *name)
+Given the specified external entity name, return the associated filename.
+This provides applications a way to convert various configuration file
+references into filename form.
+.P
+A null or empty 'name' indicates that the default configuration file should
+be used; which file this references can be overridden with the
+FC_CONFIG_FILE environment variable. Next, if the name starts with '~', it
+refers to a file in the current users home directory. Otherwise if the name
+doesn't start with '/', it refers to a file in the default configuration
+directory; the built-in default directory can be overridden with the
+FC_CONFIG_DIR environment variable.
+
+.SS Initialization
+These functions provide some control over how the library is initialized.
+
+.TP
+FcBool FcInitConfig (void)
+Initializes the default configuration using the default configuration file
+
+.TP
+FcBool FcInitFonts (void)
+Initializes the set of fonts available in the default configuration
+
+.TP
+FcBool FcInit (void)
+Calls FcInitConfig and FcInitFonts to completely initialize the default
+configuration.
+
+.SS FreeType specific functions
+.nf
+.B #include <fontconfig/fcfreetype.h>
+.fi
+While the fontconfig library doesn't insist that FreeType be used as the
+rasterization mechanism for fonts, it does provide some convenience
+functions.
+
+.TP
+FT_UInt FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
+Maps a Unicode char to a glyph index. This function uses information from
+several possible underlying encoding tables to work around broken fonts.
+As a result, this function isn't designed to be used in performance
+sensitive areas; results from this function are intended to be cached by
+higher level functions.
+
+.TP
+FcCharSet *FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks) Scans a
+FreeType face and returns the set of encoded Unicode chars. This scans
+several encoding tables to build as complete a list as possible. If
+'blanks' is not 0, the glyphs in the font are examined and any blank glyphs
+not in 'blanks' are not placed in the returned FcCharSet.
+
+.TP
+FcPattern *FcFreeTypeQuery (const char *file, int id, FcBlanks *blanks, int *count)
+Constructs a pattern representing the 'id'th font in 'file'. The number
+of fonts in 'file' is returned in 'count'.
+
+.SS XML specific functions
+.nf
+.B #include <fontconfig/fcxml.h>
+.fi
+These functions expose the libxml2 datatypes used for font configuration.
+
+.TP
+xmlDocPtr FcConfigLoad (const char *file)
+Loads a configuration file mapping 'file' into a filename with
+FcConfigFilename. This doesn't load a complete configuration as any
+include files referenced from 'file' will not be loaded.
+
+.TP
+FcBool FcConfigParse (FcConfig *config, xmlDocPtr doc)
+Walks the given configuration and constructs the internal representation in
+'config'. Any include files referenced from within 'doc' will be loaded
+with FcConfigLoad and also parsed.
+
+.SS File and Directory routines
+
+.TP
+FcBool FcFileScan (FcFontSet *set, FcFileCache *cache, FcBlanks *blanks, const char *file, FcBool force)
+Scans a single file and adds all fonts found to 'set'. If 'force' is FcTrue,
+then the file is scanned even if associated information is found in 'cache'.
+
+.TP
+FcBool FcDirScan (FcFontSet *set, FcFileCache *cache, FcBlanks *blanks, const char *dir, FcBool force)
+Scans an entire directory and adds all fonts found to 'set'. If 'force' is
+FcTrue, then the directory and all files within it are scanned even if
+information is present in the per-directory cache file or 'cache'.
+
+.TP
+FcBool FcDirSave (FcFontSet *set, const char *dir)
+Creates the per-directory cache file for 'dir' and populates it with the
+fonts in 'set'.
+
+.SS String utilities
+
+.TP
+int FcUtf8ToUcs4 (FcChar8 *src, FcChar32 *dst, int len)
+Converts the next Unicode char from 'src' into 'dst' and returns the number
+of bytes containing the char. 'src' nust be at least 'len' bytes long.
+
+.TP
+FcBool FcUtf8Len (FcChar8 *string, int len, int *nchar, int *wchar)
+Counts the number of Unicode chars in 'len' bytes of 'string'. Places that
+count in 'nchar'. 'wchar' contains 1, 2 or 4 depending on the number of
+bytes needed to hold the largest unicode char counted. The return value
+indicates whether 'string' is a well-formed UTF8 string.
+
+.TP
+char *FcStrCopy (const char *s)
+Allocates memory, copies 's' and returns the resulting buffer. Yes, this is
+'strdup', but that function isn't available on every platform.
+
+.TP
+int FcStrCmpIgnoreCase (const char *s1, const char *s2)
+Returns the usual <0, 0, >0 result of comparing 's1' and 's2'. This test
+is case-insensitive in the ASCII range and will operate properly with UTF8
+encoded strings, although it does not check for well formed strings.
+
+.SH CONFIGURATION FILE FORMAT
+Configuration files for fontconfig are stored in XML format; this
+format makes external configuration tools easier to write and ensures that
+they will generate syntactically correct configuration files. As XML
+files are plain text, they can also be manipulated by the expert user using
+a text editor.
+.P
+The fontconfig document type definition resides in the external entity
+"fonts.dtd"; this is normally stored in the default font configuration
+directory (/etc/fonts). Each configuration file should contain the
+following structure:
+.sp
+.nf
+ <?xml version="1.0"?>
+ <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+ <fontconfig>
+ ...
+ </fontconfig>
+.fi
+.P
+.SS <fontconfig>
+This is the top level element for a font configuration and can contain
+<dir>, <cache>, <include>, <match> and <alias> elements in any order.
+
+.SS <dir>
+This element contains a directory name which will be scanned for font files
+to include in the set of available fonts.
+
+.SS <cache>
+This element contains a file name for the per-user cache of font
+information. If it starts with '~', it refers to a file in the users
+home directory. This file is used to hold information about fonts that
+isn't present in the per-directory cache files. It is automatically
+maintained by the fontconfig library. The default for this file
+is ``~/.fonts.cache''.
+
+.SS <include ignore_missing="no">
+This element contains the name of an additional configuration file. When
+the XML datatype is traversed by FcConfigParse, the contents of the file
+will also be incorporated into the configuration by passing the filename to
+FcConfigLoadAndParse. If 'ignore_missing' is set to "yes" instead of the
+default "no", a missing file will elicit no warning message from the library.
+
+.SS <match target="pattern">
+This element holds first a (possibly empty) list of tests and then a
+(possibly empty) list of edits. Patterns which match all of the tests are
+subjected to all the edits. If 'target' is set to "font" instead of the
+default "pattern", then this element applies to the font name resulting from
+a match rather than a font pattern to be matched.
+
+.SS <test qual="any" name="property" compare="eq">
+This element contains a single value which is compared with the pattern
+property "property" (substitute any of the property names seen above).
+'compare' can be one of "eq", "not_eq", "less", "less_eq", "more", or
+"more_eq". 'qual' may either be the default, "any", in which case the match
+succeeds if any value associated with the property matches the test value, or
+"all", in which case all of the values associated with the property must
+match the test value.
+
+.SS <edit name="property" mode="assign">
+This element contains a list of expression elements (any of the value or
+operator elements). The expression elements are evaluated at run-time and
+modify the property "property". The modification depends on whether
+"property" was matched by one of the associated <test> elements, if so, the
+modification may affect the first matched value. 'mode' is one of:
+.nf
+.RS
+.ta 1i 3i 5i
+Mode Operation with match Operation without match
+
+"assign" Replace matching value Replace all values
+"assign_replace" Replace all values Replace all values
+"prepend" Insert before matching value Insert at head of list
+"prepend_first" Insert at head of list Insert at head of list
+"append" Append after matching value Append at end of list
+"append_last" Append at end of list Append at end of list
+.RE
+.DT
+.fi
+.SS <int>
+.SS <double>
+.SS <string>
+.SS <bool>
+These elements hold a single value of the indicated type. <bool> elements
+hold either true or false.
+.SS <matrix>
+This element holds the four <double> elements of an affine transformation.
+.SS <name>
+Holds a property name. Evaluates to the first value from the property of
+the font, not the pattern.
+.SS <const>
+Holds the name of a constant; these are always integers and serve as
+symbolic names for common font values:
+.RS
+.sp
+.nf
+.ta 1i 2i 3i
+.lc \(em
+Constant Property CPP symbol
+
+light weight FC_WEIGHT_LIGHT
+medium weight FC_WEIGHT_MEDIUM
+demibold weight FC_WEIGHT_DEMIBOLD
+bold weight FC_WEIGHT_BOLD
+black weight FC_WEIGHT_BLACK
+roman slant FC_SLANT_ROMAN
+italic slant FC_SLANT_ITALIC
+oblique slant FC_SLANT_OBLIQUE
+proportional spacing FC_PROPORTIONAL
+mono spacing FC_MONO
+charcell spacing FC_CHARCELL
+rgb rgba FC_RGBA_RGB
+bgr rgba FC_RGBA_BGR
+vrgb rgba FC_RGBA_VRGB
+vbgr rgba FC_RGBA_VBGR
+.DT
+.fi
+.RE
+.SS <or>
+.SS <and>
+.SS <plus>
+.SS <minus>
+.SS <times>
+.SS <divide>
+These elements perform the specified operation on a list of expression
+elements. <or> and <and> are boolean, not bitwise.
+.SS <eq>
+.SS <not_eq>
+.SS <less>
+.SS <less_eq>
+.SS <more>
+.SS <more_eq>
+These elements compare two values, producing a boolean result.
+.SS <not>
+Inverts the boolean sense of its one expression element
+.SS <if>
+This element takes three expression elements; if the value of the first is
+true, it produces the value of the second, otherwise it produces the value
+of the third.
+.SS <alias>
+Alias elements provide a shorthand notation for the set of common match
+operations needed to substitute one font family for another. They contain a
+<family> element followed by optional <prefer>, <accept> and <default>
+elements. Fonts matching the <family> element are edited to prepend the
+list of <prefer>ed families before the matching <family>, append the
+<accept>able familys after the matching <family> and append the <default>
+families to the end of the family list.
+.SS <family>
+Holds a single font family name
+.SS <prefer>
+.SS <accept>
+.SS <default>
+These hold a list of <family> elements to be used by the <alias> element.
+.SH EXAMPLE CONFIGURATION FILE
+.SS System configuration file
+This is an example of a system-wide configuration file
+.sp
+.nf
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts/fonts.conf file to configure system font access -->
+<fontconfig>
+<!--
+ Find fonts in these directories
+-->
+<dir>/usr/X11R6/lib/X11/fonts/truetype</dir>
+<dir>/usr/X11R6/lib/X11/fonts/Type1</dir>
+
+<!--
+ Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+<match target="pattern">
+ <test qual="any" name="family"><string>mono</string></test>
+ <edit name="family" mode="assign"><string>monospace</string></edit>
+</match>
+
+<!--
+ Names not including any well known alias are given 'sans'
+-->
+<match target="pattern">
+ <test qual="all" name="family" mode="not_eq">sans</test>
+ <test qual="all" name="family" mode="not_eq">serif</test>
+ <test qual="all" name="family" mode="not_eq">monospace</test>
+ <edit name="family" mode="append_last"><string>sans</string></edit>
+</match>
+
+<!--
+ Load per-user customization file, but don't complain
+ if it doesn't exist
+-->
+<include ignore_missing="yes">~/.fonts.conf</include>
+
+<!--
+ Alias well known font names to available TrueType fonts.
+ These substitute TrueType faces for similar Type1
+ faces to improve screen appearance.
+-->
+<alias>
+ <family>Times</family>
+ <prefer><family>Times New Roman</family></prefer>
+ <default><family>serif</family></default>
+</alias>
+<alias>
+ <family>Helvetica</family>
+ <prefer><family>Verdana</family></prefer>
+ <default><family>sans</family></default>
+</alias>
+<alias>
+ <family>Courier</family>
+ <prefer><family>Courier New</family></prefer>
+ <default><family>monospace</family></default>
+</alias>
+
+<!--
+ Provide required aliases for standard names
+ Do these after the users configuration file so that
+ any aliases there are used preferentially
+-->
+<alias>
+ <family>serif</family>
+ <prefer><family>Times New Roman</family></prefer>
+</alias>
+<alias>
+ <family>sans</family>
+ <prefer><family>Verdana</family></prefer>
+</alias>
+<alias>
+ <family>monospace</family>
+ <prefer><family>Andale Mono</family></prefer>
+</alias>
+</fontconfig>
+.fi
+.SS User configuration file
+This is an example of a per-user configuration file that lives in
+~/.fonts.conf
+.sp
+.nf
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- ~/.fonts.conf for per-user font configuration -->
+<fontconfig>
+
+<!--
+ Private font directory
+-->
+<dir>~/misc/fonts</dir>
+
+<!--
+ use rgb sub-pixel ordering to improve glyph appearance on
+ LCD screens. Changes affecting rendering, but not matching
+ should always use target="font".
+-->
+<match target="font">
+ <edit name="rgba" mode="assign"><const>rgb</const></edit>
+</match>
+</fontconfig>
+.fi
+.SH FILES
+.B fonts.conf
+contains configuration information for the fontconfig library
+consisting of directories to look at for font information as well as
+instructions on editing program specified font patterns before attempting to
+match the available fonts. It is in xml format.
+
+.B fonts.dtd
+is a DTD that describes the format of the configuration files.
+
+.B ~/.fonts.conf
+is the conventional location for per-user font configuration, although the
+actual location is specified in the global fonts.conf file.
+
+.B ~/.fonts.cache
+is the conventional repository of font information that isn't found in the
+per-directory caches. This file is automatically maintained by fontconfig.
+
+.SH AUTHOR
+Keith Packard, member of the XFree86 Project, Inc.