From 24330d27f88bbf387d92128d2c21e005f2563e93 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 14 Feb 2002 23:34:13 +0000 Subject: [PATCH] Initial revision --- AUTHORS | 1 + COPYING | 22 + ChangeLog | 0 INSTALL | 3 + Imakefile | 25 + NEWS | 0 README | 2 + acconfig.h | 2 + configure.in | 202 ++++++ cvscompile.sh | 6 + doc/fontconfig.tex | 55 ++ fc-cache/Imakefile | 19 + fc-cache/fc-cache.c | 145 ++++ fc-cache/fc-cache.man | 45 ++ fc-list/Imakefile | 17 + fc-list/fc-list.c | 128 ++++ fc-list/fc-list.man | 36 + findfonts | 8 + fontconfig/Imakefile | 8 + fontconfig/fcfreetype.h | 34 + fontconfig/fcprivate.h | 117 +++ fontconfig/fcxml.h | 37 + fontconfig/fontconfig.h | 551 ++++++++++++++ fonts.conf.in | 191 +++++ fonts.dtd | 165 +++++ setfontdirs | 19 + src/Imakefile | 90 +++ src/fcblanks.c | 84 +++ src/fccache.c | 592 +++++++++++++++ src/fccfg.c | 1369 +++++++++++++++++++++++++++++++++++ src/fccharset.c | 1521 +++++++++++++++++++++++++++++++++++++++ src/fcdbg.c | 272 +++++++ src/fcdefault.c | 87 +++ src/fcdir.c | 178 +++++ src/fcfreetype.c | 236 ++++++ src/fcfs.c | 82 +++ src/fcinit.c | 174 +++++ src/fcint.h | 480 ++++++++++++ src/fclist.c | 442 ++++++++++++ src/fcmatch.c | 347 +++++++++ src/fcmatrix.c | 112 +++ src/fcname.c | 621 ++++++++++++++++ src/fcpat.c | 491 +++++++++++++ src/fcstr.c | 188 +++++ src/fcxml.c | 1032 ++++++++++++++++++++++++++ src/fontconfig.man | 1113 ++++++++++++++++++++++++++++ 46 files changed, 11349 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Imakefile create mode 100644 NEWS create mode 100644 README create mode 100644 acconfig.h create mode 100644 configure.in create mode 100644 cvscompile.sh create mode 100644 doc/fontconfig.tex create mode 100644 fc-cache/Imakefile create mode 100644 fc-cache/fc-cache.c create mode 100644 fc-cache/fc-cache.man create mode 100644 fc-list/Imakefile create mode 100644 fc-list/fc-list.c create mode 100644 fc-list/fc-list.man create mode 100755 findfonts create mode 100644 fontconfig/Imakefile create mode 100644 fontconfig/fcfreetype.h create mode 100644 fontconfig/fcprivate.h create mode 100644 fontconfig/fcxml.h create mode 100644 fontconfig/fontconfig.h create mode 100644 fonts.conf.in create mode 100644 fonts.dtd create mode 100755 setfontdirs create mode 100644 src/Imakefile create mode 100644 src/fcblanks.c create mode 100644 src/fccache.c create mode 100644 src/fccfg.c create mode 100644 src/fccharset.c create mode 100644 src/fcdbg.c create mode 100644 src/fcdefault.c create mode 100644 src/fcdir.c create mode 100644 src/fcfreetype.c create mode 100644 src/fcfs.c create mode 100644 src/fcinit.c create mode 100644 src/fcint.h create mode 100644 src/fclist.c create mode 100644 src/fcmatch.c create mode 100644 src/fcmatrix.c create mode 100644 src/fcname.c create mode 100644 src/fcpat.c create mode 100644 src/fcstr.c create mode 100644 src/fcxml.c create mode 100644 src/fontconfig.man 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.