From: Keith Packard Date: Thu, 14 Feb 2002 23:34:13 +0000 (+0000) Subject: Initial revision X-Git-Tag: v1_0_1~1 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=24330d27f88bbf387d92128d2c21e005f2563e93;p=fontconfig.git Initial revision --- 24330d27f88bbf387d92128d2c21e005f2563e93 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..9cee037 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Keith Packard 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 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 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 +#include +#include +#ifdef HAVE_CONFIG_H +#include +#else +#define HAVE_GETOPT 1 +#endif + +#if HAVE_GETOPT_LONG +#define _GNU_SOURCE +#include +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 +#include +#include +#ifdef HAVE_CONFIG_H +#include +#else +#define HAVE_GETOPT 1 +#endif + +#if HAVE_GETOPT_LONG +#define _GNU_SOURCE +#include +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/^/ /' | sed 's;$;;' 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 + +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 + +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 +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 @@ + + + + + + + + + + /usr/X11R6/lib/X11/fonts/truetype + /usr/X11R6/lib/X11/fonts/Type1 + /usr/X11R6/lib/X11/fonts/TrueType + + + + + + + mono + + + monospace + + + + + + + sans + + + sans-serif + + + + + + + + Times + serif + + + Times New Roman + serif + + + + Helvetica + sans-serif + + + Arial + sans-serif + + + Verdana + sans-serif + + + + Courier + monospace + + + Courier New + monospace + + + Andale Mono + monospace + + + + + sans-serif + + + serif + + + monospace + + + sans-serif + + + + + ~/.fonts.conf + + + + Times + Times New Roman + serif + + + Helvetica + Verdana + sans-serif + + + Arial + Verdana + sans-serif + + + Courier + Courier New + monospace + + + + + serif + + Times New Roman + Nimbus Roman No9 L + Luxi Serif + Times + + + + sans-serif + + Verdana + Nimbus Sans L + Luxi Sans + Arial + Helvetica + + + + monospace + + Andale Mono + Courier New + Nimbus Mono L + Luxi Mono + + + + + + 0x20 + 0xa0 + 0x2000 + 0x2001 + 0x2002 + 0x2003 + 0x2004 + 0x2005 + 0x2005 + 0x2006 + 0x2007 + 0x2008 + 0x2009 + 0x200a + 0x200b + 0x3000 + + + diff --git a/fonts.dtd b/fonts.dtd new file mode 100644 index 0000000..a3c987b --- /dev/null +++ b/fonts.dtd @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + +. ++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 + +#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 + +#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 +#include +#include +#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 +#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 +#include + +/* + * 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 +#include +#include "fcint.h" + +void +FcValuePrint (FcValue v) +{ + switch (v.type) { + case FcTypeVoid: + printf (" "); + 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 +#include +#include +#include +#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 +#include +#include +#include "fcint.h" +#include +#include +#include +#include + +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 +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#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 +#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 +#include +#include "fcint.h" +#include + +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 +#include +#include +#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 +#include +#include +#include +#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 +#include +#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 +#include +#include +#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 +#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 : ""); + 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 +.B #include +.B #include +.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 + -:=:=... +.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 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 +.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 +.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 + + + + ... + +.fi +.P +.SS +This is the top level element for a font configuration and can contain +, , , and elements in any order. + +.SS +This element contains a directory name which will be scanned for font files +to include in the set of available fonts. + +.SS +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 +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 +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 +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 +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 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 +.SS +.SS +.SS +These elements hold a single value of the indicated type. elements +hold either true or false. +.SS +This element holds the four elements of an affine transformation. +.SS +Holds a property name. Evaluates to the first value from the property of +the font, not the pattern. +.SS +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 +.SS +.SS +.SS +.SS +.SS +These elements perform the specified operation on a list of expression +elements. and are boolean, not bitwise. +.SS +.SS +.SS +.SS +.SS +.SS +These elements compare two values, producing a boolean result. +.SS +Inverts the boolean sense of its one expression element +.SS +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 elements provide a shorthand notation for the set of common match +operations needed to substitute one font family for another. They contain a + element followed by optional , and +elements. Fonts matching the element are edited to prepend the +list of ed families before the matching , append the +able familys after the matching and append the +families to the end of the family list. +.SS +Holds a single font family name +.SS +.SS +.SS +These hold a list of elements to be used by the element. +.SH EXAMPLE CONFIGURATION FILE +.SS System configuration file +This is an example of a system-wide configuration file +.sp +.nf + + + + + +/usr/X11R6/lib/X11/fonts/truetype +/usr/X11R6/lib/X11/fonts/Type1 + + + + mono + monospace + + + + + sans + serif + monospace + sans + + + +~/.fonts.conf + + + + Times + Times New Roman + serif + + + Helvetica + Verdana + sans + + + Courier + Courier New + monospace + + + + + serif + Times New Roman + + + sans + Verdana + + + monospace + Andale Mono + + +.fi +.SS User configuration file +This is an example of a per-user configuration file that lives in +~/.fonts.conf +.sp +.nf + + + + + + +~/misc/fonts + + + + rgb + + +.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.