diff options
author | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
commit | dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0 (patch) | |
tree | bdf833cc6a4fc9035411779e10dd9e8478201885 /fontconfig/src | |
parent | 0b40f5f4b54453a77f4b09c431f8efc6875da61f (diff) | |
download | vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.gz vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.bz2 vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.zip |
Synchronised line endinge with release branch
Diffstat (limited to 'fontconfig/src')
-rw-r--r-- | fontconfig/src/Makefile.am | 334 | ||||
-rw-r--r-- | fontconfig/src/fcatomic.c | 434 | ||||
-rw-r--r-- | fontconfig/src/fcblanks.c | 190 | ||||
-rw-r--r-- | fontconfig/src/fccache.c | 2546 | ||||
-rw-r--r-- | fontconfig/src/fccfg.c | 4216 | ||||
-rw-r--r-- | fontconfig/src/fccharset.c | 2878 | ||||
-rw-r--r-- | fontconfig/src/fcdbg.c | 812 | ||||
-rw-r--r-- | fontconfig/src/fcdefault.c | 362 | ||||
-rw-r--r-- | fontconfig/src/fcdir.c | 650 | ||||
-rw-r--r-- | fontconfig/src/fcformat.c | 2428 | ||||
-rw-r--r-- | fontconfig/src/fcfreetype.c | 6010 | ||||
-rw-r--r-- | fontconfig/src/fcfs.c | 270 | ||||
-rw-r--r-- | fontconfig/src/fcftint.h | 108 | ||||
-rw-r--r-- | fontconfig/src/fcinit.c | 578 | ||||
-rw-r--r-- | fontconfig/src/fcint.h | 2078 | ||||
-rw-r--r-- | fontconfig/src/fclang.c | 1772 | ||||
-rw-r--r-- | fontconfig/src/fclist.c | 1154 | ||||
-rw-r--r-- | fontconfig/src/fcmatch.c | 1680 | ||||
-rw-r--r-- | fontconfig/src/fcmatrix.c | 240 | ||||
-rw-r--r-- | fontconfig/src/fcname.c | 1804 | ||||
-rw-r--r-- | fontconfig/src/fcpat.c | 2534 | ||||
-rw-r--r-- | fontconfig/src/fcstr.c | 2396 | ||||
-rw-r--r-- | fontconfig/src/fcxml.c | 5614 | ||||
-rw-r--r-- | fontconfig/src/ftglue.c | 522 |
24 files changed, 20805 insertions, 20805 deletions
diff --git a/fontconfig/src/Makefile.am b/fontconfig/src/Makefile.am index 7ecbc1b62..090f9b1ab 100644 --- a/fontconfig/src/Makefile.am +++ b/fontconfig/src/Makefile.am @@ -1,167 +1,167 @@ -#
-# fontconfig/src/Makefile.am
-#
-# Copyright © 2003 Keith Packard
-#
-# Permission to use, copy, modify, distribute, and sell this software and its
-# documentation for any purpose is hereby granted without fee, provided that
-# the above copyright notice appear in all copies and that both that
-# copyright notice and this permission notice appear in supporting
-# documentation, and that the name of the author(s) not be used in
-# advertising or publicity pertaining to distribution of the software without
-# specific, written prior permission. The authors make no
-# representations about the suitability of this software for any purpose. It
-# is provided "as is" without express or implied warranty.
-#
-# THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
-# EVENT SHALL THE AUTHOR(S) 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.
-
-if OS_WIN32
-
-export_symbols = -export-symbols fontconfig.def
-
-fontconfig_def_dependency = fontconfig.def
-
-# gcc import library install/uninstall
-
-install-libtool-import-lib:
- $(INSTALL) .libs/libfontconfig.dll.a $(DESTDIR)$(libdir)
- $(INSTALL) fontconfig.def $(DESTDIR)$(libdir)/fontconfig.def
-
-uninstall-libtool-import-lib:
- -rm $(DESTDIR)$(libdir)/libfontconfig.dll.a $(DESTDIR)$(libdir)/fontconfig.def
-
-else
-
-install-libtool-import-lib:
-uninstall-libtool-import-lib:
-
-fontconfig_def_dependency =
-
-endif
-
-if MS_LIB_AVAILABLE
-
-# Microsoft import library install/uninstall
-
-noinst_DATA = fontconfig.lib
-
-fontconfig.lib : libfontconfig.la
- lib -name:libfontconfig-@LIBT_CURRENT_MINUS_AGE@.dll -def:fontconfig.def -out:$@
-
-install-ms-import-lib:
- $(INSTALL) fontconfig.lib $(DESTDIR)$(libdir)
-
-uninstall-ms-import-lib:
- -rm $(DESTDIR)$(libdir)/fontconfig.lib
-
-else
-
-install-ms-import-lib:
-uninstall-ms-import-lib:
-
-endif
-
-INCLUDES = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/src \
- $(FREETYPE_CFLAGS) \
- $(LIBXML2_CFLAGS) \
- $(EXPAT_CFLAGS) \
- $(WARN_CFLAGS) \
- -DFC_CACHEDIR='"$(FC_CACHEDIR)"' \
- -DFONTCONFIG_PATH='"$(CONFDIR)"'
-
-EXTRA_DIST = makealias
-
-noinst_HEADERS=fcint.h fcftint.h fcdeprecate.h
-
-ALIAS_FILES = fcalias.h fcaliastail.h fcftalias.h fcftaliastail.h
-
-BUILT_SOURCES = $(ALIAS_FILES) \
- ../fc-case/fccase.h \
- ../fc-glyphname/fcglyphname.h \
- ../fc-lang/fclang.h
-
-noinst_PROGRAMS = fcarch
-
-../fc-case/fccase.h:
- cd ../fc-case && $(MAKE) $(AM_MAKEFLAGS) fccase.h
-../fc-glyphname/fcglyphname.h:
- cd ../fc-glyphname && $(MAKE) $(AM_MAKEFLAGS) fcglyphname.h
-../fc-lang/fclang.h:
- cd ../fc-lang && $(MAKE) $(AM_MAKEFLAGS) fclang.h
-
-libfontconfig_la_SOURCES = \
- fcarch.h \
- fcatomic.c \
- fcblanks.c \
- fccache.c \
- fccfg.c \
- fccharset.c \
- fcdbg.c \
- fcdefault.c \
- fcdir.c \
- fcformat.c \
- fcfreetype.c \
- fcfs.c \
- fcinit.c \
- fclang.c \
- fclist.c \
- fcmatch.c \
- fcmatrix.c \
- fcname.c \
- fcpat.c \
- fcserialize.c \
- fcstr.c \
- fcxml.c \
- ftglue.h \
- ftglue.c
-
-lib_LTLIBRARIES = libfontconfig.la
-
-libfontconfig_la_LDFLAGS = \
- -version-info @LIBT_VERSION_INFO@ -no-undefined $(export_symbols)
-
-libfontconfig_la_LIBADD = $(ICONV_LIBS) $(FREETYPE_LIBS) $(LIBXML2_LIBS) $(EXPAT_LIBS)
-
-libfontconfig_la_DEPENDENCIES = $(fontconfig_def_dependency)
-
-install-data-local: install-ms-import-lib install-libtool-import-lib
-
-uninstall-local: uninstall-ms-import-lib uninstall-libtool-import-lib
-
-PUBLIC_FILES = \
- $(top_srcdir)/fontconfig/fontconfig.h \
- $(top_srcdir)/src/fcdeprecate.h \
- $(top_srcdir)/fontconfig/fcprivate.h
-
-PUBLIC_FT_FILES = \
- $(top_srcdir)/fontconfig/fcfreetype.h
-
-fcaliastail.h: fcalias.h
-
-fcalias.h: $(top_srcdir)/src/makealias $(PUBLIC_FILES)
- sh $(top_srcdir)/src/makealias "$(top_srcdir)/src" fcalias.h fcaliastail.h $(PUBLIC_FILES)
-
-fcftaliastail.h: fcftalias.h
-
-fcftalias.h: $(top_srcdir)/src/makealias $(PUBLIC_FT_FILES)
- sh $(top_srcdir)/src/makealias "$(top_srcdir)/src" fcftalias.h fcftaliastail.h $(PUBLIC_FT_FILES)
-
-CLEANFILES = $(ALIAS_FILES)
-
-fontconfig.def: $(PUBLIC_FILES) $(PUBLIC_FT_FILES)
- echo Generating $@
- (echo EXPORTS; \
- (cat $(PUBLIC_FILES) $(PUBLIC_FT_FILES) || echo 'FcERROR ()' ) | \
- grep '^Fc[^ ]* *(' | sed -e 's/ *(.*$$//' -e 's/^/ /' | \
- sort; \
- echo LIBRARY libfontconfig-@LIBT_CURRENT_MINUS_AGE@.dll; \
- echo VERSION @LIBT_CURRENT@.@LIBT_REVISION@) >$@
- @ ! grep -q FcERROR $@ || ($(RM) $@; false)
+# +# fontconfig/src/Makefile.am +# +# Copyright © 2003 Keith Packard +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of the author(s) not be used in +# advertising or publicity pertaining to distribution of the software without +# specific, written prior permission. The authors make no +# representations about the suitability of this software for any purpose. It +# is provided "as is" without express or implied warranty. +# +# THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +# EVENT SHALL THE AUTHOR(S) 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. + +if OS_WIN32 + +export_symbols = -export-symbols fontconfig.def + +fontconfig_def_dependency = fontconfig.def + +# gcc import library install/uninstall + +install-libtool-import-lib: + $(INSTALL) .libs/libfontconfig.dll.a $(DESTDIR)$(libdir) + $(INSTALL) fontconfig.def $(DESTDIR)$(libdir)/fontconfig.def + +uninstall-libtool-import-lib: + -rm $(DESTDIR)$(libdir)/libfontconfig.dll.a $(DESTDIR)$(libdir)/fontconfig.def + +else + +install-libtool-import-lib: +uninstall-libtool-import-lib: + +fontconfig_def_dependency = + +endif + +if MS_LIB_AVAILABLE + +# Microsoft import library install/uninstall + +noinst_DATA = fontconfig.lib + +fontconfig.lib : libfontconfig.la + lib -name:libfontconfig-@LIBT_CURRENT_MINUS_AGE@.dll -def:fontconfig.def -out:$@ + +install-ms-import-lib: + $(INSTALL) fontconfig.lib $(DESTDIR)$(libdir) + +uninstall-ms-import-lib: + -rm $(DESTDIR)$(libdir)/fontconfig.lib + +else + +install-ms-import-lib: +uninstall-ms-import-lib: + +endif + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + $(FREETYPE_CFLAGS) \ + $(LIBXML2_CFLAGS) \ + $(EXPAT_CFLAGS) \ + $(WARN_CFLAGS) \ + -DFC_CACHEDIR='"$(FC_CACHEDIR)"' \ + -DFONTCONFIG_PATH='"$(CONFDIR)"' + +EXTRA_DIST = makealias + +noinst_HEADERS=fcint.h fcftint.h fcdeprecate.h + +ALIAS_FILES = fcalias.h fcaliastail.h fcftalias.h fcftaliastail.h + +BUILT_SOURCES = $(ALIAS_FILES) \ + ../fc-case/fccase.h \ + ../fc-glyphname/fcglyphname.h \ + ../fc-lang/fclang.h + +noinst_PROGRAMS = fcarch + +../fc-case/fccase.h: + cd ../fc-case && $(MAKE) $(AM_MAKEFLAGS) fccase.h +../fc-glyphname/fcglyphname.h: + cd ../fc-glyphname && $(MAKE) $(AM_MAKEFLAGS) fcglyphname.h +../fc-lang/fclang.h: + cd ../fc-lang && $(MAKE) $(AM_MAKEFLAGS) fclang.h + +libfontconfig_la_SOURCES = \ + fcarch.h \ + fcatomic.c \ + fcblanks.c \ + fccache.c \ + fccfg.c \ + fccharset.c \ + fcdbg.c \ + fcdefault.c \ + fcdir.c \ + fcformat.c \ + fcfreetype.c \ + fcfs.c \ + fcinit.c \ + fclang.c \ + fclist.c \ + fcmatch.c \ + fcmatrix.c \ + fcname.c \ + fcpat.c \ + fcserialize.c \ + fcstr.c \ + fcxml.c \ + ftglue.h \ + ftglue.c + +lib_LTLIBRARIES = libfontconfig.la + +libfontconfig_la_LDFLAGS = \ + -version-info @LIBT_VERSION_INFO@ -no-undefined $(export_symbols) + +libfontconfig_la_LIBADD = $(ICONV_LIBS) $(FREETYPE_LIBS) $(LIBXML2_LIBS) $(EXPAT_LIBS) + +libfontconfig_la_DEPENDENCIES = $(fontconfig_def_dependency) + +install-data-local: install-ms-import-lib install-libtool-import-lib + +uninstall-local: uninstall-ms-import-lib uninstall-libtool-import-lib + +PUBLIC_FILES = \ + $(top_srcdir)/fontconfig/fontconfig.h \ + $(top_srcdir)/src/fcdeprecate.h \ + $(top_srcdir)/fontconfig/fcprivate.h + +PUBLIC_FT_FILES = \ + $(top_srcdir)/fontconfig/fcfreetype.h + +fcaliastail.h: fcalias.h + +fcalias.h: $(top_srcdir)/src/makealias $(PUBLIC_FILES) + sh $(top_srcdir)/src/makealias "$(top_srcdir)/src" fcalias.h fcaliastail.h $(PUBLIC_FILES) + +fcftaliastail.h: fcftalias.h + +fcftalias.h: $(top_srcdir)/src/makealias $(PUBLIC_FT_FILES) + sh $(top_srcdir)/src/makealias "$(top_srcdir)/src" fcftalias.h fcftaliastail.h $(PUBLIC_FT_FILES) + +CLEANFILES = $(ALIAS_FILES) + +fontconfig.def: $(PUBLIC_FILES) $(PUBLIC_FT_FILES) + echo Generating $@ + (echo EXPORTS; \ + (cat $(PUBLIC_FILES) $(PUBLIC_FT_FILES) || echo 'FcERROR ()' ) | \ + grep '^Fc[^ ]* *(' | sed -e 's/ *(.*$$//' -e 's/^/ /' | \ + sort; \ + echo LIBRARY libfontconfig-@LIBT_CURRENT_MINUS_AGE@.dll; \ + echo VERSION @LIBT_CURRENT@.@LIBT_REVISION@) >$@ + @ ! grep -q FcERROR $@ || ($(RM) $@; false) diff --git a/fontconfig/src/fcatomic.c b/fontconfig/src/fcatomic.c index cc16a9c96..b5f3d5aaa 100644 --- a/fontconfig/src/fcatomic.c +++ b/fontconfig/src/fcatomic.c @@ -1,217 +1,217 @@ -/*
- * fontconfig/src/fcatomic.c
- *
- * Copyright © 2002 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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.
- */
-
-/*
- * fcatomic.c
- *
- * Lock cache and configuration files for atomic update
- *
- * Uses only regular filesystem calls so it should
- * work even in the absense of functioning file locking
- *
- * On Unix, four files are used:
- * file - the data file accessed by other apps.
- * new - a new version of the data file while it's being written
- * lck - the lock file
- * tmp - a temporary file made unique with mkstemp
- *
- * Here's how it works:
- * Create 'tmp' and store our PID in it
- * Attempt to link it to 'lck'
- * Unlink 'tmp'
- * If the link succeeded, the lock is held
- *
- * On Windows, where there are no links, no tmp file is used, and lck
- * is a directory that's mkdir'ed. If the mkdir succeeds, the lock is
- * held.
- */
-
-#include "fcint.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <time.h>
-
-#ifdef _WIN32
-#undef mkdir
-#define mkdir(path,mode) _mkdir(path)
-#endif
-
-#define NEW_NAME ".NEW"
-#define LCK_NAME ".LCK"
-#define TMP_NAME ".TMP-XXXXXX"
-
-FcAtomic *
-FcAtomicCreate (const FcChar8 *file)
-{
- int file_len = strlen ((char *) file);
- int new_len = file_len + sizeof (NEW_NAME);
- int lck_len = file_len + sizeof (LCK_NAME);
- int tmp_len = file_len + sizeof (TMP_NAME);
- int total_len = (sizeof (FcAtomic) +
- file_len + 1 +
- new_len + 1 +
- lck_len + 1 +
- tmp_len + 1);
- FcAtomic *atomic = malloc (total_len);
- if (!atomic)
- return 0;
- FcMemAlloc (FC_MEM_ATOMIC, total_len);
-
- atomic->file = (FcChar8 *) (atomic + 1);
- strcpy ((char *) atomic->file, (char *) file);
-
- atomic->new = atomic->file + file_len + 1;
- strcpy ((char *) atomic->new, (char *) file);
- strcat ((char *) atomic->new, NEW_NAME);
-
- atomic->lck = atomic->new + new_len + 1;
- strcpy ((char *) atomic->lck, (char *) file);
- strcat ((char *) atomic->lck, LCK_NAME);
-
- atomic->tmp = atomic->lck + lck_len + 1;
-
- return atomic;
-}
-
-FcBool
-FcAtomicLock (FcAtomic *atomic)
-{
- int fd = -1;
- FILE *f = 0;
- int ret;
- struct stat lck_stat;
-
-#ifdef HAVE_LINK
- strcpy ((char *) atomic->tmp, (char *) atomic->file);
- strcat ((char *) atomic->tmp, TMP_NAME);
- fd = mkstemp ((char *) atomic->tmp);
- if (fd < 0)
- return FcFalse;
- f = fdopen (fd, "w");
- if (!f)
- {
- close (fd);
- unlink ((char *) atomic->tmp);
- return FcFalse;
- }
- ret = fprintf (f, "%ld\n", (long)getpid());
- if (ret <= 0)
- {
- fclose (f);
- unlink ((char *) atomic->tmp);
- return FcFalse;
- }
- if (fclose (f) == EOF)
- {
- unlink ((char *) atomic->tmp);
- return FcFalse;
- }
- ret = link ((char *) atomic->tmp, (char *) atomic->lck);
- (void) unlink ((char *) atomic->tmp);
-#else
- ret = mkdir ((char *) atomic->lck, 0600);
-#endif
- if (ret < 0)
- {
- /*
- * If the file is around and old (> 10 minutes),
- * assume the lock is stale. This assumes that any
- * machines sharing the same filesystem will have clocks
- * reasonably close to each other.
- */
- if (FcStat (atomic->lck, &lck_stat) >= 0)
- {
- time_t now = time (0);
- if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
- {
-#ifdef HAVE_LINK
- if (unlink ((char *) atomic->lck) == 0)
- return FcAtomicLock (atomic);
-#else
- if (rmdir ((char *) atomic->lck) == 0)
- return FcAtomicLock (atomic);
-#endif
- }
- }
- return FcFalse;
- }
- (void) unlink ((char *) atomic->new);
- return FcTrue;
-}
-
-FcChar8 *
-FcAtomicNewFile (FcAtomic *atomic)
-{
- return atomic->new;
-}
-
-FcChar8 *
-FcAtomicOrigFile (FcAtomic *atomic)
-{
- return atomic->file;
-}
-
-FcBool
-FcAtomicReplaceOrig (FcAtomic *atomic)
-{
-#ifdef _WIN32
- unlink (atomic->file);
-#endif
- if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
- return FcFalse;
- return FcTrue;
-}
-
-void
-FcAtomicDeleteNew (FcAtomic *atomic)
-{
- unlink ((char *) atomic->new);
-}
-
-void
-FcAtomicUnlock (FcAtomic *atomic)
-{
-#ifdef HAVE_LINK
- unlink ((char *) atomic->lck);
-#else
- rmdir ((char *) atomic->lck);
-#endif
-}
-
-void
-FcAtomicDestroy (FcAtomic *atomic)
-{
- FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) +
- strlen ((char *) atomic->file) * 4 + 4 +
- sizeof (NEW_NAME) + sizeof (LCK_NAME) +
- sizeof (TMP_NAME));
-
- free (atomic);
-}
-#define __fcatomic__
-#include "fcaliastail.h"
-#undef __fcatomic__
+/* + * fontconfig/src/fcatomic.c + * + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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. + */ + +/* + * fcatomic.c + * + * Lock cache and configuration files for atomic update + * + * Uses only regular filesystem calls so it should + * work even in the absense of functioning file locking + * + * On Unix, four files are used: + * file - the data file accessed by other apps. + * new - a new version of the data file while it's being written + * lck - the lock file + * tmp - a temporary file made unique with mkstemp + * + * Here's how it works: + * Create 'tmp' and store our PID in it + * Attempt to link it to 'lck' + * Unlink 'tmp' + * If the link succeeded, the lock is held + * + * On Windows, where there are no links, no tmp file is used, and lck + * is a directory that's mkdir'ed. If the mkdir succeeds, the lock is + * held. + */ + +#include "fcint.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> + +#ifdef _WIN32 +#undef mkdir +#define mkdir(path,mode) _mkdir(path) +#endif + +#define NEW_NAME ".NEW" +#define LCK_NAME ".LCK" +#define TMP_NAME ".TMP-XXXXXX" + +FcAtomic * +FcAtomicCreate (const FcChar8 *file) +{ + int file_len = strlen ((char *) file); + int new_len = file_len + sizeof (NEW_NAME); + int lck_len = file_len + sizeof (LCK_NAME); + int tmp_len = file_len + sizeof (TMP_NAME); + int total_len = (sizeof (FcAtomic) + + file_len + 1 + + new_len + 1 + + lck_len + 1 + + tmp_len + 1); + FcAtomic *atomic = malloc (total_len); + if (!atomic) + return 0; + FcMemAlloc (FC_MEM_ATOMIC, total_len); + + atomic->file = (FcChar8 *) (atomic + 1); + strcpy ((char *) atomic->file, (char *) file); + + atomic->new = atomic->file + file_len + 1; + strcpy ((char *) atomic->new, (char *) file); + strcat ((char *) atomic->new, NEW_NAME); + + atomic->lck = atomic->new + new_len + 1; + strcpy ((char *) atomic->lck, (char *) file); + strcat ((char *) atomic->lck, LCK_NAME); + + atomic->tmp = atomic->lck + lck_len + 1; + + return atomic; +} + +FcBool +FcAtomicLock (FcAtomic *atomic) +{ + int fd = -1; + FILE *f = 0; + int ret; + struct stat lck_stat; + +#ifdef HAVE_LINK + strcpy ((char *) atomic->tmp, (char *) atomic->file); + strcat ((char *) atomic->tmp, TMP_NAME); + fd = mkstemp ((char *) atomic->tmp); + if (fd < 0) + return FcFalse; + f = fdopen (fd, "w"); + if (!f) + { + close (fd); + unlink ((char *) atomic->tmp); + return FcFalse; + } + ret = fprintf (f, "%ld\n", (long)getpid()); + if (ret <= 0) + { + fclose (f); + unlink ((char *) atomic->tmp); + return FcFalse; + } + if (fclose (f) == EOF) + { + unlink ((char *) atomic->tmp); + return FcFalse; + } + ret = link ((char *) atomic->tmp, (char *) atomic->lck); + (void) unlink ((char *) atomic->tmp); +#else + ret = mkdir ((char *) atomic->lck, 0600); +#endif + if (ret < 0) + { + /* + * If the file is around and old (> 10 minutes), + * assume the lock is stale. This assumes that any + * machines sharing the same filesystem will have clocks + * reasonably close to each other. + */ + if (FcStat (atomic->lck, &lck_stat) >= 0) + { + time_t now = time (0); + if ((long int) (now - lck_stat.st_mtime) > 10 * 60) + { +#ifdef HAVE_LINK + if (unlink ((char *) atomic->lck) == 0) + return FcAtomicLock (atomic); +#else + if (rmdir ((char *) atomic->lck) == 0) + return FcAtomicLock (atomic); +#endif + } + } + return FcFalse; + } + (void) unlink ((char *) atomic->new); + return FcTrue; +} + +FcChar8 * +FcAtomicNewFile (FcAtomic *atomic) +{ + return atomic->new; +} + +FcChar8 * +FcAtomicOrigFile (FcAtomic *atomic) +{ + return atomic->file; +} + +FcBool +FcAtomicReplaceOrig (FcAtomic *atomic) +{ +#ifdef _WIN32 + unlink (atomic->file); +#endif + if (rename ((char *) atomic->new, (char *) atomic->file) < 0) + return FcFalse; + return FcTrue; +} + +void +FcAtomicDeleteNew (FcAtomic *atomic) +{ + unlink ((char *) atomic->new); +} + +void +FcAtomicUnlock (FcAtomic *atomic) +{ +#ifdef HAVE_LINK + unlink ((char *) atomic->lck); +#else + rmdir ((char *) atomic->lck); +#endif +} + +void +FcAtomicDestroy (FcAtomic *atomic) +{ + FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) + + strlen ((char *) atomic->file) * 4 + 4 + + sizeof (NEW_NAME) + sizeof (LCK_NAME) + + sizeof (TMP_NAME)); + + free (atomic); +} +#define __fcatomic__ +#include "fcaliastail.h" +#undef __fcatomic__ diff --git a/fontconfig/src/fcblanks.c b/fontconfig/src/fcblanks.c index eab2ecf78..a80a1344f 100644 --- a/fontconfig/src/fcblanks.c +++ b/fontconfig/src/fcblanks.c @@ -1,95 +1,95 @@ -/*
- * fontconfig/src/fcblanks.c
- *
- * Copyright © 2002 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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;
- FcMemAlloc (FC_MEM_BLANKS, sizeof (FcBlanks));
- b->nblank = 0;
- b->sblank = 0;
- b->blanks = 0;
- return b;
-}
-
-void
-FcBlanksDestroy (FcBlanks *b)
-{
- if (b->blanks)
- {
- FcMemFree (FC_MEM_BLANKS, b->sblank * sizeof (FcChar32));
- free (b->blanks);
- }
- FcMemFree (FC_MEM_BLANKS, sizeof (FcBlanks));
- 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;
- if (b->sblank)
- FcMemFree (FC_MEM_BLANKS, b->sblank * sizeof (FcChar32));
- FcMemAlloc (FC_MEM_BLANKS, sblank * sizeof (FcChar32));
- 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;
-}
-#define __fcblanks__
-#include "fcaliastail.h"
-#undef __fcblanks__
+/* + * fontconfig/src/fcblanks.c + * + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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; + FcMemAlloc (FC_MEM_BLANKS, sizeof (FcBlanks)); + b->nblank = 0; + b->sblank = 0; + b->blanks = 0; + return b; +} + +void +FcBlanksDestroy (FcBlanks *b) +{ + if (b->blanks) + { + FcMemFree (FC_MEM_BLANKS, b->sblank * sizeof (FcChar32)); + free (b->blanks); + } + FcMemFree (FC_MEM_BLANKS, sizeof (FcBlanks)); + 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; + if (b->sblank) + FcMemFree (FC_MEM_BLANKS, b->sblank * sizeof (FcChar32)); + FcMemAlloc (FC_MEM_BLANKS, sblank * sizeof (FcChar32)); + 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; +} +#define __fcblanks__ +#include "fcaliastail.h" +#undef __fcblanks__ diff --git a/fontconfig/src/fccache.c b/fontconfig/src/fccache.c index b27e3d39e..392e66f80 100644 --- a/fontconfig/src/fccache.c +++ b/fontconfig/src/fccache.c @@ -1,1273 +1,1273 @@ -/*
- * Copyright © 2000 Keith Packard
- * Copyright © 2005 Patrick Lam
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include "fcarch.h"
-#include <stdio.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/types.h>
-#include <assert.h>
-#if defined(HAVE_MMAP) || defined(__CYGWIN__)
-# include <unistd.h>
-# include <sys/mman.h>
-#endif
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-
-struct MD5Context {
- FcChar32 buf[4];
- FcChar32 bits[2];
- unsigned char in[64];
-};
-
-static void MD5Init(struct MD5Context *ctx);
-static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len);
-static void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
-static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
-
-#define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX))
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-#ifdef __GNUC__
-typedef long long INT64;
-#define EPOCH_OFFSET 11644473600ll
-#else
-#define EPOCH_OFFSET 11644473600i64
-typedef __int64 INT64;
-#endif
-
-/* Workaround for problems in the stat() in the Microsoft C library:
- *
- * 1) stat() uses FindFirstFile() to get the file
- * attributes. Unfortunately this API doesn't return correct values
- * for modification time of a directory until some time after a file
- * or subdirectory has been added to the directory. (This causes
- * run-test.sh to fail, for instance.) GetFileAttributesEx() is
- * better, it returns the updated timestamp right away.
- *
- * 2) stat() does some strange things related to backward
- * compatibility with the local time timestamps on FAT volumes and
- * daylight saving time. This causes problems after the switches
- * to/from daylight saving time. See
- * http://bugzilla.gnome.org/show_bug.cgi?id=154968 , especially
- * comment #30, and http://www.codeproject.com/datetime/dstbugs.asp .
- * We don't need any of that, FAT and Win9x are as good as dead. So
- * just use the UTC timestamps from NTFS, converted to the Unix epoch.
- */
-
-int
-FcStat (const char *file, struct stat *statb)
-{
- WIN32_FILE_ATTRIBUTE_DATA wfad;
- char full_path_name[MAX_PATH];
- char *basename;
- DWORD rc;
-
- if (!GetFileAttributesEx (file, GetFileExInfoStandard, &wfad))
- return -1;
-
- statb->st_dev = 0;
-
- /* Calculate a pseudo inode number as a hash of the full path name.
- * Call GetLongPathName() to get the spelling of the path name as it
- * is on disk.
- */
- rc = GetFullPathName (file, sizeof (full_path_name), full_path_name, &basename);
- if (rc == 0 || rc > sizeof (full_path_name))
- return -1;
-
- rc = GetLongPathName (full_path_name, full_path_name, sizeof (full_path_name));
- statb->st_ino = FcStringHash (full_path_name);
-
- statb->st_mode = _S_IREAD | _S_IWRITE;
- statb->st_mode |= (statb->st_mode >> 3) | (statb->st_mode >> 6);
-
- if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- statb->st_mode |= _S_IFDIR;
- else
- statb->st_mode |= _S_IFREG;
-
- statb->st_nlink = 1;
- statb->st_uid = statb->st_gid = 0;
- statb->st_rdev = 0;
-
- if (wfad.nFileSizeHigh > 0)
- return -1;
- statb->st_size = wfad.nFileSizeLow;
-
- statb->st_atime = (*(INT64 *)&wfad.ftLastAccessTime)/10000000 - EPOCH_OFFSET;
- statb->st_mtime = (*(INT64 *)&wfad.ftLastWriteTime)/10000000 - EPOCH_OFFSET;
- statb->st_ctime = statb->st_mtime;
-
- return 0;
-}
-
-#else
-
-int
-FcStat (const char *file, struct stat *statb)
-{
- return stat ((char *) file, statb);
-}
-
-#endif
-
-static const char bin2hex[] = { '0', '1', '2', '3',
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
- 'c', 'd', 'e', 'f' };
-
-static FcChar8 *
-FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN])
-{
- unsigned char hash[16];
- FcChar8 *hex_hash;
- int cnt;
- struct MD5Context ctx;
-
- MD5Init (&ctx);
- MD5Update (&ctx, (const unsigned char *)dir, strlen ((const char *) dir));
-
- MD5Final (hash, &ctx);
-
- cache_base[0] = '/';
- hex_hash = cache_base + 1;
- for (cnt = 0; cnt < 16; ++cnt)
- {
- hex_hash[2*cnt ] = bin2hex[hash[cnt] >> 4];
- hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf];
- }
- hex_hash[2*cnt] = 0;
- strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
-
- return cache_base;
-}
-
-FcBool
-FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
-{
- FcChar8 *cache_hashed = NULL;
- FcChar8 cache_base[CACHEBASE_LEN];
- FcStrList *list;
- FcChar8 *cache_dir;
-
- FcDirCacheBasename (dir, cache_base);
-
- list = FcStrListCreate (config->cacheDirs);
- if (!list)
- return FcFalse;
-
- while ((cache_dir = FcStrListNext (list)))
- {
- cache_hashed = FcStrPlus (cache_dir, cache_base);
- if (!cache_hashed)
- break;
- (void) unlink ((char *) cache_hashed);
- FcStrFree (cache_hashed);
- }
- FcStrListDone (list);
- /* return FcFalse if something went wrong */
- if (cache_dir)
- return FcFalse;
- return FcTrue;
-}
-
-static int
-FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
-{
- int fd;
-
-#ifdef _WIN32
- if (FcStat (cache_file, file_stat) < 0)
- return -1;
-#endif
- fd = open((char *) cache_file, O_RDONLY | O_BINARY);
- if (fd < 0)
- return fd;
-#ifndef _WIN32
- if (fstat (fd, file_stat) < 0)
- {
- close (fd);
- return -1;
- }
-#endif
- return fd;
-}
-
-/*
- * Look for a cache file for the specified dir. Attempt
- * to use each one we find, stopping when the callback
- * indicates success
- */
-static FcBool
-FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
- FcBool (*callback) (int fd, struct stat *fd_stat,
- struct stat *dir_stat, void *closure),
- void *closure, FcChar8 **cache_file_ret)
-{
- int fd = -1;
- FcChar8 cache_base[CACHEBASE_LEN];
- FcStrList *list;
- FcChar8 *cache_dir;
- struct stat file_stat, dir_stat;
- FcBool ret = FcFalse;
-
- if (FcStat (dir, &dir_stat) < 0)
- return FcFalse;
-
- FcDirCacheBasename (dir, cache_base);
-
- list = FcStrListCreate (config->cacheDirs);
- if (!list)
- return FcFalse;
-
- while ((cache_dir = FcStrListNext (list)))
- {
- FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base);
- if (!cache_hashed)
- break;
- fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
- if (fd >= 0) {
- ret = (*callback) (fd, &file_stat, &dir_stat, closure);
- close (fd);
- if (ret)
- {
- if (cache_file_ret)
- *cache_file_ret = cache_hashed;
- else
- FcStrFree (cache_hashed);
- break;
- }
- }
- FcStrFree (cache_hashed);
- }
- FcStrListDone (list);
-
- return ret;
-}
-
-#define FC_CACHE_MIN_MMAP 1024
-
-/*
- * Skip list element, make sure the 'next' pointer is the last thing
- * in the structure, it will be allocated large enough to hold all
- * of the necessary pointers
- */
-
-typedef struct _FcCacheSkip FcCacheSkip;
-
-struct _FcCacheSkip {
- FcCache *cache;
- int ref;
- intptr_t size;
- dev_t cache_dev;
- ino_t cache_ino;
- time_t cache_mtime;
- FcCacheSkip *next[1];
-};
-
-/*
- * The head of the skip list; pointers for every possible level
- * in the skip list, plus the largest level in the list
- */
-
-#define FC_CACHE_MAX_LEVEL 16
-
-static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL];
-static int fcCacheMaxLevel;
-
-#if HAVE_RANDOM
-# define FcRandom() random()
-#else
-# if HAVE_LRAND48
-# define FcRandom() lrand48()
-# else
-# if HAVE_RAND
-# define FcRandom() rand()
-# endif
-# endif
-#endif
-/*
- * Generate a random level number, distributed
- * so that each level is 1/4 as likely as the one before
- *
- * Note that level numbers run 1 <= level <= MAX_LEVEL
- */
-static int
-random_level (void)
-{
- /* tricky bit -- each bit is '1' 75% of the time */
- long int bits = FcRandom () | FcRandom ();
- int level = 0;
-
- while (++level < FC_CACHE_MAX_LEVEL)
- {
- if (bits & 1)
- break;
- bits >>= 1;
- }
- return level;
-}
-
-/*
- * Insert cache into the list
- */
-static FcBool
-FcCacheInsert (FcCache *cache, struct stat *cache_stat)
-{
- FcCacheSkip **update[FC_CACHE_MAX_LEVEL];
- FcCacheSkip *s, **next;
- int i, level;
-
- /*
- * Find links along each chain
- */
- next = fcCacheChains;
- for (i = fcCacheMaxLevel; --i >= 0; )
- {
- for (; (s = next[i]); next = s->next)
- if (s->cache > cache)
- break;
- update[i] = &next[i];
- }
-
- /*
- * Create new list element
- */
- level = random_level ();
- if (level > fcCacheMaxLevel)
- {
- level = fcCacheMaxLevel + 1;
- update[fcCacheMaxLevel] = &fcCacheChains[fcCacheMaxLevel];
- fcCacheMaxLevel = level;
- }
-
- s = malloc (sizeof (FcCacheSkip) + (level - 1) * sizeof (FcCacheSkip *));
- if (!s)
- return FcFalse;
-
- s->cache = cache;
- s->size = cache->size;
- s->ref = 1;
- if (cache_stat)
- {
- s->cache_dev = cache_stat->st_dev;
- s->cache_ino = cache_stat->st_ino;
- s->cache_mtime = cache_stat->st_mtime;
- }
- else
- {
- s->cache_dev = 0;
- s->cache_ino = 0;
- s->cache_mtime = 0;
- }
-
- /*
- * Insert into all fcCacheChains
- */
- for (i = 0; i < level; i++)
- {
- s->next[i] = *update[i];
- *update[i] = s;
- }
- return FcTrue;
-}
-
-static FcCacheSkip *
-FcCacheFindByAddr (void *object)
-{
- int i;
- FcCacheSkip **next = fcCacheChains;
- FcCacheSkip *s;
-
- /*
- * Walk chain pointers one level at a time
- */
- for (i = fcCacheMaxLevel; --i >= 0;)
- while (next[i] && (char *) object >= ((char *) next[i]->cache + next[i]->size))
- next = next[i]->next;
- /*
- * Here we are
- */
- s = next[0];
- if (s && (char *) object < ((char *) s->cache + s->size))
- return s;
- return NULL;
-}
-
-static void
-FcCacheRemove (FcCache *cache)
-{
- FcCacheSkip **update[FC_CACHE_MAX_LEVEL];
- FcCacheSkip *s, **next;
- int i;
-
- /*
- * Find links along each chain
- */
- next = fcCacheChains;
- for (i = fcCacheMaxLevel; --i >= 0; )
- {
- for (; (s = next[i]); next = s->next)
- if (s->cache >= cache)
- break;
- update[i] = &next[i];
- }
- s = next[0];
- for (i = 0; i < fcCacheMaxLevel && *update[i] == s; i++)
- *update[i] = s->next[i];
- while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
- fcCacheMaxLevel--;
- free (s);
-}
-
-static FcCache *
-FcCacheFindByStat (struct stat *cache_stat)
-{
- FcCacheSkip *s;
-
- for (s = fcCacheChains[0]; s; s = s->next[0])
- if (s->cache_dev == cache_stat->st_dev &&
- s->cache_ino == cache_stat->st_ino &&
- s->cache_mtime == cache_stat->st_mtime)
- {
- s->ref++;
- return s->cache;
- }
- return NULL;
-}
-
-static void
-FcDirCacheDispose (FcCache *cache)
-{
- switch (cache->magic) {
- case FC_CACHE_MAGIC_ALLOC:
- free (cache);
- break;
- case FC_CACHE_MAGIC_MMAP:
-#if defined(HAVE_MMAP) || defined(__CYGWIN__)
- munmap (cache, cache->size);
-#elif defined(_WIN32)
- UnmapViewOfFile (cache);
-#endif
- break;
- }
- FcCacheRemove (cache);
-}
-
-void
-FcCacheObjectReference (void *object)
-{
- FcCacheSkip *skip = FcCacheFindByAddr (object);
-
- if (skip)
- skip->ref++;
-}
-
-void
-FcCacheObjectDereference (void *object)
-{
- FcCacheSkip *skip = FcCacheFindByAddr (object);
-
- if (skip)
- {
- skip->ref--;
- if (skip->ref <= 0)
- FcDirCacheDispose (skip->cache);
- }
-}
-
-void
-FcCacheFini (void)
-{
- int i;
-
- for (i = 0; i < FC_CACHE_MAX_LEVEL; i++)
- assert (fcCacheChains[i] == NULL);
- assert (fcCacheMaxLevel == 0);
-}
-
-static FcBool
-FcCacheTimeValid (FcCache *cache, struct stat *dir_stat)
-{
- struct stat dir_static;
-
- if (!dir_stat)
- {
- if (FcStat (FcCacheDir (cache), &dir_static) < 0)
- return FcFalse;
- dir_stat = &dir_static;
- }
- if (FcDebug () & FC_DBG_CACHE)
- printf ("FcCacheTimeValid dir \"%s\" cache time %d dir time %d\n",
- FcCacheDir (cache), cache->mtime, (int) dir_stat->st_mtime);
- return cache->mtime == (int) dir_stat->st_mtime;
-}
-
-/*
- * Map a cache file into memory
- */
-static FcCache *
-FcDirCacheMapFd (int fd, struct stat *fd_stat, struct stat *dir_stat)
-{
- FcCache *cache;
- FcBool allocated = FcFalse;
-
- if (fd_stat->st_size < sizeof (FcCache))
- return NULL;
- cache = FcCacheFindByStat (fd_stat);
- if (cache)
- {
- if (FcCacheTimeValid (cache, dir_stat))
- return cache;
- FcDirCacheUnload (cache);
- cache = NULL;
- }
-
- /*
- * Lage cache files are mmap'ed, smaller cache files are read. This
- * balances the system cost of mmap against per-process memory usage.
- */
- if (fd_stat->st_size >= FC_CACHE_MIN_MMAP)
- {
-#if defined(HAVE_MMAP) || defined(__CYGWIN__)
- cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (cache == MAP_FAILED)
- cache = NULL;
-#elif defined(_WIN32)
- {
- HANDLE hFileMap;
-
- cache = NULL;
- hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
- PAGE_READONLY, 0, 0, NULL);
- if (hFileMap != NULL)
- {
- cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0,
- fd_stat->st_size);
- CloseHandle (hFileMap);
- }
- }
-#endif
- }
- if (!cache)
- {
- cache = malloc (fd_stat->st_size);
- if (!cache)
- return NULL;
-
- if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size)
- {
- free (cache);
- return NULL;
- }
- allocated = FcTrue;
- }
- if (cache->magic != FC_CACHE_MAGIC_MMAP ||
- cache->version < FC_CACHE_CONTENT_VERSION ||
- cache->size != fd_stat->st_size ||
- !FcCacheTimeValid (cache, dir_stat) ||
- !FcCacheInsert (cache, fd_stat))
- {
- if (allocated)
- free (cache);
- else
- {
-#if defined(HAVE_MMAP) || defined(__CYGWIN__)
- munmap (cache, fd_stat->st_size);
-#elif defined(_WIN32)
- UnmapViewOfFile (cache);
-#endif
- }
- return NULL;
- }
-
- /* Mark allocated caches so they're freed rather than unmapped */
- if (allocated)
- cache->magic = FC_CACHE_MAGIC_ALLOC;
-
- return cache;
-}
-
-void
-FcDirCacheReference (FcCache *cache, int nref)
-{
- FcCacheSkip *skip = FcCacheFindByAddr (cache);
-
- if (skip)
- skip->ref += nref;
-}
-
-void
-FcDirCacheUnload (FcCache *cache)
-{
- FcCacheObjectDereference (cache);
-}
-
-static FcBool
-FcDirCacheMapHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
-{
- FcCache *cache = FcDirCacheMapFd (fd, fd_stat, dir_stat);
-
- if (!cache)
- return FcFalse;
- *((FcCache **) closure) = cache;
- return FcTrue;
-}
-
-FcCache *
-FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
-{
- FcCache *cache = NULL;
-
- if (!FcDirCacheProcess (config, dir,
- FcDirCacheMapHelper,
- &cache, cache_file))
- return NULL;
- return cache;
-}
-
-FcCache *
-FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
-{
- int fd;
- FcCache *cache;
- struct stat my_file_stat;
-
- if (!file_stat)
- file_stat = &my_file_stat;
- fd = FcDirCacheOpenFile (cache_file, file_stat);
- if (fd < 0)
- return NULL;
- cache = FcDirCacheMapFd (fd, file_stat, NULL);
- close (fd);
- return cache;
-}
-
-/*
- * Validate a cache file by reading the header and checking
- * the magic number and the size field
- */
-static FcBool
-FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
-{
- FcBool ret = FcTrue;
- FcCache c;
-
- if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
- ret = FcFalse;
- else if (c.magic != FC_CACHE_MAGIC_MMAP)
- ret = FcFalse;
- else if (c.version < FC_CACHE_CONTENT_VERSION)
- ret = FcFalse;
- else if (fd_stat->st_size != c.size)
- ret = FcFalse;
- else if (c.mtime != (int) dir_stat->st_mtime)
- ret = FcFalse;
- return ret;
-}
-
-static FcBool
-FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
-{
- return FcDirCacheProcess (config, dir,
- FcDirCacheValidateHelper,
- NULL, NULL);
-}
-
-FcBool
-FcDirCacheValid (const FcChar8 *dir)
-{
- FcConfig *config;
-
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
-
- return FcDirCacheValidConfig (dir, config);
-}
-
-/*
- * Build a cache structure from the given contents
- */
-FcCache *
-FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
-{
- FcSerialize *serialize = FcSerializeCreate ();
- FcCache *cache;
- int i;
- intptr_t cache_offset;
- intptr_t dirs_offset;
- FcChar8 *dir_serialize;
- intptr_t *dirs_serialize;
- FcFontSet *set_serialize;
-
- if (!serialize)
- return NULL;
- /*
- * Space for cache structure
- */
- cache_offset = FcSerializeReserve (serialize, sizeof (FcCache));
- /*
- * Directory name
- */
- if (!FcStrSerializeAlloc (serialize, dir))
- goto bail1;
- /*
- * Subdirs
- */
- dirs_offset = FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *));
- for (i = 0; i < dirs->num; i++)
- if (!FcStrSerializeAlloc (serialize, dirs->strs[i]))
- goto bail1;
-
- /*
- * Patterns
- */
- if (!FcFontSetSerializeAlloc (serialize, set))
- goto bail1;
-
- /* Serialize layout complete. Now allocate space and fill it */
- cache = malloc (serialize->size);
- if (!cache)
- goto bail1;
- /* shut up valgrind */
- memset (cache, 0, serialize->size);
-
- serialize->linear = cache;
-
- cache->magic = FC_CACHE_MAGIC_ALLOC;
- cache->version = FC_CACHE_CONTENT_VERSION;
- cache->size = serialize->size;
- cache->mtime = (int) dir_stat->st_mtime;
-
- /*
- * Serialize directory name
- */
- dir_serialize = FcStrSerialize (serialize, dir);
- if (!dir_serialize)
- goto bail2;
- cache->dir = FcPtrToOffset (cache, dir_serialize);
-
- /*
- * Serialize sub dirs
- */
- dirs_serialize = FcSerializePtr (serialize, dirs);
- if (!dirs_serialize)
- goto bail2;
- cache->dirs = FcPtrToOffset (cache, dirs_serialize);
- cache->dirs_count = dirs->num;
- for (i = 0; i < dirs->num; i++)
- {
- FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]);
- if (!d_serialize)
- goto bail2;
- dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize);
- }
-
- /*
- * Serialize font set
- */
- set_serialize = FcFontSetSerialize (serialize, set);
- if (!set_serialize)
- goto bail2;
- cache->set = FcPtrToOffset (cache, set_serialize);
-
- FcSerializeDestroy (serialize);
-
- FcCacheInsert (cache, NULL);
-
- return cache;
-
-bail2:
- free (cache);
-bail1:
- FcSerializeDestroy (serialize);
- return NULL;
-}
-
-
-#ifdef _WIN32
-#undef mkdir
-#define mkdir(path,mode) _mkdir(path)
-#endif
-
-static FcBool
-FcMakeDirectory (const FcChar8 *dir)
-{
- FcChar8 *parent;
- FcBool ret;
-
- if (strlen ((char *) dir) == 0)
- return FcFalse;
-
- parent = FcStrDirname (dir);
- if (!parent)
- return FcFalse;
- if (access ((char *) parent, F_OK) == 0)
- ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
- else if (access ((char *) parent, F_OK) == -1)
- ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
- else
- ret = FcFalse;
- FcStrFree (parent);
- return ret;
-}
-
-/* write serialized state to the cache file */
-FcBool
-FcDirCacheWrite (FcCache *cache, FcConfig *config)
-{
- FcChar8 *dir = FcCacheDir (cache);
- FcChar8 cache_base[CACHEBASE_LEN];
- FcChar8 *cache_hashed;
- int fd;
- FcAtomic *atomic;
- FcStrList *list;
- FcChar8 *cache_dir = NULL;
- FcChar8 *test_dir;
- FcCacheSkip *skip;
- struct stat cache_stat;
- int magic;
- int written;
-
- /*
- * Write it to the first directory in the list which is writable
- */
-
- list = FcStrListCreate (config->cacheDirs);
- if (!list)
- return FcFalse;
- while ((test_dir = FcStrListNext (list))) {
- if (access ((char *) test_dir, W_OK|X_OK) == 0)
- {
- cache_dir = test_dir;
- break;
- }
- else
- {
- /*
- * If the directory doesn't exist, try to create it
- */
- if (access ((char *) test_dir, F_OK) == -1) {
- if (FcMakeDirectory (test_dir))
- {
- cache_dir = test_dir;
- break;
- }
- }
- /*
- * Otherwise, try making it writable
- */
- else if (chmod ((char *) test_dir, 0755) == 0)
- {
- cache_dir = test_dir;
- break;
- }
- }
- }
- FcStrListDone (list);
- if (!cache_dir)
- return FcFalse;
-
- FcDirCacheBasename (dir, cache_base);
- cache_hashed = FcStrPlus (cache_dir, cache_base);
- if (!cache_hashed)
- return FcFalse;
-
- if (FcDebug () & FC_DBG_CACHE)
- printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
- dir, cache_hashed);
-
- atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
- if (!atomic)
- goto bail1;
-
- if (!FcAtomicLock (atomic))
- goto bail3;
-
- fd = open((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
- if (fd == -1)
- goto bail4;
-
- /* Temporarily switch magic to MMAP while writing to file */
- magic = cache->magic;
- if (magic != FC_CACHE_MAGIC_MMAP)
- cache->magic = FC_CACHE_MAGIC_MMAP;
-
- /*
- * Write cache contents to file
- */
- written = write (fd, cache, cache->size);
-
- /* Switch magic back */
- if (magic != FC_CACHE_MAGIC_MMAP)
- cache->magic = magic;
-
- if (written != cache->size)
- {
- perror ("write cache");
- goto bail5;
- }
-
- close(fd);
- if (!FcAtomicReplaceOrig(atomic))
- goto bail4;
-
- /* If the file is small, update the cache chain entry such that the
- * new cache file is not read again. If it's large, we don't do that
- * such that we reload it, using mmap, which is shared across processes.
- */
- if (cache->size < FC_CACHE_MIN_MMAP &&
- (skip = FcCacheFindByAddr (cache)) &&
- FcStat (cache_hashed, &cache_stat))
- {
- skip->cache_dev = cache_stat.st_dev;
- skip->cache_ino = cache_stat.st_ino;
- skip->cache_mtime = cache_stat.st_mtime;
- }
-
- FcStrFree (cache_hashed);
- FcAtomicUnlock (atomic);
- FcAtomicDestroy (atomic);
- return FcTrue;
-
- bail5:
- close (fd);
- bail4:
- FcAtomicUnlock (atomic);
- bail3:
- FcAtomicDestroy (atomic);
- bail1:
- FcStrFree (cache_hashed);
- return FcFalse;
-}
-
-/*
- * Hokey little macro trick to permit the definitions of C functions
- * with the same name as CPP macros
- */
-#define args1(x) (x)
-#define args2(x,y) (x,y)
-
-const FcChar8 *
-FcCacheDir args1(const FcCache *c)
-{
- return FcCacheDir (c);
-}
-
-FcFontSet *
-FcCacheCopySet args1(const FcCache *c)
-{
- FcFontSet *old = FcCacheSet (c);
- FcFontSet *new = FcFontSetCreate ();
- int i;
-
- if (!new)
- return NULL;
- for (i = 0; i < old->nfont; i++)
- {
- FcPattern *font = FcFontSetFont (old, i);
-
- FcPatternReference (font);
- if (!FcFontSetAdd (new, font))
- {
- FcFontSetDestroy (new);
- return NULL;
- }
- }
- return new;
-}
-
-const FcChar8 *
-FcCacheSubdir args2(const FcCache *c, int i)
-{
- return FcCacheSubdir (c, i);
-}
-
-int
-FcCacheNumSubdir args1(const FcCache *c)
-{
- return c->dirs_count;
-}
-
-int
-FcCacheNumFont args1(const FcCache *c)
-{
- return FcCacheSet(c)->nfont;
-}
-
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-#ifndef HIGHFIRST
-#define byteReverse(buf, len) /* Nothing */
-#else
-/*
- * Note: this code is harmless on little-endian machines.
- */
-void byteReverse(unsigned char *buf, unsigned longs)
-{
- FcChar32 t;
- do {
- t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- *(FcChar32 *) buf = t;
- buf += 4;
- } while (--longs);
-}
-#endif
-
-/*
- * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-static void MD5Init(struct MD5Context *ctx)
-{
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
-
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
-{
- FcChar32 t;
-
- /* Update bitcount */
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
- ctx->bits[1]++; /* Carry from low to high */
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
-
- /* Handle any leading odd-sized chunks */
-
- if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
-
- t = 64 - t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
- buf += t;
- len -= t;
- }
- /* Process data in 64-byte chunks */
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
- buf += 64;
- len -= 64;
- }
-
- /* Handle any remaining bytes of data. */
-
- memcpy(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
-{
- unsigned count;
- unsigned char *p;
-
- /* Compute number of bytes mod 64 */
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- p = ctx->in + count;
- *p++ = 0x80;
-
- /* Bytes of padding needed to make 64 bytes */
- count = 64 - 1 - count;
-
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
-
- /* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
- } else {
- /* Pad block to 56 bytes */
- memset(p, 0, count - 8);
- }
- byteReverse(ctx->in, 14);
-
- /* Append length in bits and transform */
- ((FcChar32 *) ctx->in)[14] = ctx->bits[0];
- ((FcChar32 *) ctx->in)[15] = ctx->bits[1];
-
- MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
-}
-
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data. MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
-{
- register FcChar32 a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-#define __fccache__
-#include "fcaliastail.h"
-#undef __fccache__
+/* + * Copyright © 2000 Keith Packard + * Copyright © 2005 Patrick Lam + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include "fcarch.h" +#include <stdio.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <sys/types.h> +#include <assert.h> +#if defined(HAVE_MMAP) || defined(__CYGWIN__) +# include <unistd.h> +# include <sys/mman.h> +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + +struct MD5Context { + FcChar32 buf[4]; + FcChar32 bits[2]; + unsigned char in[64]; +}; + +static void MD5Init(struct MD5Context *ctx); +static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len); +static void MD5Final(unsigned char digest[16], struct MD5Context *ctx); +static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]); + +#define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX)) + +#ifdef _WIN32 + +#include <windows.h> + +#ifdef __GNUC__ +typedef long long INT64; +#define EPOCH_OFFSET 11644473600ll +#else +#define EPOCH_OFFSET 11644473600i64 +typedef __int64 INT64; +#endif + +/* Workaround for problems in the stat() in the Microsoft C library: + * + * 1) stat() uses FindFirstFile() to get the file + * attributes. Unfortunately this API doesn't return correct values + * for modification time of a directory until some time after a file + * or subdirectory has been added to the directory. (This causes + * run-test.sh to fail, for instance.) GetFileAttributesEx() is + * better, it returns the updated timestamp right away. + * + * 2) stat() does some strange things related to backward + * compatibility with the local time timestamps on FAT volumes and + * daylight saving time. This causes problems after the switches + * to/from daylight saving time. See + * http://bugzilla.gnome.org/show_bug.cgi?id=154968 , especially + * comment #30, and http://www.codeproject.com/datetime/dstbugs.asp . + * We don't need any of that, FAT and Win9x are as good as dead. So + * just use the UTC timestamps from NTFS, converted to the Unix epoch. + */ + +int +FcStat (const char *file, struct stat *statb) +{ + WIN32_FILE_ATTRIBUTE_DATA wfad; + char full_path_name[MAX_PATH]; + char *basename; + DWORD rc; + + if (!GetFileAttributesEx (file, GetFileExInfoStandard, &wfad)) + return -1; + + statb->st_dev = 0; + + /* Calculate a pseudo inode number as a hash of the full path name. + * Call GetLongPathName() to get the spelling of the path name as it + * is on disk. + */ + rc = GetFullPathName (file, sizeof (full_path_name), full_path_name, &basename); + if (rc == 0 || rc > sizeof (full_path_name)) + return -1; + + rc = GetLongPathName (full_path_name, full_path_name, sizeof (full_path_name)); + statb->st_ino = FcStringHash (full_path_name); + + statb->st_mode = _S_IREAD | _S_IWRITE; + statb->st_mode |= (statb->st_mode >> 3) | (statb->st_mode >> 6); + + if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + statb->st_mode |= _S_IFDIR; + else + statb->st_mode |= _S_IFREG; + + statb->st_nlink = 1; + statb->st_uid = statb->st_gid = 0; + statb->st_rdev = 0; + + if (wfad.nFileSizeHigh > 0) + return -1; + statb->st_size = wfad.nFileSizeLow; + + statb->st_atime = (*(INT64 *)&wfad.ftLastAccessTime)/10000000 - EPOCH_OFFSET; + statb->st_mtime = (*(INT64 *)&wfad.ftLastWriteTime)/10000000 - EPOCH_OFFSET; + statb->st_ctime = statb->st_mtime; + + return 0; +} + +#else + +int +FcStat (const char *file, struct stat *statb) +{ + return stat ((char *) file, statb); +} + +#endif + +static const char bin2hex[] = { '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' }; + +static FcChar8 * +FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN]) +{ + unsigned char hash[16]; + FcChar8 *hex_hash; + int cnt; + struct MD5Context ctx; + + MD5Init (&ctx); + MD5Update (&ctx, (const unsigned char *)dir, strlen ((const char *) dir)); + + MD5Final (hash, &ctx); + + cache_base[0] = '/'; + hex_hash = cache_base + 1; + for (cnt = 0; cnt < 16; ++cnt) + { + hex_hash[2*cnt ] = bin2hex[hash[cnt] >> 4]; + hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf]; + } + hex_hash[2*cnt] = 0; + strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX); + + return cache_base; +} + +FcBool +FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config) +{ + FcChar8 *cache_hashed = NULL; + FcChar8 cache_base[CACHEBASE_LEN]; + FcStrList *list; + FcChar8 *cache_dir; + + FcDirCacheBasename (dir, cache_base); + + list = FcStrListCreate (config->cacheDirs); + if (!list) + return FcFalse; + + while ((cache_dir = FcStrListNext (list))) + { + cache_hashed = FcStrPlus (cache_dir, cache_base); + if (!cache_hashed) + break; + (void) unlink ((char *) cache_hashed); + FcStrFree (cache_hashed); + } + FcStrListDone (list); + /* return FcFalse if something went wrong */ + if (cache_dir) + return FcFalse; + return FcTrue; +} + +static int +FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat) +{ + int fd; + +#ifdef _WIN32 + if (FcStat (cache_file, file_stat) < 0) + return -1; +#endif + fd = open((char *) cache_file, O_RDONLY | O_BINARY); + if (fd < 0) + return fd; +#ifndef _WIN32 + if (fstat (fd, file_stat) < 0) + { + close (fd); + return -1; + } +#endif + return fd; +} + +/* + * Look for a cache file for the specified dir. Attempt + * to use each one we find, stopping when the callback + * indicates success + */ +static FcBool +FcDirCacheProcess (FcConfig *config, const FcChar8 *dir, + FcBool (*callback) (int fd, struct stat *fd_stat, + struct stat *dir_stat, void *closure), + void *closure, FcChar8 **cache_file_ret) +{ + int fd = -1; + FcChar8 cache_base[CACHEBASE_LEN]; + FcStrList *list; + FcChar8 *cache_dir; + struct stat file_stat, dir_stat; + FcBool ret = FcFalse; + + if (FcStat (dir, &dir_stat) < 0) + return FcFalse; + + FcDirCacheBasename (dir, cache_base); + + list = FcStrListCreate (config->cacheDirs); + if (!list) + return FcFalse; + + while ((cache_dir = FcStrListNext (list))) + { + FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base); + if (!cache_hashed) + break; + fd = FcDirCacheOpenFile (cache_hashed, &file_stat); + if (fd >= 0) { + ret = (*callback) (fd, &file_stat, &dir_stat, closure); + close (fd); + if (ret) + { + if (cache_file_ret) + *cache_file_ret = cache_hashed; + else + FcStrFree (cache_hashed); + break; + } + } + FcStrFree (cache_hashed); + } + FcStrListDone (list); + + return ret; +} + +#define FC_CACHE_MIN_MMAP 1024 + +/* + * Skip list element, make sure the 'next' pointer is the last thing + * in the structure, it will be allocated large enough to hold all + * of the necessary pointers + */ + +typedef struct _FcCacheSkip FcCacheSkip; + +struct _FcCacheSkip { + FcCache *cache; + int ref; + intptr_t size; + dev_t cache_dev; + ino_t cache_ino; + time_t cache_mtime; + FcCacheSkip *next[1]; +}; + +/* + * The head of the skip list; pointers for every possible level + * in the skip list, plus the largest level in the list + */ + +#define FC_CACHE_MAX_LEVEL 16 + +static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL]; +static int fcCacheMaxLevel; + +#if HAVE_RANDOM +# define FcRandom() random() +#else +# if HAVE_LRAND48 +# define FcRandom() lrand48() +# else +# if HAVE_RAND +# define FcRandom() rand() +# endif +# endif +#endif +/* + * Generate a random level number, distributed + * so that each level is 1/4 as likely as the one before + * + * Note that level numbers run 1 <= level <= MAX_LEVEL + */ +static int +random_level (void) +{ + /* tricky bit -- each bit is '1' 75% of the time */ + long int bits = FcRandom () | FcRandom (); + int level = 0; + + while (++level < FC_CACHE_MAX_LEVEL) + { + if (bits & 1) + break; + bits >>= 1; + } + return level; +} + +/* + * Insert cache into the list + */ +static FcBool +FcCacheInsert (FcCache *cache, struct stat *cache_stat) +{ + FcCacheSkip **update[FC_CACHE_MAX_LEVEL]; + FcCacheSkip *s, **next; + int i, level; + + /* + * Find links along each chain + */ + next = fcCacheChains; + for (i = fcCacheMaxLevel; --i >= 0; ) + { + for (; (s = next[i]); next = s->next) + if (s->cache > cache) + break; + update[i] = &next[i]; + } + + /* + * Create new list element + */ + level = random_level (); + if (level > fcCacheMaxLevel) + { + level = fcCacheMaxLevel + 1; + update[fcCacheMaxLevel] = &fcCacheChains[fcCacheMaxLevel]; + fcCacheMaxLevel = level; + } + + s = malloc (sizeof (FcCacheSkip) + (level - 1) * sizeof (FcCacheSkip *)); + if (!s) + return FcFalse; + + s->cache = cache; + s->size = cache->size; + s->ref = 1; + if (cache_stat) + { + s->cache_dev = cache_stat->st_dev; + s->cache_ino = cache_stat->st_ino; + s->cache_mtime = cache_stat->st_mtime; + } + else + { + s->cache_dev = 0; + s->cache_ino = 0; + s->cache_mtime = 0; + } + + /* + * Insert into all fcCacheChains + */ + for (i = 0; i < level; i++) + { + s->next[i] = *update[i]; + *update[i] = s; + } + return FcTrue; +} + +static FcCacheSkip * +FcCacheFindByAddr (void *object) +{ + int i; + FcCacheSkip **next = fcCacheChains; + FcCacheSkip *s; + + /* + * Walk chain pointers one level at a time + */ + for (i = fcCacheMaxLevel; --i >= 0;) + while (next[i] && (char *) object >= ((char *) next[i]->cache + next[i]->size)) + next = next[i]->next; + /* + * Here we are + */ + s = next[0]; + if (s && (char *) object < ((char *) s->cache + s->size)) + return s; + return NULL; +} + +static void +FcCacheRemove (FcCache *cache) +{ + FcCacheSkip **update[FC_CACHE_MAX_LEVEL]; + FcCacheSkip *s, **next; + int i; + + /* + * Find links along each chain + */ + next = fcCacheChains; + for (i = fcCacheMaxLevel; --i >= 0; ) + { + for (; (s = next[i]); next = s->next) + if (s->cache >= cache) + break; + update[i] = &next[i]; + } + s = next[0]; + for (i = 0; i < fcCacheMaxLevel && *update[i] == s; i++) + *update[i] = s->next[i]; + while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL) + fcCacheMaxLevel--; + free (s); +} + +static FcCache * +FcCacheFindByStat (struct stat *cache_stat) +{ + FcCacheSkip *s; + + for (s = fcCacheChains[0]; s; s = s->next[0]) + if (s->cache_dev == cache_stat->st_dev && + s->cache_ino == cache_stat->st_ino && + s->cache_mtime == cache_stat->st_mtime) + { + s->ref++; + return s->cache; + } + return NULL; +} + +static void +FcDirCacheDispose (FcCache *cache) +{ + switch (cache->magic) { + case FC_CACHE_MAGIC_ALLOC: + free (cache); + break; + case FC_CACHE_MAGIC_MMAP: +#if defined(HAVE_MMAP) || defined(__CYGWIN__) + munmap (cache, cache->size); +#elif defined(_WIN32) + UnmapViewOfFile (cache); +#endif + break; + } + FcCacheRemove (cache); +} + +void +FcCacheObjectReference (void *object) +{ + FcCacheSkip *skip = FcCacheFindByAddr (object); + + if (skip) + skip->ref++; +} + +void +FcCacheObjectDereference (void *object) +{ + FcCacheSkip *skip = FcCacheFindByAddr (object); + + if (skip) + { + skip->ref--; + if (skip->ref <= 0) + FcDirCacheDispose (skip->cache); + } +} + +void +FcCacheFini (void) +{ + int i; + + for (i = 0; i < FC_CACHE_MAX_LEVEL; i++) + assert (fcCacheChains[i] == NULL); + assert (fcCacheMaxLevel == 0); +} + +static FcBool +FcCacheTimeValid (FcCache *cache, struct stat *dir_stat) +{ + struct stat dir_static; + + if (!dir_stat) + { + if (FcStat (FcCacheDir (cache), &dir_static) < 0) + return FcFalse; + dir_stat = &dir_static; + } + if (FcDebug () & FC_DBG_CACHE) + printf ("FcCacheTimeValid dir \"%s\" cache time %d dir time %d\n", + FcCacheDir (cache), cache->mtime, (int) dir_stat->st_mtime); + return cache->mtime == (int) dir_stat->st_mtime; +} + +/* + * Map a cache file into memory + */ +static FcCache * +FcDirCacheMapFd (int fd, struct stat *fd_stat, struct stat *dir_stat) +{ + FcCache *cache; + FcBool allocated = FcFalse; + + if (fd_stat->st_size < sizeof (FcCache)) + return NULL; + cache = FcCacheFindByStat (fd_stat); + if (cache) + { + if (FcCacheTimeValid (cache, dir_stat)) + return cache; + FcDirCacheUnload (cache); + cache = NULL; + } + + /* + * Lage cache files are mmap'ed, smaller cache files are read. This + * balances the system cost of mmap against per-process memory usage. + */ + if (fd_stat->st_size >= FC_CACHE_MIN_MMAP) + { +#if defined(HAVE_MMAP) || defined(__CYGWIN__) + cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0); + if (cache == MAP_FAILED) + cache = NULL; +#elif defined(_WIN32) + { + HANDLE hFileMap; + + cache = NULL; + hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL, + PAGE_READONLY, 0, 0, NULL); + if (hFileMap != NULL) + { + cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, + fd_stat->st_size); + CloseHandle (hFileMap); + } + } +#endif + } + if (!cache) + { + cache = malloc (fd_stat->st_size); + if (!cache) + return NULL; + + if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size) + { + free (cache); + return NULL; + } + allocated = FcTrue; + } + if (cache->magic != FC_CACHE_MAGIC_MMAP || + cache->version < FC_CACHE_CONTENT_VERSION || + cache->size != fd_stat->st_size || + !FcCacheTimeValid (cache, dir_stat) || + !FcCacheInsert (cache, fd_stat)) + { + if (allocated) + free (cache); + else + { +#if defined(HAVE_MMAP) || defined(__CYGWIN__) + munmap (cache, fd_stat->st_size); +#elif defined(_WIN32) + UnmapViewOfFile (cache); +#endif + } + return NULL; + } + + /* Mark allocated caches so they're freed rather than unmapped */ + if (allocated) + cache->magic = FC_CACHE_MAGIC_ALLOC; + + return cache; +} + +void +FcDirCacheReference (FcCache *cache, int nref) +{ + FcCacheSkip *skip = FcCacheFindByAddr (cache); + + if (skip) + skip->ref += nref; +} + +void +FcDirCacheUnload (FcCache *cache) +{ + FcCacheObjectDereference (cache); +} + +static FcBool +FcDirCacheMapHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure) +{ + FcCache *cache = FcDirCacheMapFd (fd, fd_stat, dir_stat); + + if (!cache) + return FcFalse; + *((FcCache **) closure) = cache; + return FcTrue; +} + +FcCache * +FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file) +{ + FcCache *cache = NULL; + + if (!FcDirCacheProcess (config, dir, + FcDirCacheMapHelper, + &cache, cache_file)) + return NULL; + return cache; +} + +FcCache * +FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat) +{ + int fd; + FcCache *cache; + struct stat my_file_stat; + + if (!file_stat) + file_stat = &my_file_stat; + fd = FcDirCacheOpenFile (cache_file, file_stat); + if (fd < 0) + return NULL; + cache = FcDirCacheMapFd (fd, file_stat, NULL); + close (fd); + return cache; +} + +/* + * Validate a cache file by reading the header and checking + * the magic number and the size field + */ +static FcBool +FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure) +{ + FcBool ret = FcTrue; + FcCache c; + + if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache)) + ret = FcFalse; + else if (c.magic != FC_CACHE_MAGIC_MMAP) + ret = FcFalse; + else if (c.version < FC_CACHE_CONTENT_VERSION) + ret = FcFalse; + else if (fd_stat->st_size != c.size) + ret = FcFalse; + else if (c.mtime != (int) dir_stat->st_mtime) + ret = FcFalse; + return ret; +} + +static FcBool +FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config) +{ + return FcDirCacheProcess (config, dir, + FcDirCacheValidateHelper, + NULL, NULL); +} + +FcBool +FcDirCacheValid (const FcChar8 *dir) +{ + FcConfig *config; + + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + + return FcDirCacheValidConfig (dir, config); +} + +/* + * Build a cache structure from the given contents + */ +FcCache * +FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs) +{ + FcSerialize *serialize = FcSerializeCreate (); + FcCache *cache; + int i; + intptr_t cache_offset; + intptr_t dirs_offset; + FcChar8 *dir_serialize; + intptr_t *dirs_serialize; + FcFontSet *set_serialize; + + if (!serialize) + return NULL; + /* + * Space for cache structure + */ + cache_offset = FcSerializeReserve (serialize, sizeof (FcCache)); + /* + * Directory name + */ + if (!FcStrSerializeAlloc (serialize, dir)) + goto bail1; + /* + * Subdirs + */ + dirs_offset = FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *)); + for (i = 0; i < dirs->num; i++) + if (!FcStrSerializeAlloc (serialize, dirs->strs[i])) + goto bail1; + + /* + * Patterns + */ + if (!FcFontSetSerializeAlloc (serialize, set)) + goto bail1; + + /* Serialize layout complete. Now allocate space and fill it */ + cache = malloc (serialize->size); + if (!cache) + goto bail1; + /* shut up valgrind */ + memset (cache, 0, serialize->size); + + serialize->linear = cache; + + cache->magic = FC_CACHE_MAGIC_ALLOC; + cache->version = FC_CACHE_CONTENT_VERSION; + cache->size = serialize->size; + cache->mtime = (int) dir_stat->st_mtime; + + /* + * Serialize directory name + */ + dir_serialize = FcStrSerialize (serialize, dir); + if (!dir_serialize) + goto bail2; + cache->dir = FcPtrToOffset (cache, dir_serialize); + + /* + * Serialize sub dirs + */ + dirs_serialize = FcSerializePtr (serialize, dirs); + if (!dirs_serialize) + goto bail2; + cache->dirs = FcPtrToOffset (cache, dirs_serialize); + cache->dirs_count = dirs->num; + for (i = 0; i < dirs->num; i++) + { + FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]); + if (!d_serialize) + goto bail2; + dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize); + } + + /* + * Serialize font set + */ + set_serialize = FcFontSetSerialize (serialize, set); + if (!set_serialize) + goto bail2; + cache->set = FcPtrToOffset (cache, set_serialize); + + FcSerializeDestroy (serialize); + + FcCacheInsert (cache, NULL); + + return cache; + +bail2: + free (cache); +bail1: + FcSerializeDestroy (serialize); + return NULL; +} + + +#ifdef _WIN32 +#undef mkdir +#define mkdir(path,mode) _mkdir(path) +#endif + +static FcBool +FcMakeDirectory (const FcChar8 *dir) +{ + FcChar8 *parent; + FcBool ret; + + if (strlen ((char *) dir) == 0) + return FcFalse; + + parent = FcStrDirname (dir); + if (!parent) + return FcFalse; + if (access ((char *) parent, F_OK) == 0) + ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0; + else if (access ((char *) parent, F_OK) == -1) + ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0; + else + ret = FcFalse; + FcStrFree (parent); + return ret; +} + +/* write serialized state to the cache file */ +FcBool +FcDirCacheWrite (FcCache *cache, FcConfig *config) +{ + FcChar8 *dir = FcCacheDir (cache); + FcChar8 cache_base[CACHEBASE_LEN]; + FcChar8 *cache_hashed; + int fd; + FcAtomic *atomic; + FcStrList *list; + FcChar8 *cache_dir = NULL; + FcChar8 *test_dir; + FcCacheSkip *skip; + struct stat cache_stat; + int magic; + int written; + + /* + * Write it to the first directory in the list which is writable + */ + + list = FcStrListCreate (config->cacheDirs); + if (!list) + return FcFalse; + while ((test_dir = FcStrListNext (list))) { + if (access ((char *) test_dir, W_OK|X_OK) == 0) + { + cache_dir = test_dir; + break; + } + else + { + /* + * If the directory doesn't exist, try to create it + */ + if (access ((char *) test_dir, F_OK) == -1) { + if (FcMakeDirectory (test_dir)) + { + cache_dir = test_dir; + break; + } + } + /* + * Otherwise, try making it writable + */ + else if (chmod ((char *) test_dir, 0755) == 0) + { + cache_dir = test_dir; + break; + } + } + } + FcStrListDone (list); + if (!cache_dir) + return FcFalse; + + FcDirCacheBasename (dir, cache_base); + cache_hashed = FcStrPlus (cache_dir, cache_base); + if (!cache_hashed) + return FcFalse; + + if (FcDebug () & FC_DBG_CACHE) + printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n", + dir, cache_hashed); + + atomic = FcAtomicCreate ((FcChar8 *)cache_hashed); + if (!atomic) + goto bail1; + + if (!FcAtomicLock (atomic)) + goto bail3; + + fd = open((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666); + if (fd == -1) + goto bail4; + + /* Temporarily switch magic to MMAP while writing to file */ + magic = cache->magic; + if (magic != FC_CACHE_MAGIC_MMAP) + cache->magic = FC_CACHE_MAGIC_MMAP; + + /* + * Write cache contents to file + */ + written = write (fd, cache, cache->size); + + /* Switch magic back */ + if (magic != FC_CACHE_MAGIC_MMAP) + cache->magic = magic; + + if (written != cache->size) + { + perror ("write cache"); + goto bail5; + } + + close(fd); + if (!FcAtomicReplaceOrig(atomic)) + goto bail4; + + /* If the file is small, update the cache chain entry such that the + * new cache file is not read again. If it's large, we don't do that + * such that we reload it, using mmap, which is shared across processes. + */ + if (cache->size < FC_CACHE_MIN_MMAP && + (skip = FcCacheFindByAddr (cache)) && + FcStat (cache_hashed, &cache_stat)) + { + skip->cache_dev = cache_stat.st_dev; + skip->cache_ino = cache_stat.st_ino; + skip->cache_mtime = cache_stat.st_mtime; + } + + FcStrFree (cache_hashed); + FcAtomicUnlock (atomic); + FcAtomicDestroy (atomic); + return FcTrue; + + bail5: + close (fd); + bail4: + FcAtomicUnlock (atomic); + bail3: + FcAtomicDestroy (atomic); + bail1: + FcStrFree (cache_hashed); + return FcFalse; +} + +/* + * Hokey little macro trick to permit the definitions of C functions + * with the same name as CPP macros + */ +#define args1(x) (x) +#define args2(x,y) (x,y) + +const FcChar8 * +FcCacheDir args1(const FcCache *c) +{ + return FcCacheDir (c); +} + +FcFontSet * +FcCacheCopySet args1(const FcCache *c) +{ + FcFontSet *old = FcCacheSet (c); + FcFontSet *new = FcFontSetCreate (); + int i; + + if (!new) + return NULL; + for (i = 0; i < old->nfont; i++) + { + FcPattern *font = FcFontSetFont (old, i); + + FcPatternReference (font); + if (!FcFontSetAdd (new, font)) + { + FcFontSetDestroy (new); + return NULL; + } + } + return new; +} + +const FcChar8 * +FcCacheSubdir args2(const FcCache *c, int i) +{ + return FcCacheSubdir (c, i); +} + +int +FcCacheNumSubdir args1(const FcCache *c) +{ + return c->dirs_count; +} + +int +FcCacheNumFont args1(const FcCache *c) +{ + return FcCacheSet(c)->nfont; +} + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + FcChar32 t; + do { + t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(FcChar32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len) +{ + FcChar32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (FcChar32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (FcChar32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (FcChar32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((FcChar32 *) ctx->in)[14] = ctx->bits[0]; + ((FcChar32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (FcChar32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]) +{ + register FcChar32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +#define __fccache__ +#include "fcaliastail.h" +#undef __fccache__ diff --git a/fontconfig/src/fccfg.c b/fontconfig/src/fccfg.c index d948ab8d5..09c59919d 100644 --- a/fontconfig/src/fccfg.c +++ b/fontconfig/src/fccfg.c @@ -1,2108 +1,2108 @@ -/*
- * fontconfig/src/fccfg.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <dirent.h>
-#include <sys/types.h>
-
-#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
-#define STRICT
-#include <windows.h>
-#undef STRICT
-#endif
-
-#if defined (_WIN32) && !defined (R_OK)
-#define R_OK 4
-#endif
-
-FcConfig *_fcConfig;
-
-FcConfig *
-FcConfigCreate (void)
-{
- FcSetName set;
- FcConfig *config;
-
- config = malloc (sizeof (FcConfig));
- if (!config)
- goto bail0;
- FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
-
- config->configDirs = FcStrSetCreate ();
- if (!config->configDirs)
- goto bail1;
-
- config->configFiles = FcStrSetCreate ();
- if (!config->configFiles)
- goto bail2;
-
- config->fontDirs = FcStrSetCreate ();
- if (!config->fontDirs)
- goto bail3;
-
- config->acceptGlobs = FcStrSetCreate ();
- if (!config->acceptGlobs)
- goto bail4;
-
- config->rejectGlobs = FcStrSetCreate ();
- if (!config->rejectGlobs)
- goto bail5;
-
- config->acceptPatterns = FcFontSetCreate ();
- if (!config->acceptPatterns)
- goto bail6;
-
- config->rejectPatterns = FcFontSetCreate ();
- if (!config->rejectPatterns)
- goto bail7;
-
- config->cacheDirs = FcStrSetCreate ();
- if (!config->cacheDirs)
- goto bail8;
-
- config->blanks = 0;
-
- config->substPattern = 0;
- config->substFont = 0;
- config->substScan = 0;
- config->maxObjects = 0;
- for (set = FcSetSystem; set <= FcSetApplication; set++)
- config->fonts[set] = 0;
-
- config->rescanTime = time(0);
- config->rescanInterval = 30;
-
- config->expr_pool = NULL;
-
- config->ref = 1;
-
- return config;
-
-bail8:
- FcFontSetDestroy (config->rejectPatterns);
-bail7:
- FcFontSetDestroy (config->acceptPatterns);
-bail6:
- FcStrSetDestroy (config->rejectGlobs);
-bail5:
- FcStrSetDestroy (config->acceptGlobs);
-bail4:
- FcStrSetDestroy (config->fontDirs);
-bail3:
- FcStrSetDestroy (config->configFiles);
-bail2:
- FcStrSetDestroy (config->configDirs);
-bail1:
- free (config);
- FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
-bail0:
- return 0;
-}
-
-static FcFileTime
-FcConfigNewestFile (FcStrSet *files)
-{
- FcStrList *list = FcStrListCreate (files);
- FcFileTime newest = { 0, FcFalse };
- FcChar8 *file;
- struct stat statb;
-
- if (list)
- {
- while ((file = FcStrListNext (list)))
- if (FcStat (file, &statb) == 0)
- if (!newest.set || statb.st_mtime - newest.time > 0)
- {
- newest.set = FcTrue;
- newest.time = statb.st_mtime;
- }
- FcStrListDone (list);
- }
- return newest;
-}
-
-FcBool
-FcConfigUptoDate (FcConfig *config)
-{
- FcFileTime config_time, config_dir_time, font_time;
- time_t now = time(0);
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
- }
- config_time = FcConfigNewestFile (config->configFiles);
- config_dir_time = FcConfigNewestFile (config->configDirs);
- font_time = FcConfigNewestFile (config->fontDirs);
- if ((config_time.set && config_time.time - config->rescanTime > 0) ||
- (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
- (font_time.set && (font_time.time - config->rescanTime) > 0))
- {
- /* We need to check for potential clock problems here (OLPC ticket #6046) */
- if ((config_time.set && (config_time.time - now) > 0) ||
- (config_dir_time.set && (config_dir_time.time - now) > 0) ||
- (font_time.set && (font_time.time - now) > 0))
- {
- fprintf (stderr,
- "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n");
- config->rescanTime = now;
- return FcTrue;
- }
- else
- return FcFalse;
- }
- config->rescanTime = now;
- return FcTrue;
-}
-
-static void
-FcSubstDestroy (FcSubst *s)
-{
- FcSubst *n;
-
- while (s)
- {
- n = s->next;
- if (s->test)
- FcTestDestroy (s->test);
- if (s->edit)
- FcEditDestroy (s->edit);
- free (s);
- FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
- s = n;
- }
-}
-
-FcExpr *
-FcConfigAllocExpr (FcConfig *config)
-{
- if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
- {
- FcExprPage *new_page;
-
- new_page = malloc (sizeof (FcExprPage));
- if (!new_page)
- return 0;
- FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage));
-
- new_page->next_page = config->expr_pool;
- new_page->next = new_page->exprs;
- config->expr_pool = new_page;
- }
-
- return config->expr_pool->next++;
-}
-
-FcConfig *
-FcConfigReference (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
-
- config->ref++;
-
- return config;
-}
-
-void
-FcConfigDestroy (FcConfig *config)
-{
- FcSetName set;
- FcExprPage *page;
-
- if (--config->ref > 0)
- return;
-
- if (config == _fcConfig)
- _fcConfig = 0;
-
- FcStrSetDestroy (config->configDirs);
- FcStrSetDestroy (config->fontDirs);
- FcStrSetDestroy (config->cacheDirs);
- FcStrSetDestroy (config->configFiles);
- FcStrSetDestroy (config->acceptGlobs);
- FcStrSetDestroy (config->rejectGlobs);
- FcFontSetDestroy (config->acceptPatterns);
- FcFontSetDestroy (config->rejectPatterns);
-
- if (config->blanks)
- FcBlanksDestroy (config->blanks);
-
- FcSubstDestroy (config->substPattern);
- FcSubstDestroy (config->substFont);
- FcSubstDestroy (config->substScan);
- for (set = FcSetSystem; set <= FcSetApplication; set++)
- if (config->fonts[set])
- FcFontSetDestroy (config->fonts[set]);
-
- page = config->expr_pool;
- while (page)
- {
- FcExprPage *next = page->next_page;
- FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage));
- free (page);
- page = next;
- }
-
- free (config);
- FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
-}
-
-/*
- * Add cache to configuration, adding fonts and directories
- */
-
-FcBool
-FcConfigAddCache (FcConfig *config, FcCache *cache,
- FcSetName set, FcStrSet *dirSet)
-{
- FcFontSet *fs;
- intptr_t *dirs;
- int i;
-
- /*
- * Add fonts
- */
- fs = FcCacheSet (cache);
- if (fs)
- {
- int nref = 0;
-
- for (i = 0; i < fs->nfont; i++)
- {
- FcPattern *font = FcFontSetFont (fs, i);
- FcChar8 *font_file;
-
- /*
- * Check to see if font is banned by filename
- */
- if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
- 0, &font_file) == FcResultMatch &&
- !FcConfigAcceptFilename (config, font_file))
- {
- continue;
- }
-
- /*
- * Check to see if font is banned by pattern
- */
- if (!FcConfigAcceptFont (config, font))
- continue;
-
- nref++;
- FcFontSetAdd (config->fonts[set], font);
- }
- FcDirCacheReference (cache, nref);
- }
-
- /*
- * Add directories
- */
- dirs = FcCacheDirs (cache);
- if (dirs)
- {
- for (i = 0; i < cache->dirs_count; i++)
- {
- FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
- if (FcConfigAcceptFilename (config, dir))
- FcStrSetAddFilename (dirSet, dir);
- }
- }
- return FcTrue;
-}
-
-static FcBool
-FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
-{
- FcStrList *dirlist;
- FcChar8 *dir;
- FcCache *cache;
-
- dirlist = FcStrListCreate (dirSet);
- if (!dirlist)
- return FcFalse;
-
- while ((dir = FcStrListNext (dirlist)))
- {
- if (FcDebug () & FC_DBG_FONTSET)
- printf ("adding fonts from%s\n", dir);
- cache = FcDirCacheRead (dir, FcFalse, config);
- if (!cache)
- continue;
- FcConfigAddCache (config, cache, set, dirSet);
- FcDirCacheUnload (cache);
- }
- FcStrListDone (dirlist);
- return FcTrue;
-}
-
-/*
- * Scan the current list of directories in the configuration
- * and build the set of available fonts.
- */
-
-FcBool
-FcConfigBuildFonts (FcConfig *config)
-{
- FcFontSet *fonts;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
- }
-
- fonts = FcFontSetCreate ();
- if (!fonts)
- return FcFalse;
-
- FcConfigSetFonts (config, fonts, FcSetSystem);
-
- if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
- return FcFalse;
- if (FcDebug () & FC_DBG_FONTSET)
- FcFontSetPrint (fonts);
- return FcTrue;
-}
-
-FcBool
-FcConfigSetCurrent (FcConfig *config)
-{
- if (config == _fcConfig)
- return FcTrue;
-
- if (!config->fonts)
- if (!FcConfigBuildFonts (config))
- return FcFalse;
-
- if (_fcConfig)
- FcConfigDestroy (_fcConfig);
- _fcConfig = config;
- return FcTrue;
-}
-
-FcConfig *
-FcConfigGetCurrent (void)
-{
- if (!_fcConfig)
- if (!FcInit ())
- return 0;
- return _fcConfig;
-}
-
-FcBool
-FcConfigAddConfigDir (FcConfig *config,
- const FcChar8 *d)
-{
- return FcStrSetAddFilename (config->configDirs, d);
-}
-
-FcStrList *
-FcConfigGetConfigDirs (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return FcStrListCreate (config->configDirs);
-}
-
-FcBool
-FcConfigAddFontDir (FcConfig *config,
- const FcChar8 *d)
-{
- return FcStrSetAddFilename (config->fontDirs, d);
-}
-
-FcBool
-FcConfigAddDir (FcConfig *config,
- const FcChar8 *d)
-{
- return (FcConfigAddConfigDir (config, d) &&
- FcConfigAddFontDir (config, d));
-}
-
-FcStrList *
-FcConfigGetFontDirs (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return FcStrListCreate (config->fontDirs);
-}
-
-FcBool
-FcConfigAddCacheDir (FcConfig *config,
- const FcChar8 *d)
-{
- return FcStrSetAddFilename (config->cacheDirs, d);
-}
-
-FcStrList *
-FcConfigGetCacheDirs (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return FcStrListCreate (config->cacheDirs);
-}
-
-FcBool
-FcConfigAddConfigFile (FcConfig *config,
- const FcChar8 *f)
-{
- FcBool ret;
- FcChar8 *file = FcConfigFilename (f);
-
- if (!file)
- return FcFalse;
-
- ret = FcStrSetAdd (config->configFiles, file);
- FcStrFree (file);
- return ret;
-}
-
-FcStrList *
-FcConfigGetConfigFiles (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return FcStrListCreate (config->configFiles);
-}
-
-FcChar8 *
-FcConfigGetCache (FcConfig *config)
-{
- return NULL;
-}
-
-FcFontSet *
-FcConfigGetFonts (FcConfig *config,
- FcSetName set)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return config->fonts[set];
-}
-
-void
-FcConfigSetFonts (FcConfig *config,
- FcFontSet *fonts,
- FcSetName set)
-{
- if (config->fonts[set])
- FcFontSetDestroy (config->fonts[set]);
- config->fonts[set] = fonts;
-}
-
-FcBlanks *
-FcConfigGetBlanks (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return config->blanks;
-}
-
-FcBool
-FcConfigAddBlank (FcConfig *config,
- FcChar32 blank)
-{
- FcBlanks *b, *freeme = 0;
-
- b = config->blanks;
- if (!b)
- {
- freeme = b = FcBlanksCreate ();
- if (!b)
- return FcFalse;
- }
- if (!FcBlanksAdd (b, blank))
- {
- if (freeme)
- FcBlanksDestroy (freeme);
- return FcFalse;
- }
- config->blanks = b;
- return FcTrue;
-}
-
-int
-FcConfigGetRescanInterval (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- return config->rescanInterval;
-}
-
-FcBool
-FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
- }
- config->rescanInterval = rescanInterval;
- return FcTrue;
-}
-
-/*
- * A couple of typos escaped into the library
- */
-int
-FcConfigGetRescanInverval (FcConfig *config)
-{
- return FcConfigGetRescanInterval (config);
-}
-
-FcBool
-FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
-{
- return FcConfigSetRescanInterval (config, rescanInterval);
-}
-
-
-FcBool
-FcConfigAddEdit (FcConfig *config,
- FcTest *test,
- FcEdit *edit,
- FcMatchKind kind)
-{
- FcSubst *subst, **prev;
- FcTest *t;
- int num;
-
- switch (kind) {
- case FcMatchPattern:
- prev = &config->substPattern;
- break;
- case FcMatchFont:
- prev = &config->substFont;
- break;
- case FcMatchScan:
- prev = &config->substScan;
- break;
- default:
- return FcFalse;
- }
- subst = (FcSubst *) malloc (sizeof (FcSubst));
- if (!subst)
- return FcFalse;
- FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
- for (; *prev; prev = &(*prev)->next);
- *prev = subst;
- subst->next = 0;
- subst->test = test;
- subst->edit = edit;
- num = 0;
- for (t = test; t; t = t->next)
- {
- if (t->kind == FcMatchDefault)
- t->kind = kind;
- num++;
- }
- if (config->maxObjects < num)
- config->maxObjects = num;
- if (FcDebug () & FC_DBG_EDIT)
- {
- printf ("Add Subst ");
- FcSubstPrint (subst);
- }
- return FcTrue;
-}
-
-typedef struct _FcSubState {
- FcPatternElt *elt;
- FcValueList *value;
-} FcSubState;
-
-static FcValue
-FcConfigPromote (FcValue v, FcValue u)
-{
- if (v.type == FcTypeInteger)
- {
- v.type = FcTypeDouble;
- v.u.d = (double) v.u.i;
- }
- else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
- {
- v.u.m = &FcIdentityMatrix;
- v.type = FcTypeMatrix;
- }
- else if (v.type == FcTypeString && u.type == FcTypeLangSet)
- {
- v.u.l = FcLangSetPromote (v.u.s);
- v.type = FcTypeLangSet;
- }
- return v;
-}
-
-FcBool
-FcConfigCompareValue (const FcValue *left_o,
- FcOp op,
- const FcValue *right_o)
-{
- FcValue left = FcValueCanonicalize(left_o);
- FcValue right = FcValueCanonicalize(right_o);
- FcBool ret = FcFalse;
-
- left = FcConfigPromote (left, right);
- right = FcConfigPromote (right, left);
- if (left.type == right.type)
- {
- switch (left.type) {
- case FcTypeInteger:
- break; /* FcConfigPromote prevents this from happening */
- case FcTypeDouble:
- switch (op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = left.u.d == right.u.d;
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = left.u.d != right.u.d;
- break;
- case FcOpLess:
- ret = left.u.d < right.u.d;
- break;
- case FcOpLessEqual:
- ret = left.u.d <= right.u.d;
- break;
- case FcOpMore:
- ret = left.u.d > right.u.d;
- break;
- case FcOpMoreEqual:
- ret = left.u.d >= right.u.d;
- break;
- default:
- break;
- }
- break;
- case FcTypeBool:
- switch (op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = left.u.b == right.u.b;
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = left.u.b != right.u.b;
- break;
- default:
- break;
- }
- break;
- case FcTypeString:
- switch (op) {
- case FcOpEqual:
- case FcOpListing:
- ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
- break;
- case FcOpContains:
- ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
- break;
- case FcOpNotEqual:
- ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
- break;
- case FcOpNotContains:
- ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
- break;
- default:
- break;
- }
- break;
- case FcTypeMatrix:
- switch (op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = FcMatrixEqual (left.u.m, right.u.m);
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = !FcMatrixEqual (left.u.m, right.u.m);
- break;
- default:
- break;
- }
- break;
- case FcTypeCharSet:
- switch (op) {
- case FcOpContains:
- case FcOpListing:
- /* left contains right if right is a subset of left */
- ret = FcCharSetIsSubset (right.u.c, left.u.c);
- break;
- case FcOpNotContains:
- /* left contains right if right is a subset of left */
- ret = !FcCharSetIsSubset (right.u.c, left.u.c);
- break;
- case FcOpEqual:
- ret = FcCharSetEqual (left.u.c, right.u.c);
- break;
- case FcOpNotEqual:
- ret = !FcCharSetEqual (left.u.c, right.u.c);
- break;
- default:
- break;
- }
- break;
- case FcTypeLangSet:
- switch (op) {
- case FcOpContains:
- case FcOpListing:
- ret = FcLangSetContains (left.u.l, right.u.l);
- break;
- case FcOpNotContains:
- ret = !FcLangSetContains (left.u.l, right.u.l);
- break;
- case FcOpEqual:
- ret = FcLangSetEqual (left.u.l, right.u.l);
- break;
- case FcOpNotEqual:
- ret = !FcLangSetEqual (left.u.l, right.u.l);
- break;
- default:
- break;
- }
- break;
- case FcTypeVoid:
- switch (op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = FcTrue;
- break;
- default:
- break;
- }
- break;
- case FcTypeFTFace:
- switch (op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = left.u.f == right.u.f;
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = left.u.f != right.u.f;
- break;
- default:
- break;
- }
- break;
- }
- }
- else
- {
- if (op == FcOpNotEqual || op == FcOpNotContains)
- ret = FcTrue;
- }
- return ret;
-}
-
-
-#define _FcDoubleFloor(d) ((int) (d))
-#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
-#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
-#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
-#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
-#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
-
-static FcValue
-FcConfigEvaluate (FcPattern *p, FcExpr *e)
-{
- FcValue v, vl, vr;
- FcResult r;
- FcMatrix *m;
- FcChar8 *str;
-
- 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 FcOpLangSet:
- v.type = FcTypeLangSet;
- v.u.l = e->u.lval;
- v = FcValueSave (v);
- break;
- case FcOpBool:
- v.type = FcTypeBool;
- v.u.b = e->u.bval;
- break;
- case FcOpField:
- r = FcPatternObjectGet (p, e->u.object, 0, &v);
- if (r != FcResultMatch)
- v.type = FcTypeVoid;
- v = FcValueSave (v);
- break;
- case FcOpConst:
- if (FcNameConstant (e->u.constant, &v.u.i))
- v.type = FcTypeInteger;
- else
- v.type = FcTypeVoid;
- break;
- case FcOpQuest:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- if (vl.type == FcTypeBool)
- {
- if (vl.u.b)
- v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
- else
- v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
- }
- else
- v.type = FcTypeVoid;
- FcValueDestroy (vl);
- break;
- case FcOpEqual:
- case FcOpNotEqual:
- case FcOpLess:
- case FcOpLessEqual:
- case FcOpMore:
- case FcOpMoreEqual:
- case FcOpContains:
- case FcOpNotContains:
- case FcOpListing:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- vr = FcConfigEvaluate (p, e->u.tree.right);
- v.type = FcTypeBool;
- v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
- FcValueDestroy (vl);
- FcValueDestroy (vr);
- break;
- case FcOpOr:
- case FcOpAnd:
- 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;
- 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;
- default:
- v.type = FcTypeVoid;
- break;
- }
- break;
- case FcTypeString:
- switch (e->op) {
- case FcOpPlus:
- v.type = FcTypeString;
- str = FcStrPlus (vl.u.s, vr.u.s);
- v.u.s = FcStrStaticName (str);
- FcStrFree (str);
-
- if (!v.u.s)
- v.type = FcTypeVoid;
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- break;
- case FcTypeMatrix:
- switch (e->op) {
- case FcOpTimes:
- v.type = FcTypeMatrix;
- m = malloc (sizeof (FcMatrix));
- if (m)
- {
- FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
- FcMatrixMultiply (m, vl.u.m, vr.u.m);
- v.u.m = m;
- }
- else
- {
- v.type = FcTypeVoid;
- }
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- break;
- case FcTypeCharSet:
- switch (e->op) {
- case FcOpPlus:
- v.type = FcTypeCharSet;
- v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
- if (!v.u.c)
- v.type = FcTypeVoid;
- break;
- case FcOpMinus:
- v.type = FcTypeCharSet;
- v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
- if (!v.u.c)
- v.type = FcTypeVoid;
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- break;
- case FcTypeLangSet:
- switch (e->op) {
- case FcOpPlus:
- v.type = FcTypeLangSet;
- v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
- if (!v.u.l)
- v.type = FcTypeVoid;
- break;
- case FcOpMinus:
- v.type = FcTypeLangSet;
- v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
- if (!v.u.l)
- v.type = FcTypeVoid;
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- }
- else
- v.type = FcTypeVoid;
- FcValueDestroy (vl);
- FcValueDestroy (vr);
- break;
- case FcOpNot:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- switch (vl.type) {
- case FcTypeBool:
- v.type = FcTypeBool;
- v.u.b = !vl.u.b;
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- FcValueDestroy (vl);
- break;
- case FcOpFloor:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- switch (vl.type) {
- case FcTypeInteger:
- v = vl;
- break;
- case FcTypeDouble:
- v.type = FcTypeInteger;
- v.u.i = FcDoubleFloor (vl.u.d);
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- FcValueDestroy (vl);
- break;
- case FcOpCeil:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- switch (vl.type) {
- case FcTypeInteger:
- v = vl;
- break;
- case FcTypeDouble:
- v.type = FcTypeInteger;
- v.u.i = FcDoubleCeil (vl.u.d);
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- FcValueDestroy (vl);
- break;
- case FcOpRound:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- switch (vl.type) {
- case FcTypeInteger:
- v = vl;
- break;
- case FcTypeDouble:
- v.type = FcTypeInteger;
- v.u.i = FcDoubleRound (vl.u.d);
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- FcValueDestroy (vl);
- break;
- case FcOpTrunc:
- vl = FcConfigEvaluate (p, e->u.tree.left);
- switch (vl.type) {
- case FcTypeInteger:
- v = vl;
- break;
- case FcTypeDouble:
- v.type = FcTypeInteger;
- v.u.i = FcDoubleTrunc (vl.u.d);
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- FcValueDestroy (vl);
- break;
- default:
- v.type = FcTypeVoid;
- break;
- }
- return v;
-}
-
-static FcValueList *
-FcConfigMatchValueList (FcPattern *p,
- FcTest *t,
- FcValueList *values)
-{
- FcValueList *ret = 0;
- FcExpr *e = t->expr;
- FcValue value;
- FcValueList *v;
-
- while (e)
- {
- /* Compute the value of the match expression */
- if (e->op == FcOpComma)
- {
- value = FcConfigEvaluate (p, e->u.tree.left);
- e = e->u.tree.right;
- }
- else
- {
- value = FcConfigEvaluate (p, e);
- e = 0;
- }
-
- for (v = values; v; v = FcValueListNext(v))
- {
- /* Compare the pattern value to the match expression value */
- if (FcConfigCompareValue (&v->value, t->op, &value))
- {
- if (!ret)
- ret = v;
- }
- else
- {
- if (t->qual == FcQualAll)
- {
- ret = 0;
- break;
- }
- }
- }
- FcValueDestroy (value);
- }
- return ret;
-}
-
-static FcValueList *
-FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
-{
- 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, binding);
- }
- else
- {
- l->value = FcConfigEvaluate (p, e);
- l->next = NULL;
- }
- l->binding = binding;
- if (l->value.type == FcTypeVoid)
- {
- FcValueList *next = FcValueListNext(l);
-
- FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
- free (l);
- l = next;
- }
-
- return l;
-}
-
-static FcBool
-FcConfigAdd (FcValueListPtr *head,
- FcValueList *position,
- FcBool append,
- FcValueList *new)
-{
- FcValueListPtr *prev, last, v;
- FcValueBinding sameBinding;
-
- if (position)
- sameBinding = position->binding;
- else
- sameBinding = FcValueBindingWeak;
- for (v = new; v != NULL; v = FcValueListNext(v))
- if (v->binding == FcValueBindingSame)
- v->binding = sameBinding;
- if (append)
- {
- if (position)
- prev = &position->next;
- else
- for (prev = head; *prev != NULL;
- prev = &(*prev)->next)
- ;
- }
- else
- {
- if (position)
- {
- for (prev = head; *prev != NULL;
- prev = &(*prev)->next)
- {
- if (*prev == position)
- break;
- }
- }
- else
- prev = head;
-
- if (FcDebug () & FC_DBG_EDIT)
- {
- if (*prev == NULL)
- 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 != NULL)
- 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 (FcValueListPtr *head,
- FcValueList *position)
-{
- FcValueListPtr *prev;
-
- for (prev = head; *prev != NULL; prev = &(*prev)->next)
- {
- if (*prev == position)
- {
- *prev = position->next;
- position->next = NULL;
- FcValueListDestroy (position);
- break;
- }
- }
-}
-
-static void
-FcConfigPatternAdd (FcPattern *p,
- FcObject object,
- FcValueList *list,
- FcBool append)
-{
- if (list)
- {
- FcPatternElt *e = FcPatternObjectInsertElt (p, object);
-
- if (!e)
- return;
- FcConfigAdd (&e->values, 0, append, list);
- }
-}
-
-/*
- * Delete all values associated with a field
- */
-static void
-FcConfigPatternDel (FcPattern *p,
- FcObject object)
-{
- FcPatternElt *e = FcPatternObjectFindElt (p, object);
- if (!e)
- return;
- while (e->values != NULL)
- FcConfigDel (&e->values, e->values);
-}
-
-static void
-FcConfigPatternCanon (FcPattern *p,
- FcObject object)
-{
- FcPatternElt *e = FcPatternObjectFindElt (p, object);
- if (!e)
- return;
- if (e->values == NULL)
- FcPatternObjectDel (p, object);
-}
-
-FcBool
-FcConfigSubstituteWithPat (FcConfig *config,
- FcPattern *p,
- FcPattern *p_pat,
- FcMatchKind kind)
-{
- FcSubst *s;
- FcSubState *st;
- int i;
- FcTest *t;
- FcEdit *e;
- FcValueList *l;
- FcPattern *m;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
- }
-
- switch (kind) {
- case FcMatchPattern:
- s = config->substPattern;
- break;
- case FcMatchFont:
- s = config->substFont;
- break;
- case FcMatchScan:
- s = config->substScan;
- break;
- default:
- return FcFalse;
- }
-
- st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
- if (!st && config->maxObjects)
- return FcFalse;
- FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
-
- if (FcDebug () & FC_DBG_EDIT)
- {
- printf ("FcConfigSubstitute ");
- FcPatternPrint (p);
- }
- for (; s; s = s->next)
- {
- /*
- * Check the tests to see if
- * they all match the pattern
- */
- for (t = s->test, i = 0; t; t = t->next, i++)
- {
- if (FcDebug () & FC_DBG_EDIT)
- {
- printf ("FcConfigSubstitute test ");
- FcTestPrint (t);
- }
- st[i].elt = 0;
- if (kind == FcMatchFont && t->kind == FcMatchPattern)
- m = p_pat;
- else
- m = p;
- if (m)
- st[i].elt = FcPatternObjectFindElt (m, t->object);
- else
- st[i].elt = 0;
- /*
- * If there's no such field in the font,
- * then FcQualAll matches while FcQualAny does not
- */
- if (!st[i].elt)
- {
- if (t->qual == FcQualAll)
- {
- st[i].value = 0;
- continue;
- }
- else
- break;
- }
- /*
- * Check to see if there is a match, mark the location
- * to apply match-relative edits
- */
- st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
- if (!st[i].value)
- break;
- if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
- break;
- if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
- break;
- }
- 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, e->binding);
- /*
- * Locate any test associated with this field, skipping
- * tests associated with the pattern when substituting in
- * the font
- */
- for (t = s->test, i = 0; t; t = t->next, i++)
- {
- if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
- t->object == e->object)
- {
- /*
- * KLUDGE - the pattern may have been reallocated or
- * things may have been inserted or deleted above
- * this element by other edits. Go back and find
- * the element again
- */
- if (e != s->edit && st[i].elt)
- st[i].elt = FcPatternObjectFindElt (p, t->object);
- if (!st[i].elt)
- t = 0;
- 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;
-
- /*
- * Append the new list of values after the current value
- */
- FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
- /*
- * Delete the marked value
- */
- if (thisValue)
- FcConfigDel (&st[i].elt->values, thisValue);
- /*
- * Adjust any pointers into the value list to ensure
- * future edits occur at the same place
- */
- for (t = s->test, i = 0; t; t = t->next, i++)
- {
- if (st[i].value == thisValue)
- st[i].value = nextValue;
- }
- break;
- }
- /* fall through ... */
- case FcOpAssignReplace:
- /*
- * Delete all of the values and insert
- * the new set
- */
- FcConfigPatternDel (p, e->object);
- FcConfigPatternAdd (p, e->object, l, FcTrue);
- /*
- * Adjust any pointers into the value list as they no
- * longer point to anything valid
- */
- if (t)
- {
- FcPatternElt *thisElt = st[i].elt;
- for (t = s->test, i = 0; t; t = t->next, i++)
- {
- if (st[i].elt == thisElt)
- st[i].value = 0;
- }
- }
- break;
- case FcOpPrepend:
- if (t)
- {
- FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
- break;
- }
- /* fall through ... */
- case FcOpPrependFirst:
- FcConfigPatternAdd (p, e->object, l, FcFalse);
- break;
- case FcOpAppend:
- if (t)
- {
- FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
- break;
- }
- /* fall through ... */
- case FcOpAppendLast:
- FcConfigPatternAdd (p, e->object, l, FcTrue);
- break;
- default:
- FcValueListDestroy (l);
- break;
- }
- }
- /*
- * Now go through the pattern and eliminate
- * any properties without data
- */
- for (e = s->edit; e; e = e->next)
- FcConfigPatternCanon (p, e->object);
-
- if (FcDebug () & FC_DBG_EDIT)
- {
- printf ("FcConfigSubstitute edit");
- FcPatternPrint (p);
- }
- }
- FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
- free (st);
- if (FcDebug () & FC_DBG_EDIT)
- {
- printf ("FcConfigSubstitute done");
- FcPatternPrint (p);
- }
- return FcTrue;
-}
-
-FcBool
-FcConfigSubstitute (FcConfig *config,
- FcPattern *p,
- FcMatchKind kind)
-{
- return FcConfigSubstituteWithPat (config, p, 0, kind);
-}
-
-#if defined (_WIN32)
-
-# define WIN32_LEAN_AND_MEAN
-# define WIN32_EXTRA_LEAN
-# include <windows.h>
-
-static FcChar8 fontconfig_path[1000] = "";
-
-# if (defined (PIC) || defined (DLL_EXPORT))
-
-BOOL WINAPI
-DllMain (HINSTANCE hinstDLL,
- DWORD fdwReason,
- LPVOID lpvReserved)
-{
- FcChar8 *p;
-
- switch (fdwReason) {
- case DLL_PROCESS_ATTACH:
- if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
- sizeof (fontconfig_path)))
- break;
-
- /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
- * assume it's a Unix-style installation tree, and use
- * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
- * folder where the DLL is as FONTCONFIG_PATH.
- */
- p = strrchr (fontconfig_path, '\\');
- if (p)
- {
- *p = '\0';
- p = strrchr (fontconfig_path, '\\');
- if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
- FcStrCmpIgnoreCase (p + 1, "lib") == 0))
- *p = '\0';
- strcat (fontconfig_path, "\\etc\\fonts");
- }
- else
- fontconfig_path[0] = '\0';
-
- break;
- }
-
- return TRUE;
-}
-
-# endif /* !PIC */
-
-#undef FONTCONFIG_PATH
-#define FONTCONFIG_PATH fontconfig_path
-
-#endif /* !_WIN32 */
-
-#ifndef FONTCONFIG_FILE
-#define FONTCONFIG_FILE "fonts.conf"
-#endif
-
-static FcChar8 *
-FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
-{
- FcChar8 *path;
- int size;
-
- if (!dir)
- dir = (FcChar8 *) "";
-
- size = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
- /*
- * workaround valgrind warning because glibc takes advantage of how it knows memory is
- * allocated to implement strlen by reading in groups of 4
- */
- size = (size + 3) & ~3;
-
- path = malloc (size);
- if (!path)
- return 0;
-
- strcpy ((char *) path, (const char *) dir);
- /* make sure there's a single separator */
-#ifdef _WIN32
- if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
- path[strlen((char *) path)-1] != '\\')) &&
- !(file[0] == '/' ||
- file[0] == '\\' ||
- (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
- strcat ((char *) path, "\\");
-#else
- if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
- strcat ((char *) path, "/");
-#endif
- strcat ((char *) path, (char *) file);
-
- FcMemAlloc (FC_MEM_STRING, size);
- if (access ((char *) path, R_OK) == 0)
- return path;
-
- FcStrFree (path);
- return 0;
-}
-
-static FcChar8 **
-FcConfigGetPath (void)
-{
- FcChar8 **path;
- FcChar8 *env, *e, *colon;
- FcChar8 *dir;
- int npath;
- int i;
-
- npath = 2; /* default dir + null */
- env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
- if (env)
- {
- e = env;
- npath++;
- while (*e)
- if (*e++ == FC_SEARCH_PATH_SEPARATOR)
- npath++;
- }
- path = calloc (npath, sizeof (FcChar8 *));
- if (!path)
- goto bail0;
- i = 0;
-
- if (env)
- {
- e = env;
- while (*e)
- {
- colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
- if (!colon)
- colon = e + strlen ((char *) e);
- path[i] = malloc (colon - e + 1);
- if (!path[i])
- goto bail1;
- strncpy ((char *) path[i], (const char *) e, colon - e);
- path[i][colon - e] = '\0';
- if (*colon)
- e = colon + 1;
- else
- e = colon;
- i++;
- }
- }
-
-#ifdef _WIN32
- if (fontconfig_path[0] == '\0')
- {
- char *p;
- if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
- goto bail1;
- p = strrchr (fontconfig_path, '\\');
- if (p) *p = '\0';
- strcat (fontconfig_path, "\\fonts");
- }
-#endif
- dir = (FcChar8 *) FONTCONFIG_PATH;
- path[i] = malloc (strlen ((char *) dir) + 1);
- if (!path[i])
- goto bail1;
- strcpy ((char *) path[i], (const char *) dir);
- return path;
-
-bail1:
- for (i = 0; path[i]; i++)
- free (path[i]);
- free (path);
-bail0:
- return 0;
-}
-
-static void
-FcConfigFreePath (FcChar8 **path)
-{
- FcChar8 **p;
-
- for (p = path; *p; p++)
- free (*p);
- free (path);
-}
-
-static FcBool _FcConfigHomeEnabled = FcTrue;
-
-FcChar8 *
-FcConfigHome (void)
-{
- if (_FcConfigHomeEnabled)
- {
- char *home = getenv ("HOME");
-
-#ifdef _WIN32
- if (home == NULL)
- home = getenv ("USERPROFILE");
-#endif
-
- return (FcChar8 *) home;
- }
- return 0;
-}
-
-FcBool
-FcConfigEnableHome (FcBool enable)
-{
- FcBool prev = _FcConfigHomeEnabled;
- _FcConfigHomeEnabled = enable;
- return prev;
-}
-
-FcChar8 *
-FcConfigFilename (const FcChar8 *url)
-{
- FcChar8 *file, *dir, **path, **p;
-
- if (!url || !*url)
- {
- url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
- if (!url)
- url = (FcChar8 *) FONTCONFIG_FILE;
- }
- file = 0;
-
-#ifdef _WIN32
- if (isalpha (*url) &&
- url[1] == ':' &&
- (url[2] == '/' || url[2] == '\\'))
- goto absolute_path;
-#endif
-
- switch (*url) {
- case '~':
- dir = FcConfigHome ();
- if (dir)
- file = FcConfigFileExists (dir, url + 1);
- else
- file = 0;
- break;
-#ifdef _WIN32
- case '\\':
- absolute_path:
-#endif
- case '/':
- file = FcConfigFileExists (0, url);
- break;
- default:
- path = FcConfigGetPath ();
- if (!path)
- return 0;
- for (p = path; *p; p++)
- {
- file = FcConfigFileExists (*p, url);
- if (file)
- break;
- }
- FcConfigFreePath (path);
- break;
- }
- return file;
-}
-
-/*
- * Manage the application-specific fonts
- */
-
-FcBool
-FcConfigAppFontAddFile (FcConfig *config,
- const FcChar8 *file)
-{
- FcFontSet *set;
- FcStrSet *subdirs;
- FcStrList *sublist;
- FcChar8 *subdir;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
- }
-
- subdirs = FcStrSetCreate ();
- if (!subdirs)
- return FcFalse;
-
- set = FcConfigGetFonts (config, FcSetApplication);
- if (!set)
- {
- set = FcFontSetCreate ();
- if (!set)
- {
- FcStrSetDestroy (subdirs);
- return FcFalse;
- }
- FcConfigSetFonts (config, set, FcSetApplication);
- }
-
- if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
- {
- FcStrSetDestroy (subdirs);
- return FcFalse;
- }
- if ((sublist = FcStrListCreate (subdirs)))
- {
- while ((subdir = FcStrListNext (sublist)))
- {
- FcConfigAppFontAddDir (config, subdir);
- }
- FcStrListDone (sublist);
- }
- FcStrSetDestroy (subdirs);
- return FcTrue;
-}
-
-FcBool
-FcConfigAppFontAddDir (FcConfig *config,
- const FcChar8 *dir)
-{
- FcFontSet *set;
- FcStrSet *dirs;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return FcFalse;
- }
-
- dirs = FcStrSetCreate ();
- if (!dirs)
- return FcFalse;
-
- set = FcConfigGetFonts (config, FcSetApplication);
- if (!set)
- {
- set = FcFontSetCreate ();
- if (!set)
- {
- FcStrSetDestroy (dirs);
- return FcFalse;
- }
- FcConfigSetFonts (config, set, FcSetApplication);
- }
-
- FcStrSetAddFilename (dirs, dir);
-
- if (!FcConfigAddDirList (config, FcSetApplication, dirs))
- {
- FcStrSetDestroy (dirs);
- return FcFalse;
- }
- FcStrSetDestroy (dirs);
- return FcTrue;
-}
-
-void
-FcConfigAppFontClear (FcConfig *config)
-{
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return;
- }
-
- FcConfigSetFonts (config, 0, FcSetApplication);
-}
-
-/*
- * Manage filename-based font source selectors
- */
-
-FcBool
-FcConfigGlobAdd (FcConfig *config,
- const FcChar8 *glob,
- FcBool accept)
-{
- FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
-
- return FcStrSetAdd (set, glob);
-}
-
-static FcBool
-FcConfigGlobMatch (const FcChar8 *glob,
- const FcChar8 *string)
-{
- FcChar8 c;
-
- while ((c = *glob++))
- {
- switch (c) {
- case '*':
- /* short circuit common case */
- if (!*glob)
- return FcTrue;
- /* short circuit another common case */
- if (strchr ((char *) glob, '*') == 0)
- string += strlen ((char *) string) - strlen ((char *) glob);
- while (*string)
- {
- if (FcConfigGlobMatch (glob, string))
- return FcTrue;
- string++;
- }
- return FcFalse;
- case '?':
- if (*string++ == '\0')
- return FcFalse;
- break;
- default:
- if (*string++ != c)
- return FcFalse;
- break;
- }
- }
- return *string == '\0';
-}
-
-static FcBool
-FcConfigGlobsMatch (const FcStrSet *globs,
- const FcChar8 *string)
-{
- int i;
-
- for (i = 0; i < globs->num; i++)
- if (FcConfigGlobMatch (globs->strs[i], string))
- return FcTrue;
- return FcFalse;
-}
-
-FcBool
-FcConfigAcceptFilename (FcConfig *config,
- const FcChar8 *filename)
-{
- if (FcConfigGlobsMatch (config->acceptGlobs, filename))
- return FcTrue;
- if (FcConfigGlobsMatch (config->rejectGlobs, filename))
- return FcFalse;
- return FcTrue;
-}
-
-/*
- * Manage font-pattern based font source selectors
- */
-
-FcBool
-FcConfigPatternsAdd (FcConfig *config,
- FcPattern *pattern,
- FcBool accept)
-{
- FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
-
- return FcFontSetAdd (set, pattern);
-}
-
-static FcBool
-FcConfigPatternsMatch (const FcFontSet *patterns,
- const FcPattern *font)
-{
- int i;
-
- for (i = 0; i < patterns->nfont; i++)
- if (FcListPatternMatchAny (patterns->fonts[i], font))
- return FcTrue;
- return FcFalse;
-}
-
-FcBool
-FcConfigAcceptFont (FcConfig *config,
- const FcPattern *font)
-{
- if (FcConfigPatternsMatch (config->acceptPatterns, font))
- return FcTrue;
- if (FcConfigPatternsMatch (config->rejectPatterns, font))
- return FcFalse;
- return FcTrue;
-}
-#define __fccfg__
-#include "fcaliastail.h"
-#undef __fccfg__
+/* + * fontconfig/src/fccfg.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <dirent.h> +#include <sys/types.h> + +#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT)) +#define STRICT +#include <windows.h> +#undef STRICT +#endif + +#if defined (_WIN32) && !defined (R_OK) +#define R_OK 4 +#endif + +FcConfig *_fcConfig; + +FcConfig * +FcConfigCreate (void) +{ + FcSetName set; + FcConfig *config; + + config = malloc (sizeof (FcConfig)); + if (!config) + goto bail0; + FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig)); + + config->configDirs = FcStrSetCreate (); + if (!config->configDirs) + goto bail1; + + config->configFiles = FcStrSetCreate (); + if (!config->configFiles) + goto bail2; + + config->fontDirs = FcStrSetCreate (); + if (!config->fontDirs) + goto bail3; + + config->acceptGlobs = FcStrSetCreate (); + if (!config->acceptGlobs) + goto bail4; + + config->rejectGlobs = FcStrSetCreate (); + if (!config->rejectGlobs) + goto bail5; + + config->acceptPatterns = FcFontSetCreate (); + if (!config->acceptPatterns) + goto bail6; + + config->rejectPatterns = FcFontSetCreate (); + if (!config->rejectPatterns) + goto bail7; + + config->cacheDirs = FcStrSetCreate (); + if (!config->cacheDirs) + goto bail8; + + config->blanks = 0; + + config->substPattern = 0; + config->substFont = 0; + config->substScan = 0; + config->maxObjects = 0; + for (set = FcSetSystem; set <= FcSetApplication; set++) + config->fonts[set] = 0; + + config->rescanTime = time(0); + config->rescanInterval = 30; + + config->expr_pool = NULL; + + config->ref = 1; + + return config; + +bail8: + FcFontSetDestroy (config->rejectPatterns); +bail7: + FcFontSetDestroy (config->acceptPatterns); +bail6: + FcStrSetDestroy (config->rejectGlobs); +bail5: + FcStrSetDestroy (config->acceptGlobs); +bail4: + FcStrSetDestroy (config->fontDirs); +bail3: + FcStrSetDestroy (config->configFiles); +bail2: + FcStrSetDestroy (config->configDirs); +bail1: + free (config); + FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); +bail0: + return 0; +} + +static FcFileTime +FcConfigNewestFile (FcStrSet *files) +{ + FcStrList *list = FcStrListCreate (files); + FcFileTime newest = { 0, FcFalse }; + FcChar8 *file; + struct stat statb; + + if (list) + { + while ((file = FcStrListNext (list))) + if (FcStat (file, &statb) == 0) + if (!newest.set || statb.st_mtime - newest.time > 0) + { + newest.set = FcTrue; + newest.time = statb.st_mtime; + } + FcStrListDone (list); + } + return newest; +} + +FcBool +FcConfigUptoDate (FcConfig *config) +{ + FcFileTime config_time, config_dir_time, font_time; + time_t now = time(0); + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + config_time = FcConfigNewestFile (config->configFiles); + config_dir_time = FcConfigNewestFile (config->configDirs); + font_time = FcConfigNewestFile (config->fontDirs); + if ((config_time.set && config_time.time - config->rescanTime > 0) || + (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || + (font_time.set && (font_time.time - config->rescanTime) > 0)) + { + /* We need to check for potential clock problems here (OLPC ticket #6046) */ + if ((config_time.set && (config_time.time - now) > 0) || + (config_dir_time.set && (config_dir_time.time - now) > 0) || + (font_time.set && (font_time.time - now) > 0)) + { + fprintf (stderr, + "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n"); + config->rescanTime = now; + return FcTrue; + } + else + return FcFalse; + } + config->rescanTime = now; + return FcTrue; +} + +static void +FcSubstDestroy (FcSubst *s) +{ + FcSubst *n; + + while (s) + { + n = s->next; + if (s->test) + FcTestDestroy (s->test); + if (s->edit) + FcEditDestroy (s->edit); + free (s); + FcMemFree (FC_MEM_SUBST, sizeof (FcSubst)); + s = n; + } +} + +FcExpr * +FcConfigAllocExpr (FcConfig *config) +{ + if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) + { + FcExprPage *new_page; + + new_page = malloc (sizeof (FcExprPage)); + if (!new_page) + return 0; + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage)); + + new_page->next_page = config->expr_pool; + new_page->next = new_page->exprs; + config->expr_pool = new_page; + } + + return config->expr_pool->next++; +} + +FcConfig * +FcConfigReference (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + + config->ref++; + + return config; +} + +void +FcConfigDestroy (FcConfig *config) +{ + FcSetName set; + FcExprPage *page; + + if (--config->ref > 0) + return; + + if (config == _fcConfig) + _fcConfig = 0; + + FcStrSetDestroy (config->configDirs); + FcStrSetDestroy (config->fontDirs); + FcStrSetDestroy (config->cacheDirs); + FcStrSetDestroy (config->configFiles); + FcStrSetDestroy (config->acceptGlobs); + FcStrSetDestroy (config->rejectGlobs); + FcFontSetDestroy (config->acceptPatterns); + FcFontSetDestroy (config->rejectPatterns); + + if (config->blanks) + FcBlanksDestroy (config->blanks); + + FcSubstDestroy (config->substPattern); + FcSubstDestroy (config->substFont); + FcSubstDestroy (config->substScan); + for (set = FcSetSystem; set <= FcSetApplication; set++) + if (config->fonts[set]) + FcFontSetDestroy (config->fonts[set]); + + page = config->expr_pool; + while (page) + { + FcExprPage *next = page->next_page; + FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage)); + free (page); + page = next; + } + + free (config); + FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); +} + +/* + * Add cache to configuration, adding fonts and directories + */ + +FcBool +FcConfigAddCache (FcConfig *config, FcCache *cache, + FcSetName set, FcStrSet *dirSet) +{ + FcFontSet *fs; + intptr_t *dirs; + int i; + + /* + * Add fonts + */ + fs = FcCacheSet (cache); + if (fs) + { + int nref = 0; + + for (i = 0; i < fs->nfont; i++) + { + FcPattern *font = FcFontSetFont (fs, i); + FcChar8 *font_file; + + /* + * Check to see if font is banned by filename + */ + if (FcPatternObjectGetString (font, FC_FILE_OBJECT, + 0, &font_file) == FcResultMatch && + !FcConfigAcceptFilename (config, font_file)) + { + continue; + } + + /* + * Check to see if font is banned by pattern + */ + if (!FcConfigAcceptFont (config, font)) + continue; + + nref++; + FcFontSetAdd (config->fonts[set], font); + } + FcDirCacheReference (cache, nref); + } + + /* + * Add directories + */ + dirs = FcCacheDirs (cache); + if (dirs) + { + for (i = 0; i < cache->dirs_count; i++) + { + FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); + if (FcConfigAcceptFilename (config, dir)) + FcStrSetAddFilename (dirSet, dir); + } + } + return FcTrue; +} + +static FcBool +FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) +{ + FcStrList *dirlist; + FcChar8 *dir; + FcCache *cache; + + dirlist = FcStrListCreate (dirSet); + if (!dirlist) + return FcFalse; + + while ((dir = FcStrListNext (dirlist))) + { + if (FcDebug () & FC_DBG_FONTSET) + printf ("adding fonts from%s\n", dir); + cache = FcDirCacheRead (dir, FcFalse, config); + if (!cache) + continue; + FcConfigAddCache (config, cache, set, dirSet); + FcDirCacheUnload (cache); + } + FcStrListDone (dirlist); + return FcTrue; +} + +/* + * Scan the current list of directories in the configuration + * and build the set of available fonts. + */ + +FcBool +FcConfigBuildFonts (FcConfig *config) +{ + FcFontSet *fonts; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + + fonts = FcFontSetCreate (); + if (!fonts) + return FcFalse; + + FcConfigSetFonts (config, fonts, FcSetSystem); + + if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) + return FcFalse; + if (FcDebug () & FC_DBG_FONTSET) + FcFontSetPrint (fonts); + return FcTrue; +} + +FcBool +FcConfigSetCurrent (FcConfig *config) +{ + if (config == _fcConfig) + return FcTrue; + + if (!config->fonts) + if (!FcConfigBuildFonts (config)) + return FcFalse; + + if (_fcConfig) + FcConfigDestroy (_fcConfig); + _fcConfig = config; + return FcTrue; +} + +FcConfig * +FcConfigGetCurrent (void) +{ + if (!_fcConfig) + if (!FcInit ()) + return 0; + return _fcConfig; +} + +FcBool +FcConfigAddConfigDir (FcConfig *config, + const FcChar8 *d) +{ + return FcStrSetAddFilename (config->configDirs, d); +} + +FcStrList * +FcConfigGetConfigDirs (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return FcStrListCreate (config->configDirs); +} + +FcBool +FcConfigAddFontDir (FcConfig *config, + const FcChar8 *d) +{ + return FcStrSetAddFilename (config->fontDirs, d); +} + +FcBool +FcConfigAddDir (FcConfig *config, + const FcChar8 *d) +{ + return (FcConfigAddConfigDir (config, d) && + FcConfigAddFontDir (config, d)); +} + +FcStrList * +FcConfigGetFontDirs (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return FcStrListCreate (config->fontDirs); +} + +FcBool +FcConfigAddCacheDir (FcConfig *config, + const FcChar8 *d) +{ + return FcStrSetAddFilename (config->cacheDirs, d); +} + +FcStrList * +FcConfigGetCacheDirs (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return FcStrListCreate (config->cacheDirs); +} + +FcBool +FcConfigAddConfigFile (FcConfig *config, + const FcChar8 *f) +{ + FcBool ret; + FcChar8 *file = FcConfigFilename (f); + + if (!file) + return FcFalse; + + ret = FcStrSetAdd (config->configFiles, file); + FcStrFree (file); + return ret; +} + +FcStrList * +FcConfigGetConfigFiles (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return FcStrListCreate (config->configFiles); +} + +FcChar8 * +FcConfigGetCache (FcConfig *config) +{ + return NULL; +} + +FcFontSet * +FcConfigGetFonts (FcConfig *config, + FcSetName set) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return config->fonts[set]; +} + +void +FcConfigSetFonts (FcConfig *config, + FcFontSet *fonts, + FcSetName set) +{ + if (config->fonts[set]) + FcFontSetDestroy (config->fonts[set]); + config->fonts[set] = fonts; +} + +FcBlanks * +FcConfigGetBlanks (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return config->blanks; +} + +FcBool +FcConfigAddBlank (FcConfig *config, + FcChar32 blank) +{ + FcBlanks *b, *freeme = 0; + + b = config->blanks; + if (!b) + { + freeme = b = FcBlanksCreate (); + if (!b) + return FcFalse; + } + if (!FcBlanksAdd (b, blank)) + { + if (freeme) + FcBlanksDestroy (freeme); + return FcFalse; + } + config->blanks = b; + return FcTrue; +} + +int +FcConfigGetRescanInterval (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + return config->rescanInterval; +} + +FcBool +FcConfigSetRescanInterval (FcConfig *config, int rescanInterval) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + config->rescanInterval = rescanInterval; + return FcTrue; +} + +/* + * A couple of typos escaped into the library + */ +int +FcConfigGetRescanInverval (FcConfig *config) +{ + return FcConfigGetRescanInterval (config); +} + +FcBool +FcConfigSetRescanInverval (FcConfig *config, int rescanInterval) +{ + return FcConfigSetRescanInterval (config, rescanInterval); +} + + +FcBool +FcConfigAddEdit (FcConfig *config, + FcTest *test, + FcEdit *edit, + FcMatchKind kind) +{ + FcSubst *subst, **prev; + FcTest *t; + int num; + + switch (kind) { + case FcMatchPattern: + prev = &config->substPattern; + break; + case FcMatchFont: + prev = &config->substFont; + break; + case FcMatchScan: + prev = &config->substScan; + break; + default: + return FcFalse; + } + subst = (FcSubst *) malloc (sizeof (FcSubst)); + if (!subst) + return FcFalse; + FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst)); + for (; *prev; prev = &(*prev)->next); + *prev = subst; + subst->next = 0; + subst->test = test; + subst->edit = edit; + num = 0; + for (t = test; t; t = t->next) + { + if (t->kind == FcMatchDefault) + t->kind = kind; + num++; + } + if (config->maxObjects < num) + config->maxObjects = num; + if (FcDebug () & FC_DBG_EDIT) + { + printf ("Add Subst "); + FcSubstPrint (subst); + } + return FcTrue; +} + +typedef struct _FcSubState { + FcPatternElt *elt; + FcValueList *value; +} FcSubState; + +static FcValue +FcConfigPromote (FcValue v, FcValue u) +{ + if (v.type == FcTypeInteger) + { + v.type = FcTypeDouble; + v.u.d = (double) v.u.i; + } + else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) + { + v.u.m = &FcIdentityMatrix; + v.type = FcTypeMatrix; + } + else if (v.type == FcTypeString && u.type == FcTypeLangSet) + { + v.u.l = FcLangSetPromote (v.u.s); + v.type = FcTypeLangSet; + } + return v; +} + +FcBool +FcConfigCompareValue (const FcValue *left_o, + FcOp op, + const FcValue *right_o) +{ + FcValue left = FcValueCanonicalize(left_o); + FcValue right = FcValueCanonicalize(right_o); + FcBool ret = FcFalse; + + left = FcConfigPromote (left, right); + right = FcConfigPromote (right, left); + if (left.type == right.type) + { + switch (left.type) { + case FcTypeInteger: + break; /* FcConfigPromote prevents this from happening */ + case FcTypeDouble: + switch (op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = left.u.d == right.u.d; + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = left.u.d != right.u.d; + break; + case FcOpLess: + ret = left.u.d < right.u.d; + break; + case FcOpLessEqual: + ret = left.u.d <= right.u.d; + break; + case FcOpMore: + ret = left.u.d > right.u.d; + break; + case FcOpMoreEqual: + ret = left.u.d >= right.u.d; + break; + default: + break; + } + break; + case FcTypeBool: + switch (op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = left.u.b == right.u.b; + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = left.u.b != right.u.b; + break; + default: + break; + } + break; + case FcTypeString: + switch (op) { + case FcOpEqual: + case FcOpListing: + ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; + break; + case FcOpContains: + ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; + break; + case FcOpNotEqual: + ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; + break; + case FcOpNotContains: + ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; + break; + default: + break; + } + break; + case FcTypeMatrix: + switch (op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = FcMatrixEqual (left.u.m, right.u.m); + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = !FcMatrixEqual (left.u.m, right.u.m); + break; + default: + break; + } + break; + case FcTypeCharSet: + switch (op) { + case FcOpContains: + case FcOpListing: + /* left contains right if right is a subset of left */ + ret = FcCharSetIsSubset (right.u.c, left.u.c); + break; + case FcOpNotContains: + /* left contains right if right is a subset of left */ + ret = !FcCharSetIsSubset (right.u.c, left.u.c); + break; + case FcOpEqual: + ret = FcCharSetEqual (left.u.c, right.u.c); + break; + case FcOpNotEqual: + ret = !FcCharSetEqual (left.u.c, right.u.c); + break; + default: + break; + } + break; + case FcTypeLangSet: + switch (op) { + case FcOpContains: + case FcOpListing: + ret = FcLangSetContains (left.u.l, right.u.l); + break; + case FcOpNotContains: + ret = !FcLangSetContains (left.u.l, right.u.l); + break; + case FcOpEqual: + ret = FcLangSetEqual (left.u.l, right.u.l); + break; + case FcOpNotEqual: + ret = !FcLangSetEqual (left.u.l, right.u.l); + break; + default: + break; + } + break; + case FcTypeVoid: + switch (op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = FcTrue; + break; + default: + break; + } + break; + case FcTypeFTFace: + switch (op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = left.u.f == right.u.f; + break; + case FcOpNotEqual: + case FcOpNotContains: + ret = left.u.f != right.u.f; + break; + default: + break; + } + break; + } + } + else + { + if (op == FcOpNotEqual || op == FcOpNotContains) + ret = FcTrue; + } + return ret; +} + + +#define _FcDoubleFloor(d) ((int) (d)) +#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) +#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) +#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) +#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) +#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) + +static FcValue +FcConfigEvaluate (FcPattern *p, FcExpr *e) +{ + FcValue v, vl, vr; + FcResult r; + FcMatrix *m; + FcChar8 *str; + + 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 FcOpLangSet: + v.type = FcTypeLangSet; + v.u.l = e->u.lval; + v = FcValueSave (v); + break; + case FcOpBool: + v.type = FcTypeBool; + v.u.b = e->u.bval; + break; + case FcOpField: + r = FcPatternObjectGet (p, e->u.object, 0, &v); + if (r != FcResultMatch) + v.type = FcTypeVoid; + v = FcValueSave (v); + break; + case FcOpConst: + if (FcNameConstant (e->u.constant, &v.u.i)) + v.type = FcTypeInteger; + else + v.type = FcTypeVoid; + break; + case FcOpQuest: + vl = FcConfigEvaluate (p, e->u.tree.left); + if (vl.type == FcTypeBool) + { + if (vl.u.b) + v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); + else + v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); + } + else + v.type = FcTypeVoid; + FcValueDestroy (vl); + break; + case FcOpEqual: + case FcOpNotEqual: + case FcOpLess: + case FcOpLessEqual: + case FcOpMore: + case FcOpMoreEqual: + case FcOpContains: + case FcOpNotContains: + case FcOpListing: + vl = FcConfigEvaluate (p, e->u.tree.left); + vr = FcConfigEvaluate (p, e->u.tree.right); + v.type = FcTypeBool; + v.u.b = FcConfigCompareValue (&vl, e->op, &vr); + FcValueDestroy (vl); + FcValueDestroy (vr); + break; + case FcOpOr: + case FcOpAnd: + 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; + 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; + default: + v.type = FcTypeVoid; + break; + } + break; + case FcTypeString: + switch (e->op) { + case FcOpPlus: + v.type = FcTypeString; + str = FcStrPlus (vl.u.s, vr.u.s); + v.u.s = FcStrStaticName (str); + FcStrFree (str); + + if (!v.u.s) + v.type = FcTypeVoid; + break; + default: + v.type = FcTypeVoid; + break; + } + break; + case FcTypeMatrix: + switch (e->op) { + case FcOpTimes: + v.type = FcTypeMatrix; + m = malloc (sizeof (FcMatrix)); + if (m) + { + FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); + FcMatrixMultiply (m, vl.u.m, vr.u.m); + v.u.m = m; + } + else + { + v.type = FcTypeVoid; + } + break; + default: + v.type = FcTypeVoid; + break; + } + break; + case FcTypeCharSet: + switch (e->op) { + case FcOpPlus: + v.type = FcTypeCharSet; + v.u.c = FcCharSetUnion (vl.u.c, vr.u.c); + if (!v.u.c) + v.type = FcTypeVoid; + break; + case FcOpMinus: + v.type = FcTypeCharSet; + v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c); + if (!v.u.c) + v.type = FcTypeVoid; + break; + default: + v.type = FcTypeVoid; + break; + } + break; + case FcTypeLangSet: + switch (e->op) { + case FcOpPlus: + v.type = FcTypeLangSet; + v.u.l = FcLangSetUnion (vl.u.l, vr.u.l); + if (!v.u.l) + v.type = FcTypeVoid; + break; + case FcOpMinus: + v.type = FcTypeLangSet; + v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l); + if (!v.u.l) + v.type = FcTypeVoid; + break; + default: + v.type = FcTypeVoid; + break; + } + break; + default: + v.type = FcTypeVoid; + break; + } + } + else + v.type = FcTypeVoid; + FcValueDestroy (vl); + FcValueDestroy (vr); + break; + case FcOpNot: + vl = FcConfigEvaluate (p, e->u.tree.left); + switch (vl.type) { + case FcTypeBool: + v.type = FcTypeBool; + v.u.b = !vl.u.b; + break; + default: + v.type = FcTypeVoid; + break; + } + FcValueDestroy (vl); + break; + case FcOpFloor: + vl = FcConfigEvaluate (p, e->u.tree.left); + switch (vl.type) { + case FcTypeInteger: + v = vl; + break; + case FcTypeDouble: + v.type = FcTypeInteger; + v.u.i = FcDoubleFloor (vl.u.d); + break; + default: + v.type = FcTypeVoid; + break; + } + FcValueDestroy (vl); + break; + case FcOpCeil: + vl = FcConfigEvaluate (p, e->u.tree.left); + switch (vl.type) { + case FcTypeInteger: + v = vl; + break; + case FcTypeDouble: + v.type = FcTypeInteger; + v.u.i = FcDoubleCeil (vl.u.d); + break; + default: + v.type = FcTypeVoid; + break; + } + FcValueDestroy (vl); + break; + case FcOpRound: + vl = FcConfigEvaluate (p, e->u.tree.left); + switch (vl.type) { + case FcTypeInteger: + v = vl; + break; + case FcTypeDouble: + v.type = FcTypeInteger; + v.u.i = FcDoubleRound (vl.u.d); + break; + default: + v.type = FcTypeVoid; + break; + } + FcValueDestroy (vl); + break; + case FcOpTrunc: + vl = FcConfigEvaluate (p, e->u.tree.left); + switch (vl.type) { + case FcTypeInteger: + v = vl; + break; + case FcTypeDouble: + v.type = FcTypeInteger; + v.u.i = FcDoubleTrunc (vl.u.d); + break; + default: + v.type = FcTypeVoid; + break; + } + FcValueDestroy (vl); + break; + default: + v.type = FcTypeVoid; + break; + } + return v; +} + +static FcValueList * +FcConfigMatchValueList (FcPattern *p, + FcTest *t, + FcValueList *values) +{ + FcValueList *ret = 0; + FcExpr *e = t->expr; + FcValue value; + FcValueList *v; + + while (e) + { + /* Compute the value of the match expression */ + if (e->op == FcOpComma) + { + value = FcConfigEvaluate (p, e->u.tree.left); + e = e->u.tree.right; + } + else + { + value = FcConfigEvaluate (p, e); + e = 0; + } + + for (v = values; v; v = FcValueListNext(v)) + { + /* Compare the pattern value to the match expression value */ + if (FcConfigCompareValue (&v->value, t->op, &value)) + { + if (!ret) + ret = v; + } + else + { + if (t->qual == FcQualAll) + { + ret = 0; + break; + } + } + } + FcValueDestroy (value); + } + return ret; +} + +static FcValueList * +FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding) +{ + 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, binding); + } + else + { + l->value = FcConfigEvaluate (p, e); + l->next = NULL; + } + l->binding = binding; + if (l->value.type == FcTypeVoid) + { + FcValueList *next = FcValueListNext(l); + + FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); + free (l); + l = next; + } + + return l; +} + +static FcBool +FcConfigAdd (FcValueListPtr *head, + FcValueList *position, + FcBool append, + FcValueList *new) +{ + FcValueListPtr *prev, last, v; + FcValueBinding sameBinding; + + if (position) + sameBinding = position->binding; + else + sameBinding = FcValueBindingWeak; + for (v = new; v != NULL; v = FcValueListNext(v)) + if (v->binding == FcValueBindingSame) + v->binding = sameBinding; + if (append) + { + if (position) + prev = &position->next; + else + for (prev = head; *prev != NULL; + prev = &(*prev)->next) + ; + } + else + { + if (position) + { + for (prev = head; *prev != NULL; + prev = &(*prev)->next) + { + if (*prev == position) + break; + } + } + else + prev = head; + + if (FcDebug () & FC_DBG_EDIT) + { + if (*prev == NULL) + 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 != NULL) + 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 (FcValueListPtr *head, + FcValueList *position) +{ + FcValueListPtr *prev; + + for (prev = head; *prev != NULL; prev = &(*prev)->next) + { + if (*prev == position) + { + *prev = position->next; + position->next = NULL; + FcValueListDestroy (position); + break; + } + } +} + +static void +FcConfigPatternAdd (FcPattern *p, + FcObject object, + FcValueList *list, + FcBool append) +{ + if (list) + { + FcPatternElt *e = FcPatternObjectInsertElt (p, object); + + if (!e) + return; + FcConfigAdd (&e->values, 0, append, list); + } +} + +/* + * Delete all values associated with a field + */ +static void +FcConfigPatternDel (FcPattern *p, + FcObject object) +{ + FcPatternElt *e = FcPatternObjectFindElt (p, object); + if (!e) + return; + while (e->values != NULL) + FcConfigDel (&e->values, e->values); +} + +static void +FcConfigPatternCanon (FcPattern *p, + FcObject object) +{ + FcPatternElt *e = FcPatternObjectFindElt (p, object); + if (!e) + return; + if (e->values == NULL) + FcPatternObjectDel (p, object); +} + +FcBool +FcConfigSubstituteWithPat (FcConfig *config, + FcPattern *p, + FcPattern *p_pat, + FcMatchKind kind) +{ + FcSubst *s; + FcSubState *st; + int i; + FcTest *t; + FcEdit *e; + FcValueList *l; + FcPattern *m; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + + switch (kind) { + case FcMatchPattern: + s = config->substPattern; + break; + case FcMatchFont: + s = config->substFont; + break; + case FcMatchScan: + s = config->substScan; + break; + default: + return FcFalse; + } + + st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); + if (!st && config->maxObjects) + return FcFalse; + FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); + + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute "); + FcPatternPrint (p); + } + for (; s; s = s->next) + { + /* + * Check the tests to see if + * they all match the pattern + */ + for (t = s->test, i = 0; t; t = t->next, i++) + { + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute test "); + FcTestPrint (t); + } + st[i].elt = 0; + if (kind == FcMatchFont && t->kind == FcMatchPattern) + m = p_pat; + else + m = p; + if (m) + st[i].elt = FcPatternObjectFindElt (m, t->object); + else + st[i].elt = 0; + /* + * If there's no such field in the font, + * then FcQualAll matches while FcQualAny does not + */ + if (!st[i].elt) + { + if (t->qual == FcQualAll) + { + st[i].value = 0; + continue; + } + else + break; + } + /* + * Check to see if there is a match, mark the location + * to apply match-relative edits + */ + st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values); + if (!st[i].value) + break; + if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) + break; + if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) + break; + } + 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, e->binding); + /* + * Locate any test associated with this field, skipping + * tests associated with the pattern when substituting in + * the font + */ + for (t = s->test, i = 0; t; t = t->next, i++) + { + if ((t->kind == FcMatchFont || kind == FcMatchPattern) && + t->object == e->object) + { + /* + * KLUDGE - the pattern may have been reallocated or + * things may have been inserted or deleted above + * this element by other edits. Go back and find + * the element again + */ + if (e != s->edit && st[i].elt) + st[i].elt = FcPatternObjectFindElt (p, t->object); + if (!st[i].elt) + t = 0; + 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; + + /* + * Append the new list of values after the current value + */ + FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l); + /* + * Delete the marked value + */ + if (thisValue) + FcConfigDel (&st[i].elt->values, thisValue); + /* + * Adjust any pointers into the value list to ensure + * future edits occur at the same place + */ + for (t = s->test, i = 0; t; t = t->next, i++) + { + if (st[i].value == thisValue) + st[i].value = nextValue; + } + break; + } + /* fall through ... */ + case FcOpAssignReplace: + /* + * Delete all of the values and insert + * the new set + */ + FcConfigPatternDel (p, e->object); + FcConfigPatternAdd (p, e->object, l, FcTrue); + /* + * Adjust any pointers into the value list as they no + * longer point to anything valid + */ + if (t) + { + FcPatternElt *thisElt = st[i].elt; + for (t = s->test, i = 0; t; t = t->next, i++) + { + if (st[i].elt == thisElt) + st[i].value = 0; + } + } + break; + case FcOpPrepend: + if (t) + { + FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l); + break; + } + /* fall through ... */ + case FcOpPrependFirst: + FcConfigPatternAdd (p, e->object, l, FcFalse); + break; + case FcOpAppend: + if (t) + { + FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l); + break; + } + /* fall through ... */ + case FcOpAppendLast: + FcConfigPatternAdd (p, e->object, l, FcTrue); + break; + default: + FcValueListDestroy (l); + break; + } + } + /* + * Now go through the pattern and eliminate + * any properties without data + */ + for (e = s->edit; e; e = e->next) + FcConfigPatternCanon (p, e->object); + + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute edit"); + FcPatternPrint (p); + } + } + FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); + free (st); + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute done"); + FcPatternPrint (p); + } + return FcTrue; +} + +FcBool +FcConfigSubstitute (FcConfig *config, + FcPattern *p, + FcMatchKind kind) +{ + return FcConfigSubstituteWithPat (config, p, 0, kind); +} + +#if defined (_WIN32) + +# define WIN32_LEAN_AND_MEAN +# define WIN32_EXTRA_LEAN +# include <windows.h> + +static FcChar8 fontconfig_path[1000] = ""; + +# if (defined (PIC) || defined (DLL_EXPORT)) + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + FcChar8 *p; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path, + sizeof (fontconfig_path))) + break; + + /* If the fontconfig DLL is in a "bin" or "lib" subfolder, + * assume it's a Unix-style installation tree, and use + * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the + * folder where the DLL is as FONTCONFIG_PATH. + */ + p = strrchr (fontconfig_path, '\\'); + if (p) + { + *p = '\0'; + p = strrchr (fontconfig_path, '\\'); + if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 || + FcStrCmpIgnoreCase (p + 1, "lib") == 0)) + *p = '\0'; + strcat (fontconfig_path, "\\etc\\fonts"); + } + else + fontconfig_path[0] = '\0'; + + break; + } + + return TRUE; +} + +# endif /* !PIC */ + +#undef FONTCONFIG_PATH +#define FONTCONFIG_PATH fontconfig_path + +#endif /* !_WIN32 */ + +#ifndef FONTCONFIG_FILE +#define FONTCONFIG_FILE "fonts.conf" +#endif + +static FcChar8 * +FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) +{ + FcChar8 *path; + int size; + + if (!dir) + dir = (FcChar8 *) ""; + + size = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; + /* + * workaround valgrind warning because glibc takes advantage of how it knows memory is + * allocated to implement strlen by reading in groups of 4 + */ + size = (size + 3) & ~3; + + path = malloc (size); + if (!path) + return 0; + + strcpy ((char *) path, (const char *) dir); + /* make sure there's a single separator */ +#ifdef _WIN32 + if ((!path[0] || (path[strlen((char *) path)-1] != '/' && + path[strlen((char *) path)-1] != '\\')) && + !(file[0] == '/' || + file[0] == '\\' || + (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) + strcat ((char *) path, "\\"); +#else + if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') + strcat ((char *) path, "/"); +#endif + strcat ((char *) path, (char *) file); + + FcMemAlloc (FC_MEM_STRING, size); + if (access ((char *) path, R_OK) == 0) + return path; + + FcStrFree (path); + return 0; +} + +static FcChar8 ** +FcConfigGetPath (void) +{ + FcChar8 **path; + FcChar8 *env, *e, *colon; + FcChar8 *dir; + int npath; + int i; + + npath = 2; /* default dir + null */ + env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); + if (env) + { + e = env; + npath++; + while (*e) + if (*e++ == FC_SEARCH_PATH_SEPARATOR) + npath++; + } + path = calloc (npath, sizeof (FcChar8 *)); + if (!path) + goto bail0; + i = 0; + + if (env) + { + e = env; + while (*e) + { + colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); + if (!colon) + colon = e + strlen ((char *) e); + path[i] = malloc (colon - e + 1); + if (!path[i]) + goto bail1; + strncpy ((char *) path[i], (const char *) e, colon - e); + path[i][colon - e] = '\0'; + if (*colon) + e = colon + 1; + else + e = colon; + i++; + } + } + +#ifdef _WIN32 + if (fontconfig_path[0] == '\0') + { + char *p; + if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path))) + goto bail1; + p = strrchr (fontconfig_path, '\\'); + if (p) *p = '\0'; + strcat (fontconfig_path, "\\fonts"); + } +#endif + dir = (FcChar8 *) FONTCONFIG_PATH; + path[i] = malloc (strlen ((char *) dir) + 1); + if (!path[i]) + goto bail1; + strcpy ((char *) path[i], (const char *) dir); + return path; + +bail1: + for (i = 0; path[i]; i++) + free (path[i]); + free (path); +bail0: + return 0; +} + +static void +FcConfigFreePath (FcChar8 **path) +{ + FcChar8 **p; + + for (p = path; *p; p++) + free (*p); + free (path); +} + +static FcBool _FcConfigHomeEnabled = FcTrue; + +FcChar8 * +FcConfigHome (void) +{ + if (_FcConfigHomeEnabled) + { + char *home = getenv ("HOME"); + +#ifdef _WIN32 + if (home == NULL) + home = getenv ("USERPROFILE"); +#endif + + return (FcChar8 *) home; + } + return 0; +} + +FcBool +FcConfigEnableHome (FcBool enable) +{ + FcBool prev = _FcConfigHomeEnabled; + _FcConfigHomeEnabled = enable; + return prev; +} + +FcChar8 * +FcConfigFilename (const FcChar8 *url) +{ + FcChar8 *file, *dir, **path, **p; + + if (!url || !*url) + { + url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); + if (!url) + url = (FcChar8 *) FONTCONFIG_FILE; + } + file = 0; + +#ifdef _WIN32 + if (isalpha (*url) && + url[1] == ':' && + (url[2] == '/' || url[2] == '\\')) + goto absolute_path; +#endif + + switch (*url) { + case '~': + dir = FcConfigHome (); + if (dir) + file = FcConfigFileExists (dir, url + 1); + else + file = 0; + break; +#ifdef _WIN32 + case '\\': + absolute_path: +#endif + case '/': + file = FcConfigFileExists (0, url); + break; + default: + path = FcConfigGetPath (); + if (!path) + return 0; + for (p = path; *p; p++) + { + file = FcConfigFileExists (*p, url); + if (file) + break; + } + FcConfigFreePath (path); + break; + } + return file; +} + +/* + * Manage the application-specific fonts + */ + +FcBool +FcConfigAppFontAddFile (FcConfig *config, + const FcChar8 *file) +{ + FcFontSet *set; + FcStrSet *subdirs; + FcStrList *sublist; + FcChar8 *subdir; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + + subdirs = FcStrSetCreate (); + if (!subdirs) + return FcFalse; + + set = FcConfigGetFonts (config, FcSetApplication); + if (!set) + { + set = FcFontSetCreate (); + if (!set) + { + FcStrSetDestroy (subdirs); + return FcFalse; + } + FcConfigSetFonts (config, set, FcSetApplication); + } + + if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) + { + FcStrSetDestroy (subdirs); + return FcFalse; + } + if ((sublist = FcStrListCreate (subdirs))) + { + while ((subdir = FcStrListNext (sublist))) + { + FcConfigAppFontAddDir (config, subdir); + } + FcStrListDone (sublist); + } + FcStrSetDestroy (subdirs); + return FcTrue; +} + +FcBool +FcConfigAppFontAddDir (FcConfig *config, + const FcChar8 *dir) +{ + FcFontSet *set; + FcStrSet *dirs; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + + dirs = FcStrSetCreate (); + if (!dirs) + return FcFalse; + + set = FcConfigGetFonts (config, FcSetApplication); + if (!set) + { + set = FcFontSetCreate (); + if (!set) + { + FcStrSetDestroy (dirs); + return FcFalse; + } + FcConfigSetFonts (config, set, FcSetApplication); + } + + FcStrSetAddFilename (dirs, dir); + + if (!FcConfigAddDirList (config, FcSetApplication, dirs)) + { + FcStrSetDestroy (dirs); + return FcFalse; + } + FcStrSetDestroy (dirs); + return FcTrue; +} + +void +FcConfigAppFontClear (FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return; + } + + FcConfigSetFonts (config, 0, FcSetApplication); +} + +/* + * Manage filename-based font source selectors + */ + +FcBool +FcConfigGlobAdd (FcConfig *config, + const FcChar8 *glob, + FcBool accept) +{ + FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; + + return FcStrSetAdd (set, glob); +} + +static FcBool +FcConfigGlobMatch (const FcChar8 *glob, + const FcChar8 *string) +{ + FcChar8 c; + + while ((c = *glob++)) + { + switch (c) { + case '*': + /* short circuit common case */ + if (!*glob) + return FcTrue; + /* short circuit another common case */ + if (strchr ((char *) glob, '*') == 0) + string += strlen ((char *) string) - strlen ((char *) glob); + while (*string) + { + if (FcConfigGlobMatch (glob, string)) + return FcTrue; + string++; + } + return FcFalse; + case '?': + if (*string++ == '\0') + return FcFalse; + break; + default: + if (*string++ != c) + return FcFalse; + break; + } + } + return *string == '\0'; +} + +static FcBool +FcConfigGlobsMatch (const FcStrSet *globs, + const FcChar8 *string) +{ + int i; + + for (i = 0; i < globs->num; i++) + if (FcConfigGlobMatch (globs->strs[i], string)) + return FcTrue; + return FcFalse; +} + +FcBool +FcConfigAcceptFilename (FcConfig *config, + const FcChar8 *filename) +{ + if (FcConfigGlobsMatch (config->acceptGlobs, filename)) + return FcTrue; + if (FcConfigGlobsMatch (config->rejectGlobs, filename)) + return FcFalse; + return FcTrue; +} + +/* + * Manage font-pattern based font source selectors + */ + +FcBool +FcConfigPatternsAdd (FcConfig *config, + FcPattern *pattern, + FcBool accept) +{ + FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; + + return FcFontSetAdd (set, pattern); +} + +static FcBool +FcConfigPatternsMatch (const FcFontSet *patterns, + const FcPattern *font) +{ + int i; + + for (i = 0; i < patterns->nfont; i++) + if (FcListPatternMatchAny (patterns->fonts[i], font)) + return FcTrue; + return FcFalse; +} + +FcBool +FcConfigAcceptFont (FcConfig *config, + const FcPattern *font) +{ + if (FcConfigPatternsMatch (config->acceptPatterns, font)) + return FcTrue; + if (FcConfigPatternsMatch (config->rejectPatterns, font)) + return FcFalse; + return FcTrue; +} +#define __fccfg__ +#include "fcaliastail.h" +#undef __fccfg__ diff --git a/fontconfig/src/fccharset.c b/fontconfig/src/fccharset.c index 54e396bce..df1d2b538 100644 --- a/fontconfig/src/fccharset.c +++ b/fontconfig/src/fccharset.c @@ -1,1439 +1,1439 @@ -/*
- * fontconfig/src/fccharset.c
- *
- * Copyright © 2001 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdlib.h>
-
-/* #define CHECK */
-
-FcCharSet *
-FcCharSetCreate (void)
-{
- FcCharSet *fcs;
-
- fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
- if (!fcs)
- return 0;
- FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
- fcs->ref = 1;
- fcs->num = 0;
- fcs->leaves_offset = 0;
- fcs->numbers_offset = 0;
- return fcs;
-}
-
-FcCharSet *
-FcCharSetNew (void)
-{
- return FcCharSetCreate ();
-}
-
-void
-FcCharSetDestroy (FcCharSet *fcs)
-{
- int i;
-
- if (fcs->ref == FC_REF_CONSTANT)
- {
- FcCacheObjectDereference (fcs);
- return;
- }
- if (--fcs->ref > 0)
- return;
- for (i = 0; i < fcs->num; i++)
- {
- FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
- free (FcCharSetLeaf (fcs, i));
- }
- if (fcs->num)
- {
- /* the numbers here are estimates */
- FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
- free (FcCharSetLeaves (fcs));
- FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
- free (FcCharSetNumbers (fcs));
- }
- FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
- free (fcs);
-}
-
-/*
- * Search for the leaf containing with the specified num.
- * Return its index if it exists, otherwise return negative of
- * the (position + 1) where it should be inserted
- */
-
-
-static int
-FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num)
-{
- FcChar16 *numbers = FcCharSetNumbers(fcs);
- FcChar16 page;
- int low = start;
- int high = fcs->num - 1;
-
- if (!numbers)
- return -1;
- while (low <= high)
- {
- int mid = (low + high) >> 1;
- page = numbers[mid];
- if (page == num)
- return mid;
- if (page < num)
- low = mid + 1;
- else
- high = mid - 1;
- }
- if (high < 0 || (high < fcs->num && numbers[high] < num))
- high++;
- return -(high + 1);
-}
-
-/*
- * Locate the leaf containing the specified char, return
- * its index if it exists, otherwise return negative of
- * the (position + 1) where it should be inserted
- */
-
-static int
-FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
-{
- return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
-}
-
-static FcCharLeaf *
-FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
-{
- int pos = FcCharSetFindLeafPos (fcs, ucs4);
- if (pos >= 0)
- return FcCharSetLeaf(fcs, pos);
- return 0;
-}
-
-#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
-
-static FcBool
-FcCharSetPutLeaf (FcCharSet *fcs,
- FcChar32 ucs4,
- FcCharLeaf *leaf,
- int pos)
-{
- intptr_t *leaves = FcCharSetLeaves (fcs);
- FcChar16 *numbers = FcCharSetNumbers (fcs);
-
- ucs4 >>= 8;
- if (ucs4 >= 0x10000)
- return FcFalse;
-
- if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
- {
- if (!fcs->num)
- {
- unsigned int alloced = 8;
- leaves = malloc (alloced * sizeof (*leaves));
- numbers = malloc (alloced * sizeof (*numbers));
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
- }
- else
- {
- unsigned int alloced = fcs->num;
- intptr_t *new_leaves, distance;
-
- FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*leaves));
- FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*numbers));
-
- alloced *= 2;
- new_leaves = realloc (leaves, alloced * sizeof (*leaves));
- numbers = realloc (numbers, alloced * sizeof (*numbers));
-
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
-
- distance = (intptr_t) new_leaves - (intptr_t) leaves;
- if (new_leaves && distance)
- {
- int i;
- for (i = 0; i < fcs->num; i++)
- new_leaves[i] -= distance;
- }
- leaves = new_leaves;
- }
-
- if (!leaves || !numbers)
- return FcFalse;
-
- fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
- fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
- }
-
- memmove (leaves + pos + 1, leaves + pos,
- (fcs->num - pos) * sizeof (*leaves));
- memmove (numbers + pos + 1, numbers + pos,
- (fcs->num - pos) * sizeof (*numbers));
- numbers[pos] = (FcChar16) ucs4;
- leaves[pos] = FcPtrToOffset (leaves, leaf);
- fcs->num++;
- return FcTrue;
-}
-
-/*
- * Locate the leaf containing the specified char, creating it
- * if desired
- */
-
-FcCharLeaf *
-FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
-{
- int pos;
- FcCharLeaf *leaf;
-
- pos = FcCharSetFindLeafPos (fcs, ucs4);
- if (pos >= 0)
- return FcCharSetLeaf(fcs, pos);
-
- leaf = calloc (1, sizeof (FcCharLeaf));
- if (!leaf)
- return 0;
-
- pos = -pos - 1;
- if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
- {
- free (leaf);
- return 0;
- }
- FcMemAlloc (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
- return leaf;
-}
-
-static FcBool
-FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
-{
- int pos;
-
- pos = FcCharSetFindLeafPos (fcs, ucs4);
- if (pos >= 0)
- {
- FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
- free (FcCharSetLeaf (fcs, pos));
- FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
- leaf);
- return FcTrue;
- }
- pos = -pos - 1;
- return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
-}
-
-FcBool
-FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
-{
- FcCharLeaf *leaf;
- FcChar32 *b;
-
- if (fcs->ref == FC_REF_CONSTANT)
- return FcFalse;
- leaf = FcCharSetFindLeafCreate (fcs, ucs4);
- if (!leaf)
- return FcFalse;
- b = &leaf->map[(ucs4 & 0xff) >> 5];
- *b |= (1 << (ucs4 & 0x1f));
- return FcTrue;
-}
-
-FcBool
-FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
-{
- FcCharLeaf *leaf;
- FcChar32 *b;
-
- if (fcs->ref == FC_REF_CONSTANT)
- return FcFalse;
- leaf = FcCharSetFindLeaf (fcs, ucs4);
- if (!leaf)
- return FcTrue;
- b = &leaf->map[(ucs4 & 0xff) >> 5];
- *b &= ~(1 << (ucs4 & 0x1f));
- /* We don't bother removing the leaf if it's empty */
- return FcTrue;
-}
-
-/*
- * An iterator for the leaves of a charset
- */
-
-typedef struct _fcCharSetIter {
- FcCharLeaf *leaf;
- FcChar32 ucs4;
- int pos;
-} FcCharSetIter;
-
-/*
- * Set iter->leaf to the leaf containing iter->ucs4 or higher
- */
-
-static void
-FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
-{
- int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
-
- if (pos < 0)
- {
- pos = -pos - 1;
- if (pos == fcs->num)
- {
- iter->ucs4 = ~0;
- iter->leaf = 0;
- return;
- }
- iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
- }
- iter->leaf = FcCharSetLeaf(fcs, pos);
- iter->pos = pos;
-}
-
-static void
-FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
-{
- int pos = iter->pos + 1;
- if (pos >= fcs->num)
- {
- iter->ucs4 = ~0;
- iter->leaf = 0;
- }
- else
- {
- iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
- iter->leaf = FcCharSetLeaf(fcs, pos);
- iter->pos = pos;
- }
-}
-
-
-static void
-FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
-{
- iter->ucs4 = 0;
- iter->pos = 0;
- FcCharSetIterSet (fcs, iter);
-}
-
-FcCharSet *
-FcCharSetCopy (FcCharSet *src)
-{
- if (src->ref != FC_REF_CONSTANT)
- src->ref++;
- else
- FcCacheObjectReference (src);
- 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)) && (bi.leaf || (aonly && ai.leaf)))
- {
- 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);
-}
-
-FcBool
-FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
-{
- int ai = 0, bi = 0;
- FcChar16 an, bn;
-
- if (a->ref == FC_REF_CONSTANT) {
- if (changed)
- *changed = FcFalse;
- return FcFalse;
- }
-
- if (changed) {
- *changed = !FcCharSetIsSubset(b, a);
- if (!*changed)
- return FcTrue;
- }
-
- while (bi < b->num)
- {
- an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
- bn = FcCharSetNumbers(b)[bi];
-
- if (an < bn)
- {
- ai = FcCharSetFindLeafForward (a, ai + 1, bn);
- if (ai < 0)
- ai = -ai - 1;
- }
- else
- {
- FcCharLeaf *bl = FcCharSetLeaf(b, bi);
- if (bn < an)
- {
- if (!FcCharSetAddLeaf (a, bn << 8, bl))
- return FcFalse;
- }
- else
- {
- FcCharLeaf *al = FcCharSetLeaf(a, ai);
- FcCharSetUnionLeaf (al, al, bl);
- }
-
- ai++;
- bi++;
- }
- }
-
- return 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)
-{
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
- return __builtin_popcount (c1);
-#else
- /* hackmem 169 */
- FcChar32 c2 = (c1 >> 1) & 033333333333;
- c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
- return (((c2 + (c2 >> 3)) & 030707070707) % 077);
-#endif
-}
-
-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;
-}
-
-/*
- * return FcTrue iff a is a subset of b
- */
-FcBool
-FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
-{
- int ai, bi;
- FcChar16 an, bn;
-
- if (a == b) return FcTrue;
- bi = 0;
- ai = 0;
- while (ai < a->num && bi < b->num)
- {
- an = FcCharSetNumbers(a)[ai];
- bn = FcCharSetNumbers(b)[bi];
- /*
- * Check matching pages
- */
- if (an == bn)
- {
- FcChar32 *am = FcCharSetLeaf(a, ai)->map;
- FcChar32 *bm = FcCharSetLeaf(b, bi)->map;
-
- if (am != bm)
- {
- int i = 256/32;
- /*
- * Does am have any bits not in bm?
- */
- while (i--)
- if (*am++ & ~*bm++)
- return FcFalse;
- }
- ai++;
- bi++;
- }
- /*
- * Does a have any pages not in b?
- */
- else if (an < bn)
- return FcFalse;
- else
- {
- bi = FcCharSetFindLeafForward (b, bi + 1, an);
- if (bi < 0)
- bi = -bi - 1;
- }
- }
- /*
- * did we look at every page?
- */
- return ai >= a->num;
-}
-
-/*
- * These two functions efficiently walk the entire charmap for
- * other software (like pango) that want their own copy
- */
-
-FcChar32
-FcCharSetNextPage (const FcCharSet *a,
- FcChar32 map[FC_CHARSET_MAP_SIZE],
- FcChar32 *next)
-{
- FcCharSetIter ai;
- FcChar32 page;
-
- ai.ucs4 = *next;
- FcCharSetIterSet (a, &ai);
- if (!ai.leaf)
- return FC_CHARSET_DONE;
-
- /*
- * Save current information
- */
- page = ai.ucs4;
- memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
- /*
- * Step to next page
- */
- FcCharSetIterNext (a, &ai);
- *next = ai.ucs4;
-
- return page;
-}
-
-FcChar32
-FcCharSetFirstPage (const FcCharSet *a,
- FcChar32 map[FC_CHARSET_MAP_SIZE],
- FcChar32 *next)
-{
- *next = 0;
- return FcCharSetNextPage (a, map, next);
-}
-
-/*
- * old coverage API, rather hard to use correctly
- */
-
-FcChar32
-FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
-{
- FcCharSetIter ai;
-
- ai.ucs4 = page;
- FcCharSetIterSet (a, &ai);
- if (!ai.leaf)
- {
- memset (result, '\0', 256 / 8);
- page = 0;
- }
- else
- {
- memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
- FcCharSetIterNext (a, &ai);
- page = ai.ucs4;
- }
- return page;
-}
-
-/*
- * 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 const unsigned char 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 const 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;
- FcChar32 c;
-
- if (*string == ' ')
- {
- v = 0;
- string++;
- }
- else
- {
- v = 0;
- for (i = 0; i < 5; i++)
- {
- if (!(c = (FcChar32) (unsigned char) *string++))
- return 0;
- c = charToValue[c];
- if (c == 0xff)
- return 0;
- v = v * 85 + c;
- }
- }
- *value = v;
- return string;
-}
-
-static FcBool
-FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value)
-{
- int i;
- if (value == 0)
- {
- return FcStrBufChar (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 (!FcStrBufChar (buf, *s++))
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcCharSet *
-FcNameParseCharSet (FcChar8 *string)
-{
- FcCharSet *c;
- FcChar32 ucs4;
- FcCharLeaf *leaf;
- FcCharLeaf temp;
- FcChar32 bits;
- int i;
-
- c = FcCharSetCreate ();
- if (!c)
- goto bail0;
- while (*string)
- {
- string = FcCharSetParseValue (string, &ucs4);
- if (!string)
- goto bail1;
- bits = 0;
- for (i = 0; i < 256/32; i++)
- {
- string = FcCharSetParseValue (string, &temp.map[i]);
- if (!string)
- goto bail1;
- bits |= temp.map[i];
- }
- if (bits)
- {
- leaf = malloc (sizeof (FcCharLeaf));
- if (!leaf)
- goto bail1;
- *leaf = temp;
- if (!FcCharSetInsertLeaf (c, ucs4, leaf))
- goto bail1;
- }
- }
- return c;
-bail1:
- if (c->num)
- {
- FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
- free (FcCharSetLeaves (c));
- }
- if (c->num)
- {
- FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
- free (FcCharSetNumbers (c));
- }
- FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
- free (c);
-bail0:
- return NULL;
-}
-
-FcBool
-FcNameUnparseCharSet (FcStrBuf *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 */
- FcStrBufChar (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;
-}
-
-typedef struct _FcCharLeafEnt FcCharLeafEnt;
-
-struct _FcCharLeafEnt {
- FcCharLeafEnt *next;
- FcChar32 hash;
- FcCharLeaf leaf;
-};
-
-#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt))
-#define FC_CHAR_LEAF_HASH_SIZE 257
-
-typedef struct _FcCharSetEnt FcCharSetEnt;
-
-struct _FcCharSetEnt {
- FcCharSetEnt *next;
- FcChar32 hash;
- FcCharSet set;
-};
-
-typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
-
-struct _FcCharSetOrigEnt {
- FcCharSetOrigEnt *next;
- const FcCharSet *orig;
- const FcCharSet *frozen;
-};
-
-#define FC_CHAR_SET_HASH_SIZE 67
-
-struct _FcCharSetFreezer {
- FcCharLeafEnt *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
- FcCharLeafEnt **leaf_blocks;
- int leaf_block_count;
- FcCharSetEnt *set_hash_table[FC_CHAR_SET_HASH_SIZE];
- FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE];
- FcCharLeafEnt *current_block;
- int leaf_remain;
- int leaves_seen;
- int charsets_seen;
- int leaves_allocated;
- int charsets_allocated;
-};
-
-static FcCharLeafEnt *
-FcCharLeafEntCreate (FcCharSetFreezer *freezer)
-{
- if (!freezer->leaf_remain)
- {
- FcCharLeafEnt **newBlocks;
-
- freezer->leaf_block_count++;
- newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
- if (!newBlocks)
- return 0;
- freezer->leaf_blocks = newBlocks;
- freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
- if (!freezer->current_block)
- return 0;
- FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
- freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
- }
- freezer->leaf_remain--;
- freezer->leaves_allocated++;
- return freezer->current_block++;
-}
-
-static FcChar32
-FcCharLeafHash (FcCharLeaf *leaf)
-{
- FcChar32 hash = 0;
- int i;
-
- for (i = 0; i < 256/32; i++)
- hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
- return hash;
-}
-
-static FcCharLeaf *
-FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
-{
- FcChar32 hash = FcCharLeafHash (leaf);
- FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
- FcCharLeafEnt *ent;
-
- for (ent = *bucket; ent; ent = ent->next)
- {
- if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
- return &ent->leaf;
- }
-
- ent = FcCharLeafEntCreate(freezer);
- if (!ent)
- return 0;
- ent->leaf = *leaf;
- ent->hash = hash;
- ent->next = *bucket;
- *bucket = ent;
- return &ent->leaf;
-}
-
-static FcChar32
-FcCharSetHash (FcCharSet *fcs)
-{
- FcChar32 hash = 0;
- int i;
-
- /* hash in leaves */
- for (i = 0; i < fcs->num; i++)
- hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i));
- /* hash in numbers */
- for (i = 0; i < fcs->num; i++)
- hash = ((hash << 1) | (hash >> 31)) ^ *FcCharSetNumbers(fcs);
- return hash;
-}
-
-static FcBool
-FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
-{
- FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
- FcCharSetOrigEnt *ent;
-
- ent = malloc (sizeof (FcCharSetOrigEnt));
- if (!ent)
- return FcFalse;
- ent->orig = orig;
- ent->frozen = frozen;
- ent->next = *bucket;
- *bucket = ent;
- return FcTrue;
-}
-
-static FcCharSet *
-FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig)
-{
- FcChar32 hash = FcCharSetHash (fcs);
- FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
- FcCharSetEnt *ent;
- int size;
- int i;
-
- for (ent = *bucket; ent; ent = ent->next)
- {
- if (ent->hash == hash &&
- ent->set.num == fcs->num &&
- !memcmp (FcCharSetNumbers(&ent->set),
- FcCharSetNumbers(fcs),
- fcs->num * sizeof (FcChar16)))
- {
- FcBool ok = FcTrue;
- int i;
-
- for (i = 0; i < fcs->num; i++)
- if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
- ok = FcFalse;
- if (ok)
- return &ent->set;
- }
- }
-
- size = (sizeof (FcCharSetEnt) +
- fcs->num * sizeof (FcCharLeaf *) +
- fcs->num * sizeof (FcChar16));
- ent = malloc (size);
- if (!ent)
- return 0;
- FcMemAlloc (FC_MEM_CHARSET, size);
-
- freezer->charsets_allocated++;
-
- ent->set.ref = FC_REF_CONSTANT;
- ent->set.num = fcs->num;
- if (fcs->num)
- {
- intptr_t *ent_leaves;
-
- ent->set.leaves_offset = sizeof (ent->set);
- ent->set.numbers_offset = (ent->set.leaves_offset +
- fcs->num * sizeof (intptr_t));
-
- ent_leaves = FcCharSetLeaves (&ent->set);
- for (i = 0; i < fcs->num; i++)
- ent_leaves[i] = FcPtrToOffset (ent_leaves,
- FcCharSetLeaf (fcs, i));
- memcpy (FcCharSetNumbers (&ent->set),
- FcCharSetNumbers (fcs),
- fcs->num * sizeof (FcChar16));
- }
- else
- {
- ent->set.leaves_offset = 0;
- ent->set.numbers_offset = 0;
- }
-
- ent->hash = hash;
- ent->next = *bucket;
- *bucket = ent;
-
- return &ent->set;
-}
-
-static const FcCharSet *
-FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
-{
- FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
- FcCharSetOrigEnt *ent;
-
- for (ent = *bucket; ent; ent = ent->next)
- if (ent->orig == orig)
- return ent->frozen;
- return NULL;
-}
-
-const FcCharSet *
-FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
-{
- FcCharSet *b;
- const FcCharSet *n = 0;
- FcCharLeaf *l;
- int i;
-
- b = FcCharSetCreate ();
- if (!b)
- goto bail0;
- for (i = 0; i < fcs->num; i++)
- {
- l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
- if (!l)
- goto bail1;
- if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
- goto bail1;
- }
- n = FcCharSetFreezeBase (freezer, b, fcs);
- if (!FcCharSetFreezeOrig (freezer, fcs, n))
- {
- n = NULL;
- goto bail1;
- }
- freezer->charsets_seen++;
- freezer->leaves_seen += fcs->num;
-bail1:
- if (b->num)
- {
- FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *));
- free (FcCharSetLeaves (b));
- }
- if (b->num)
- {
- FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16));
- free (FcCharSetNumbers (b));
- }
- FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
- free (b);
-bail0:
- return n;
-}
-
-FcCharSetFreezer *
-FcCharSetFreezerCreate (void)
-{
- FcCharSetFreezer *freezer;
-
- freezer = calloc (1, sizeof (FcCharSetFreezer));
- return freezer;
-}
-
-void
-FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
-{
- int i;
-
- if (FcDebug() & FC_DBG_CACHE)
- {
- printf ("\ncharsets %d -> %d leaves %d -> %d\n",
- freezer->charsets_seen, freezer->charsets_allocated,
- freezer->leaves_seen, freezer->leaves_allocated);
- }
- for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
- {
- FcCharSetEnt *ent, *next;
- for (ent = freezer->set_hash_table[i]; ent; ent = next)
- {
- next = ent->next;
- FcMemFree (FC_MEM_CHARSET, (sizeof (FcCharSetEnt) +
- ent->set.num * sizeof (FcCharLeaf *) +
- ent->set.num * sizeof (FcChar16)));
- free (ent);
- }
- }
-
- for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
- {
- FcCharSetOrigEnt *ent, *next;
- for (ent = freezer->orig_hash_table[i]; ent; ent = next)
- {
- next = ent->next;
- free (ent);
- }
- }
-
- for (i = 0; i < freezer->leaf_block_count; i++)
- {
- free (freezer->leaf_blocks[i]);
- FcMemFree (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
- }
-
- free (freezer->leaf_blocks);
- free (freezer);
-}
-
-FcBool
-FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
-{
- intptr_t *leaves;
- FcChar16 *numbers;
- int i;
-
- if (cs->ref != FC_REF_CONSTANT)
- {
- if (!serialize->cs_freezer)
- {
- serialize->cs_freezer = FcCharSetFreezerCreate ();
- if (!serialize->cs_freezer)
- return FcFalse;
- }
- if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
- return FcTrue;
-
- cs = FcCharSetFreeze (serialize->cs_freezer, cs);
- }
-
- leaves = FcCharSetLeaves (cs);
- numbers = FcCharSetNumbers (cs);
-
- if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
- return FcFalse;
- if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
- return FcFalse;
- if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
- return FcFalse;
- for (i = 0; i < cs->num; i++)
- if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
- sizeof (FcCharLeaf)))
- return FcFalse;
- return FcTrue;
-}
-
-FcCharSet *
-FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
-{
- FcCharSet *cs_serialized;
- intptr_t *leaves, *leaves_serialized;
- FcChar16 *numbers, *numbers_serialized;
- FcCharLeaf *leaf, *leaf_serialized;
- int i;
-
- if (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
- {
- cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
- if (!cs)
- return NULL;
- }
-
- cs_serialized = FcSerializePtr (serialize, cs);
- if (!cs_serialized)
- return NULL;
-
- cs_serialized->ref = FC_REF_CONSTANT;
- cs_serialized->num = cs->num;
-
- if (cs->num)
- {
- leaves = FcCharSetLeaves (cs);
- leaves_serialized = FcSerializePtr (serialize, leaves);
- if (!leaves_serialized)
- return NULL;
-
- cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
- leaves_serialized);
-
- numbers = FcCharSetNumbers (cs);
- numbers_serialized = FcSerializePtr (serialize, numbers);
- if (!numbers)
- return NULL;
-
- cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
- numbers_serialized);
-
- for (i = 0; i < cs->num; i++)
- {
- leaf = FcCharSetLeaf (cs, i);
- leaf_serialized = FcSerializePtr (serialize, leaf);
- if (!leaf_serialized)
- return NULL;
- *leaf_serialized = *leaf;
- leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
- leaf_serialized);
- numbers_serialized[i] = numbers[i];
- }
- }
- else
- {
- cs_serialized->leaves_offset = 0;
- cs_serialized->numbers_offset = 0;
- }
-
- return cs_serialized;
-}
-#define __fccharset__
-#include "fcaliastail.h"
-#undef __fccharset__
+/* + * fontconfig/src/fccharset.c + * + * Copyright © 2001 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdlib.h> + +/* #define CHECK */ + +FcCharSet * +FcCharSetCreate (void) +{ + FcCharSet *fcs; + + fcs = (FcCharSet *) malloc (sizeof (FcCharSet)); + if (!fcs) + return 0; + FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet)); + fcs->ref = 1; + fcs->num = 0; + fcs->leaves_offset = 0; + fcs->numbers_offset = 0; + return fcs; +} + +FcCharSet * +FcCharSetNew (void) +{ + return FcCharSetCreate (); +} + +void +FcCharSetDestroy (FcCharSet *fcs) +{ + int i; + + if (fcs->ref == FC_REF_CONSTANT) + { + FcCacheObjectDereference (fcs); + return; + } + if (--fcs->ref > 0) + return; + for (i = 0; i < fcs->num; i++) + { + FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf)); + free (FcCharSetLeaf (fcs, i)); + } + if (fcs->num) + { + /* the numbers here are estimates */ + FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t)); + free (FcCharSetLeaves (fcs)); + FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16)); + free (FcCharSetNumbers (fcs)); + } + FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet)); + free (fcs); +} + +/* + * Search for the leaf containing with the specified num. + * Return its index if it exists, otherwise return negative of + * the (position + 1) where it should be inserted + */ + + +static int +FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num) +{ + FcChar16 *numbers = FcCharSetNumbers(fcs); + FcChar16 page; + int low = start; + int high = fcs->num - 1; + + if (!numbers) + return -1; + while (low <= high) + { + int mid = (low + high) >> 1; + page = numbers[mid]; + if (page == num) + return mid; + if (page < num) + low = mid + 1; + else + high = mid - 1; + } + if (high < 0 || (high < fcs->num && numbers[high] < num)) + high++; + return -(high + 1); +} + +/* + * Locate the leaf containing the specified char, return + * its index if it exists, otherwise return negative of + * the (position + 1) where it should be inserted + */ + +static int +FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4) +{ + return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8); +} + +static FcCharLeaf * +FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4) +{ + int pos = FcCharSetFindLeafPos (fcs, ucs4); + if (pos >= 0) + return FcCharSetLeaf(fcs, pos); + return 0; +} + +#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1))) + +static FcBool +FcCharSetPutLeaf (FcCharSet *fcs, + FcChar32 ucs4, + FcCharLeaf *leaf, + int pos) +{ + intptr_t *leaves = FcCharSetLeaves (fcs); + FcChar16 *numbers = FcCharSetNumbers (fcs); + + ucs4 >>= 8; + if (ucs4 >= 0x10000) + return FcFalse; + + if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num)) + { + if (!fcs->num) + { + unsigned int alloced = 8; + leaves = malloc (alloced * sizeof (*leaves)); + numbers = malloc (alloced * sizeof (*numbers)); + FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves)); + FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers)); + } + else + { + unsigned int alloced = fcs->num; + intptr_t *new_leaves, distance; + + FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*leaves)); + FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*numbers)); + + alloced *= 2; + new_leaves = realloc (leaves, alloced * sizeof (*leaves)); + numbers = realloc (numbers, alloced * sizeof (*numbers)); + + FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves)); + FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers)); + + distance = (intptr_t) new_leaves - (intptr_t) leaves; + if (new_leaves && distance) + { + int i; + for (i = 0; i < fcs->num; i++) + new_leaves[i] -= distance; + } + leaves = new_leaves; + } + + if (!leaves || !numbers) + return FcFalse; + + fcs->leaves_offset = FcPtrToOffset (fcs, leaves); + fcs->numbers_offset = FcPtrToOffset (fcs, numbers); + } + + memmove (leaves + pos + 1, leaves + pos, + (fcs->num - pos) * sizeof (*leaves)); + memmove (numbers + pos + 1, numbers + pos, + (fcs->num - pos) * sizeof (*numbers)); + numbers[pos] = (FcChar16) ucs4; + leaves[pos] = FcPtrToOffset (leaves, leaf); + fcs->num++; + return FcTrue; +} + +/* + * Locate the leaf containing the specified char, creating it + * if desired + */ + +FcCharLeaf * +FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4) +{ + int pos; + FcCharLeaf *leaf; + + pos = FcCharSetFindLeafPos (fcs, ucs4); + if (pos >= 0) + return FcCharSetLeaf(fcs, pos); + + leaf = calloc (1, sizeof (FcCharLeaf)); + if (!leaf) + return 0; + + pos = -pos - 1; + if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos)) + { + free (leaf); + return 0; + } + FcMemAlloc (FC_MEM_CHARLEAF, sizeof (FcCharLeaf)); + return leaf; +} + +static FcBool +FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf) +{ + int pos; + + pos = FcCharSetFindLeafPos (fcs, ucs4); + if (pos >= 0) + { + FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf)); + free (FcCharSetLeaf (fcs, pos)); + FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs), + leaf); + return FcTrue; + } + pos = -pos - 1; + return FcCharSetPutLeaf (fcs, ucs4, leaf, pos); +} + +FcBool +FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4) +{ + FcCharLeaf *leaf; + FcChar32 *b; + + if (fcs->ref == FC_REF_CONSTANT) + return FcFalse; + leaf = FcCharSetFindLeafCreate (fcs, ucs4); + if (!leaf) + return FcFalse; + b = &leaf->map[(ucs4 & 0xff) >> 5]; + *b |= (1 << (ucs4 & 0x1f)); + return FcTrue; +} + +FcBool +FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4) +{ + FcCharLeaf *leaf; + FcChar32 *b; + + if (fcs->ref == FC_REF_CONSTANT) + return FcFalse; + leaf = FcCharSetFindLeaf (fcs, ucs4); + if (!leaf) + return FcTrue; + b = &leaf->map[(ucs4 & 0xff) >> 5]; + *b &= ~(1 << (ucs4 & 0x1f)); + /* We don't bother removing the leaf if it's empty */ + return FcTrue; +} + +/* + * An iterator for the leaves of a charset + */ + +typedef struct _fcCharSetIter { + FcCharLeaf *leaf; + FcChar32 ucs4; + int pos; +} FcCharSetIter; + +/* + * Set iter->leaf to the leaf containing iter->ucs4 or higher + */ + +static void +FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter) +{ + int pos = FcCharSetFindLeafPos (fcs, iter->ucs4); + + if (pos < 0) + { + pos = -pos - 1; + if (pos == fcs->num) + { + iter->ucs4 = ~0; + iter->leaf = 0; + return; + } + iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8; + } + iter->leaf = FcCharSetLeaf(fcs, pos); + iter->pos = pos; +} + +static void +FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter) +{ + int pos = iter->pos + 1; + if (pos >= fcs->num) + { + iter->ucs4 = ~0; + iter->leaf = 0; + } + else + { + iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8; + iter->leaf = FcCharSetLeaf(fcs, pos); + iter->pos = pos; + } +} + + +static void +FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter) +{ + iter->ucs4 = 0; + iter->pos = 0; + FcCharSetIterSet (fcs, iter); +} + +FcCharSet * +FcCharSetCopy (FcCharSet *src) +{ + if (src->ref != FC_REF_CONSTANT) + src->ref++; + else + FcCacheObjectReference (src); + 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)) && (bi.leaf || (aonly && ai.leaf))) + { + 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); +} + +FcBool +FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed) +{ + int ai = 0, bi = 0; + FcChar16 an, bn; + + if (a->ref == FC_REF_CONSTANT) { + if (changed) + *changed = FcFalse; + return FcFalse; + } + + if (changed) { + *changed = !FcCharSetIsSubset(b, a); + if (!*changed) + return FcTrue; + } + + while (bi < b->num) + { + an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0; + bn = FcCharSetNumbers(b)[bi]; + + if (an < bn) + { + ai = FcCharSetFindLeafForward (a, ai + 1, bn); + if (ai < 0) + ai = -ai - 1; + } + else + { + FcCharLeaf *bl = FcCharSetLeaf(b, bi); + if (bn < an) + { + if (!FcCharSetAddLeaf (a, bn << 8, bl)) + return FcFalse; + } + else + { + FcCharLeaf *al = FcCharSetLeaf(a, ai); + FcCharSetUnionLeaf (al, al, bl); + } + + ai++; + bi++; + } + } + + return 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) +{ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return __builtin_popcount (c1); +#else + /* hackmem 169 */ + FcChar32 c2 = (c1 >> 1) & 033333333333; + c2 = c1 - c2 - ((c2 >> 1) & 033333333333); + return (((c2 + (c2 >> 3)) & 030707070707) % 077); +#endif +} + +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; +} + +/* + * return FcTrue iff a is a subset of b + */ +FcBool +FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b) +{ + int ai, bi; + FcChar16 an, bn; + + if (a == b) return FcTrue; + bi = 0; + ai = 0; + while (ai < a->num && bi < b->num) + { + an = FcCharSetNumbers(a)[ai]; + bn = FcCharSetNumbers(b)[bi]; + /* + * Check matching pages + */ + if (an == bn) + { + FcChar32 *am = FcCharSetLeaf(a, ai)->map; + FcChar32 *bm = FcCharSetLeaf(b, bi)->map; + + if (am != bm) + { + int i = 256/32; + /* + * Does am have any bits not in bm? + */ + while (i--) + if (*am++ & ~*bm++) + return FcFalse; + } + ai++; + bi++; + } + /* + * Does a have any pages not in b? + */ + else if (an < bn) + return FcFalse; + else + { + bi = FcCharSetFindLeafForward (b, bi + 1, an); + if (bi < 0) + bi = -bi - 1; + } + } + /* + * did we look at every page? + */ + return ai >= a->num; +} + +/* + * These two functions efficiently walk the entire charmap for + * other software (like pango) that want their own copy + */ + +FcChar32 +FcCharSetNextPage (const FcCharSet *a, + FcChar32 map[FC_CHARSET_MAP_SIZE], + FcChar32 *next) +{ + FcCharSetIter ai; + FcChar32 page; + + ai.ucs4 = *next; + FcCharSetIterSet (a, &ai); + if (!ai.leaf) + return FC_CHARSET_DONE; + + /* + * Save current information + */ + page = ai.ucs4; + memcpy (map, ai.leaf->map, sizeof (ai.leaf->map)); + /* + * Step to next page + */ + FcCharSetIterNext (a, &ai); + *next = ai.ucs4; + + return page; +} + +FcChar32 +FcCharSetFirstPage (const FcCharSet *a, + FcChar32 map[FC_CHARSET_MAP_SIZE], + FcChar32 *next) +{ + *next = 0; + return FcCharSetNextPage (a, map, next); +} + +/* + * old coverage API, rather hard to use correctly + */ + +FcChar32 +FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result) +{ + FcCharSetIter ai; + + ai.ucs4 = page; + FcCharSetIterSet (a, &ai); + if (!ai.leaf) + { + memset (result, '\0', 256 / 8); + page = 0; + } + else + { + memcpy (result, ai.leaf->map, sizeof (ai.leaf->map)); + FcCharSetIterNext (a, &ai); + page = ai.ucs4; + } + return page; +} + +/* + * 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 const unsigned char 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 const 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; + FcChar32 c; + + if (*string == ' ') + { + v = 0; + string++; + } + else + { + v = 0; + for (i = 0; i < 5; i++) + { + if (!(c = (FcChar32) (unsigned char) *string++)) + return 0; + c = charToValue[c]; + if (c == 0xff) + return 0; + v = v * 85 + c; + } + } + *value = v; + return string; +} + +static FcBool +FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value) +{ + int i; + if (value == 0) + { + return FcStrBufChar (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 (!FcStrBufChar (buf, *s++)) + return FcFalse; + } + return FcTrue; +} + +FcCharSet * +FcNameParseCharSet (FcChar8 *string) +{ + FcCharSet *c; + FcChar32 ucs4; + FcCharLeaf *leaf; + FcCharLeaf temp; + FcChar32 bits; + int i; + + c = FcCharSetCreate (); + if (!c) + goto bail0; + while (*string) + { + string = FcCharSetParseValue (string, &ucs4); + if (!string) + goto bail1; + bits = 0; + for (i = 0; i < 256/32; i++) + { + string = FcCharSetParseValue (string, &temp.map[i]); + if (!string) + goto bail1; + bits |= temp.map[i]; + } + if (bits) + { + leaf = malloc (sizeof (FcCharLeaf)); + if (!leaf) + goto bail1; + *leaf = temp; + if (!FcCharSetInsertLeaf (c, ucs4, leaf)) + goto bail1; + } + } + return c; +bail1: + if (c->num) + { + FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *)); + free (FcCharSetLeaves (c)); + } + if (c->num) + { + FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16)); + free (FcCharSetNumbers (c)); + } + FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet)); + free (c); +bail0: + return NULL; +} + +FcBool +FcNameUnparseCharSet (FcStrBuf *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 */ + FcStrBufChar (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; +} + +typedef struct _FcCharLeafEnt FcCharLeafEnt; + +struct _FcCharLeafEnt { + FcCharLeafEnt *next; + FcChar32 hash; + FcCharLeaf leaf; +}; + +#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt)) +#define FC_CHAR_LEAF_HASH_SIZE 257 + +typedef struct _FcCharSetEnt FcCharSetEnt; + +struct _FcCharSetEnt { + FcCharSetEnt *next; + FcChar32 hash; + FcCharSet set; +}; + +typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt; + +struct _FcCharSetOrigEnt { + FcCharSetOrigEnt *next; + const FcCharSet *orig; + const FcCharSet *frozen; +}; + +#define FC_CHAR_SET_HASH_SIZE 67 + +struct _FcCharSetFreezer { + FcCharLeafEnt *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE]; + FcCharLeafEnt **leaf_blocks; + int leaf_block_count; + FcCharSetEnt *set_hash_table[FC_CHAR_SET_HASH_SIZE]; + FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE]; + FcCharLeafEnt *current_block; + int leaf_remain; + int leaves_seen; + int charsets_seen; + int leaves_allocated; + int charsets_allocated; +}; + +static FcCharLeafEnt * +FcCharLeafEntCreate (FcCharSetFreezer *freezer) +{ + if (!freezer->leaf_remain) + { + FcCharLeafEnt **newBlocks; + + freezer->leaf_block_count++; + newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *)); + if (!newBlocks) + return 0; + freezer->leaf_blocks = newBlocks; + freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); + if (!freezer->current_block) + return 0; + FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); + freezer->leaf_remain = FC_CHAR_LEAF_BLOCK; + } + freezer->leaf_remain--; + freezer->leaves_allocated++; + return freezer->current_block++; +} + +static FcChar32 +FcCharLeafHash (FcCharLeaf *leaf) +{ + FcChar32 hash = 0; + int i; + + for (i = 0; i < 256/32; i++) + hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i]; + return hash; +} + +static FcCharLeaf * +FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf) +{ + FcChar32 hash = FcCharLeafHash (leaf); + FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE]; + FcCharLeafEnt *ent; + + for (ent = *bucket; ent; ent = ent->next) + { + if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf))) + return &ent->leaf; + } + + ent = FcCharLeafEntCreate(freezer); + if (!ent) + return 0; + ent->leaf = *leaf; + ent->hash = hash; + ent->next = *bucket; + *bucket = ent; + return &ent->leaf; +} + +static FcChar32 +FcCharSetHash (FcCharSet *fcs) +{ + FcChar32 hash = 0; + int i; + + /* hash in leaves */ + for (i = 0; i < fcs->num; i++) + hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i)); + /* hash in numbers */ + for (i = 0; i < fcs->num; i++) + hash = ((hash << 1) | (hash >> 31)) ^ *FcCharSetNumbers(fcs); + return hash; +} + +static FcBool +FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen) +{ + FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE]; + FcCharSetOrigEnt *ent; + + ent = malloc (sizeof (FcCharSetOrigEnt)); + if (!ent) + return FcFalse; + ent->orig = orig; + ent->frozen = frozen; + ent->next = *bucket; + *bucket = ent; + return FcTrue; +} + +static FcCharSet * +FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig) +{ + FcChar32 hash = FcCharSetHash (fcs); + FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE]; + FcCharSetEnt *ent; + int size; + int i; + + for (ent = *bucket; ent; ent = ent->next) + { + if (ent->hash == hash && + ent->set.num == fcs->num && + !memcmp (FcCharSetNumbers(&ent->set), + FcCharSetNumbers(fcs), + fcs->num * sizeof (FcChar16))) + { + FcBool ok = FcTrue; + int i; + + for (i = 0; i < fcs->num; i++) + if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i)) + ok = FcFalse; + if (ok) + return &ent->set; + } + } + + size = (sizeof (FcCharSetEnt) + + fcs->num * sizeof (FcCharLeaf *) + + fcs->num * sizeof (FcChar16)); + ent = malloc (size); + if (!ent) + return 0; + FcMemAlloc (FC_MEM_CHARSET, size); + + freezer->charsets_allocated++; + + ent->set.ref = FC_REF_CONSTANT; + ent->set.num = fcs->num; + if (fcs->num) + { + intptr_t *ent_leaves; + + ent->set.leaves_offset = sizeof (ent->set); + ent->set.numbers_offset = (ent->set.leaves_offset + + fcs->num * sizeof (intptr_t)); + + ent_leaves = FcCharSetLeaves (&ent->set); + for (i = 0; i < fcs->num; i++) + ent_leaves[i] = FcPtrToOffset (ent_leaves, + FcCharSetLeaf (fcs, i)); + memcpy (FcCharSetNumbers (&ent->set), + FcCharSetNumbers (fcs), + fcs->num * sizeof (FcChar16)); + } + else + { + ent->set.leaves_offset = 0; + ent->set.numbers_offset = 0; + } + + ent->hash = hash; + ent->next = *bucket; + *bucket = ent; + + return &ent->set; +} + +static const FcCharSet * +FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig) +{ + FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE]; + FcCharSetOrigEnt *ent; + + for (ent = *bucket; ent; ent = ent->next) + if (ent->orig == orig) + return ent->frozen; + return NULL; +} + +const FcCharSet * +FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs) +{ + FcCharSet *b; + const FcCharSet *n = 0; + FcCharLeaf *l; + int i; + + b = FcCharSetCreate (); + if (!b) + goto bail0; + for (i = 0; i < fcs->num; i++) + { + l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i)); + if (!l) + goto bail1; + if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l)) + goto bail1; + } + n = FcCharSetFreezeBase (freezer, b, fcs); + if (!FcCharSetFreezeOrig (freezer, fcs, n)) + { + n = NULL; + goto bail1; + } + freezer->charsets_seen++; + freezer->leaves_seen += fcs->num; +bail1: + if (b->num) + { + FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *)); + free (FcCharSetLeaves (b)); + } + if (b->num) + { + FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16)); + free (FcCharSetNumbers (b)); + } + FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet)); + free (b); +bail0: + return n; +} + +FcCharSetFreezer * +FcCharSetFreezerCreate (void) +{ + FcCharSetFreezer *freezer; + + freezer = calloc (1, sizeof (FcCharSetFreezer)); + return freezer; +} + +void +FcCharSetFreezerDestroy (FcCharSetFreezer *freezer) +{ + int i; + + if (FcDebug() & FC_DBG_CACHE) + { + printf ("\ncharsets %d -> %d leaves %d -> %d\n", + freezer->charsets_seen, freezer->charsets_allocated, + freezer->leaves_seen, freezer->leaves_allocated); + } + for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) + { + FcCharSetEnt *ent, *next; + for (ent = freezer->set_hash_table[i]; ent; ent = next) + { + next = ent->next; + FcMemFree (FC_MEM_CHARSET, (sizeof (FcCharSetEnt) + + ent->set.num * sizeof (FcCharLeaf *) + + ent->set.num * sizeof (FcChar16))); + free (ent); + } + } + + for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) + { + FcCharSetOrigEnt *ent, *next; + for (ent = freezer->orig_hash_table[i]; ent; ent = next) + { + next = ent->next; + free (ent); + } + } + + for (i = 0; i < freezer->leaf_block_count; i++) + { + free (freezer->leaf_blocks[i]); + FcMemFree (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); + } + + free (freezer->leaf_blocks); + free (freezer); +} + +FcBool +FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs) +{ + intptr_t *leaves; + FcChar16 *numbers; + int i; + + if (cs->ref != FC_REF_CONSTANT) + { + if (!serialize->cs_freezer) + { + serialize->cs_freezer = FcCharSetFreezerCreate (); + if (!serialize->cs_freezer) + return FcFalse; + } + if (FcCharSetFindFrozen (serialize->cs_freezer, cs)) + return FcTrue; + + cs = FcCharSetFreeze (serialize->cs_freezer, cs); + } + + leaves = FcCharSetLeaves (cs); + numbers = FcCharSetNumbers (cs); + + if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet))) + return FcFalse; + if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t))) + return FcFalse; + if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16))) + return FcFalse; + for (i = 0; i < cs->num; i++) + if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i), + sizeof (FcCharLeaf))) + return FcFalse; + return FcTrue; +} + +FcCharSet * +FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs) +{ + FcCharSet *cs_serialized; + intptr_t *leaves, *leaves_serialized; + FcChar16 *numbers, *numbers_serialized; + FcCharLeaf *leaf, *leaf_serialized; + int i; + + if (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer) + { + cs = FcCharSetFindFrozen (serialize->cs_freezer, cs); + if (!cs) + return NULL; + } + + cs_serialized = FcSerializePtr (serialize, cs); + if (!cs_serialized) + return NULL; + + cs_serialized->ref = FC_REF_CONSTANT; + cs_serialized->num = cs->num; + + if (cs->num) + { + leaves = FcCharSetLeaves (cs); + leaves_serialized = FcSerializePtr (serialize, leaves); + if (!leaves_serialized) + return NULL; + + cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized, + leaves_serialized); + + numbers = FcCharSetNumbers (cs); + numbers_serialized = FcSerializePtr (serialize, numbers); + if (!numbers) + return NULL; + + cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized, + numbers_serialized); + + for (i = 0; i < cs->num; i++) + { + leaf = FcCharSetLeaf (cs, i); + leaf_serialized = FcSerializePtr (serialize, leaf); + if (!leaf_serialized) + return NULL; + *leaf_serialized = *leaf; + leaves_serialized[i] = FcPtrToOffset (leaves_serialized, + leaf_serialized); + numbers_serialized[i] = numbers[i]; + } + } + else + { + cs_serialized->leaves_offset = 0; + cs_serialized->numbers_offset = 0; + } + + return cs_serialized; +} +#define __fccharset__ +#include "fcaliastail.h" +#undef __fccharset__ diff --git a/fontconfig/src/fcdbg.c b/fontconfig/src/fcdbg.c index b8cb079fc..cf2ff0870 100644 --- a/fontconfig/src/fcdbg.c +++ b/fontconfig/src/fcdbg.c @@ -1,406 +1,406 @@ -/*
- * fontconfig/src/fcdbg.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdio.h>
-#include <stdlib.h>
-
-void
-FcValuePrint (const FcValue v)
-{
- switch (v.type) {
- case FcTypeVoid:
- printf (" <void>");
- break;
- case FcTypeInteger:
- printf (" %d(i)", v.u.i);
- break;
- case FcTypeDouble:
- printf (" %g(f)", 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 (" ");
- FcCharSetPrint (v.u.c);
- break;
- case FcTypeLangSet:
- printf (" ");
- FcLangSetPrint (v.u.l);
- break;
- case FcTypeFTFace:
- printf (" face");
- break;
- }
-}
-
-void
-FcValueListPrint (FcValueListPtr l)
-{
- for (; l != NULL; l = FcValueListNext(l))
- {
- FcValuePrint (FcValueCanonicalize(&l->value));
- switch (l->binding) {
- case FcValueBindingWeak:
- printf ("(w)");
- break;
- case FcValueBindingStrong:
- printf ("(s)");
- break;
- case FcValueBindingSame:
- printf ("(=)");
- break;
- }
- }
-}
-
-void
-FcLangSetPrint (const FcLangSet *ls)
-{
- FcStrBuf buf;
- FcChar8 init_buf[1024];
-
- FcStrBufInit (&buf, init_buf, sizeof (init_buf));
- if (FcNameUnparseLangSet (&buf, ls) && FcStrBufChar (&buf,'\0'))
- printf ("%s", buf.buf);
- else
- printf ("langset (alloc error)");
- FcStrBufDestroy (&buf);
-}
-
-void
-FcCharSetPrint (const FcCharSet *c)
-{
- int i, j;
- intptr_t *leaves = FcCharSetLeaves (c);
- FcChar16 *numbers = FcCharSetNumbers (c);
-
-#if 0
- printf ("CharSet 0x%x\n", (intptr_t) c);
- printf ("Leaves: +%d = 0x%x\n", c->leaves_offset, (intptr_t) leaves);
- printf ("Numbers: +%d = 0x%x\n", c->numbers_offset, (intptr_t) numbers);
-
- for (i = 0; i < c->num; i++)
- {
- printf ("Page %d: %04x +%d = 0x%x\n",
- i, numbers[i], leaves[i],
- (intptr_t) FcOffsetToPtr (leaves, leaves[i], FcCharLeaf));
- }
-#endif
-
- printf ("\n");
- for (i = 0; i < c->num; i++)
- {
- intptr_t leaf_offset = leaves[i];
- FcCharLeaf *leaf = FcOffsetToPtr (leaves, leaf_offset, FcCharLeaf);
-
- printf ("\t");
- printf ("%04x:", numbers[i]);
- for (j = 0; j < 256/32; j++)
- printf (" %08x", leaf->map[j]);
- printf ("\n");
- }
-}
-
-void
-FcPatternPrint (const FcPattern *p)
-{
- int i;
- FcPatternElt *e;
-
- if (!p)
- {
- printf ("Null pattern\n");
- return;
- }
- printf ("Pattern has %d elts (size %d)\n", p->num, p->size);
- for (i = 0; i < p->num; i++)
- {
- e = &FcPatternElts(p)[i];
- printf ("\t%s:", FcObjectName(e->object));
- FcValueListPrint (FcPatternEltValues(e));
- 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 FcOpRange: printf ("Range"); break;
- case FcOpBool: printf ("Bool"); break;
- case FcOpCharSet: printf ("CharSet"); break;
- case FcOpLangSet: printf ("LangSet"); 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 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 FcOpContains: printf ("Contains"); break;
- case FcOpNotContains: printf ("NotContains"); 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 FcOpFloor: printf ("Floor"); break;
- case FcOpCeil: printf ("Ceil"); break;
- case FcOpRound: printf ("Round"); break;
- case FcOpTrunc: printf ("Trunc"); break;
- case FcOpListing: printf ("Listing"); break;
- case FcOpInvalid: printf ("Invalid"); break;
- }
-}
-
-void
-FcExprPrint (const FcExpr *expr)
-{
- if (!expr) printf ("none");
- else 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); break;
- case FcOpRange: break;
- case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break;
- case FcOpCharSet: printf ("charset\n"); break;
- case FcOpLangSet:
- printf ("langset:");
- FcLangSetPrint(expr->u.lval);
- printf ("\n");
- break;
- case FcOpNil: printf ("nil\n"); break;
- case FcOpField: printf ("%s", FcObjectName(expr->u.object)); break;
- case FcOpConst: printf ("%s", expr->u.constant); 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 FcOpAssign:
- case FcOpAssignReplace:
- case FcOpPrependFirst:
- case FcOpPrepend:
- case FcOpAppend:
- case FcOpAppendLast:
- case FcOpOr:
- case FcOpAnd:
- case FcOpEqual:
- case FcOpNotEqual:
- case FcOpLess:
- case FcOpLessEqual:
- case FcOpMore:
- case FcOpMoreEqual:
- case FcOpContains:
- case FcOpListing:
- case FcOpNotContains:
- case FcOpPlus:
- case FcOpMinus:
- case FcOpTimes:
- case FcOpDivide:
- case FcOpComma:
- FcExprPrint (expr->u.tree.left);
- printf (" ");
- switch (expr->op) {
- case FcOpAssign: printf ("Assign"); break;
- case FcOpAssignReplace: printf ("AssignReplace"); break;
- case FcOpPrependFirst: printf ("PrependFirst"); break;
- case FcOpPrepend: printf ("Prepend"); break;
- case FcOpAppend: printf ("Append"); break;
- case FcOpAppendLast: printf ("AppendLast"); break;
- case FcOpOr: printf ("Or"); break;
- case FcOpAnd: printf ("And"); break;
- case FcOpEqual: printf ("Equal"); 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 FcOpContains: printf ("Contains"); break;
- case FcOpListing: printf ("Listing"); break;
- case FcOpNotContains: printf ("NotContains"); break;
- case FcOpPlus: printf ("Plus"); break;
- case FcOpMinus: printf ("Minus"); break;
- case FcOpTimes: printf ("Times"); break;
- case FcOpDivide: printf ("Divide"); break;
- case FcOpComma: printf ("Comma"); break;
- default: break;
- }
- printf (" ");
- FcExprPrint (expr->u.tree.right);
- break;
- case FcOpNot:
- printf ("Not ");
- FcExprPrint (expr->u.tree.left);
- break;
- case FcOpFloor:
- printf ("Floor ");
- FcExprPrint (expr->u.tree.left);
- break;
- case FcOpCeil:
- printf ("Ceil ");
- FcExprPrint (expr->u.tree.left);
- break;
- case FcOpRound:
- printf ("Round ");
- FcExprPrint (expr->u.tree.left);
- break;
- case FcOpTrunc:
- printf ("Trunc ");
- FcExprPrint (expr->u.tree.left);
- break;
- case FcOpInvalid: printf ("Invalid"); break;
- }
-}
-
-void
-FcTestPrint (const FcTest *test)
-{
- switch (test->kind) {
- case FcMatchPattern:
- printf ("pattern ");
- break;
- case FcMatchFont:
- printf ("font ");
- break;
- case FcMatchScan:
- printf ("scan ");
- break;
- }
- switch (test->qual) {
- case FcQualAny:
- printf ("any ");
- break;
- case FcQualAll:
- printf ("all ");
- break;
- case FcQualFirst:
- printf ("first ");
- break;
- case FcQualNotFirst:
- printf ("not_first ");
- break;
- }
- printf ("%s ", FcObjectName (test->object));
- FcOpPrint (test->op);
- printf (" ");
- FcExprPrint (test->expr);
- printf ("\n");
-}
-
-void
-FcEditPrint (const FcEdit *edit)
-{
- printf ("Edit %s ", FcObjectName (edit->object));
- FcOpPrint (edit->op);
- printf (" ");
- FcExprPrint (edit->expr);
-}
-
-void
-FcSubstPrint (const 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 (const 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 FcDebugVal;
-
-void
-FcInitDebug (void)
-{
- char *e;
-
- e = getenv ("FC_DEBUG");
- if (e)
- {
- printf ("FC_DEBUG=%s\n", e);
- FcDebugVal = atoi (e);
- if (FcDebugVal < 0)
- FcDebugVal = 0;
- }
-}
-#define __fcdbg__
-#include "fcaliastail.h"
-#undef __fcdbg__
+/* + * fontconfig/src/fcdbg.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdio.h> +#include <stdlib.h> + +void +FcValuePrint (const FcValue v) +{ + switch (v.type) { + case FcTypeVoid: + printf (" <void>"); + break; + case FcTypeInteger: + printf (" %d(i)", v.u.i); + break; + case FcTypeDouble: + printf (" %g(f)", 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 (" "); + FcCharSetPrint (v.u.c); + break; + case FcTypeLangSet: + printf (" "); + FcLangSetPrint (v.u.l); + break; + case FcTypeFTFace: + printf (" face"); + break; + } +} + +void +FcValueListPrint (FcValueListPtr l) +{ + for (; l != NULL; l = FcValueListNext(l)) + { + FcValuePrint (FcValueCanonicalize(&l->value)); + switch (l->binding) { + case FcValueBindingWeak: + printf ("(w)"); + break; + case FcValueBindingStrong: + printf ("(s)"); + break; + case FcValueBindingSame: + printf ("(=)"); + break; + } + } +} + +void +FcLangSetPrint (const FcLangSet *ls) +{ + FcStrBuf buf; + FcChar8 init_buf[1024]; + + FcStrBufInit (&buf, init_buf, sizeof (init_buf)); + if (FcNameUnparseLangSet (&buf, ls) && FcStrBufChar (&buf,'\0')) + printf ("%s", buf.buf); + else + printf ("langset (alloc error)"); + FcStrBufDestroy (&buf); +} + +void +FcCharSetPrint (const FcCharSet *c) +{ + int i, j; + intptr_t *leaves = FcCharSetLeaves (c); + FcChar16 *numbers = FcCharSetNumbers (c); + +#if 0 + printf ("CharSet 0x%x\n", (intptr_t) c); + printf ("Leaves: +%d = 0x%x\n", c->leaves_offset, (intptr_t) leaves); + printf ("Numbers: +%d = 0x%x\n", c->numbers_offset, (intptr_t) numbers); + + for (i = 0; i < c->num; i++) + { + printf ("Page %d: %04x +%d = 0x%x\n", + i, numbers[i], leaves[i], + (intptr_t) FcOffsetToPtr (leaves, leaves[i], FcCharLeaf)); + } +#endif + + printf ("\n"); + for (i = 0; i < c->num; i++) + { + intptr_t leaf_offset = leaves[i]; + FcCharLeaf *leaf = FcOffsetToPtr (leaves, leaf_offset, FcCharLeaf); + + printf ("\t"); + printf ("%04x:", numbers[i]); + for (j = 0; j < 256/32; j++) + printf (" %08x", leaf->map[j]); + printf ("\n"); + } +} + +void +FcPatternPrint (const FcPattern *p) +{ + int i; + FcPatternElt *e; + + if (!p) + { + printf ("Null pattern\n"); + return; + } + printf ("Pattern has %d elts (size %d)\n", p->num, p->size); + for (i = 0; i < p->num; i++) + { + e = &FcPatternElts(p)[i]; + printf ("\t%s:", FcObjectName(e->object)); + FcValueListPrint (FcPatternEltValues(e)); + 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 FcOpRange: printf ("Range"); break; + case FcOpBool: printf ("Bool"); break; + case FcOpCharSet: printf ("CharSet"); break; + case FcOpLangSet: printf ("LangSet"); 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 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 FcOpContains: printf ("Contains"); break; + case FcOpNotContains: printf ("NotContains"); 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 FcOpFloor: printf ("Floor"); break; + case FcOpCeil: printf ("Ceil"); break; + case FcOpRound: printf ("Round"); break; + case FcOpTrunc: printf ("Trunc"); break; + case FcOpListing: printf ("Listing"); break; + case FcOpInvalid: printf ("Invalid"); break; + } +} + +void +FcExprPrint (const FcExpr *expr) +{ + if (!expr) printf ("none"); + else 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); break; + case FcOpRange: break; + case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break; + case FcOpCharSet: printf ("charset\n"); break; + case FcOpLangSet: + printf ("langset:"); + FcLangSetPrint(expr->u.lval); + printf ("\n"); + break; + case FcOpNil: printf ("nil\n"); break; + case FcOpField: printf ("%s", FcObjectName(expr->u.object)); break; + case FcOpConst: printf ("%s", expr->u.constant); 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 FcOpAssign: + case FcOpAssignReplace: + case FcOpPrependFirst: + case FcOpPrepend: + case FcOpAppend: + case FcOpAppendLast: + case FcOpOr: + case FcOpAnd: + case FcOpEqual: + case FcOpNotEqual: + case FcOpLess: + case FcOpLessEqual: + case FcOpMore: + case FcOpMoreEqual: + case FcOpContains: + case FcOpListing: + case FcOpNotContains: + case FcOpPlus: + case FcOpMinus: + case FcOpTimes: + case FcOpDivide: + case FcOpComma: + FcExprPrint (expr->u.tree.left); + printf (" "); + switch (expr->op) { + case FcOpAssign: printf ("Assign"); break; + case FcOpAssignReplace: printf ("AssignReplace"); break; + case FcOpPrependFirst: printf ("PrependFirst"); break; + case FcOpPrepend: printf ("Prepend"); break; + case FcOpAppend: printf ("Append"); break; + case FcOpAppendLast: printf ("AppendLast"); break; + case FcOpOr: printf ("Or"); break; + case FcOpAnd: printf ("And"); break; + case FcOpEqual: printf ("Equal"); 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 FcOpContains: printf ("Contains"); break; + case FcOpListing: printf ("Listing"); break; + case FcOpNotContains: printf ("NotContains"); break; + case FcOpPlus: printf ("Plus"); break; + case FcOpMinus: printf ("Minus"); break; + case FcOpTimes: printf ("Times"); break; + case FcOpDivide: printf ("Divide"); break; + case FcOpComma: printf ("Comma"); break; + default: break; + } + printf (" "); + FcExprPrint (expr->u.tree.right); + break; + case FcOpNot: + printf ("Not "); + FcExprPrint (expr->u.tree.left); + break; + case FcOpFloor: + printf ("Floor "); + FcExprPrint (expr->u.tree.left); + break; + case FcOpCeil: + printf ("Ceil "); + FcExprPrint (expr->u.tree.left); + break; + case FcOpRound: + printf ("Round "); + FcExprPrint (expr->u.tree.left); + break; + case FcOpTrunc: + printf ("Trunc "); + FcExprPrint (expr->u.tree.left); + break; + case FcOpInvalid: printf ("Invalid"); break; + } +} + +void +FcTestPrint (const FcTest *test) +{ + switch (test->kind) { + case FcMatchPattern: + printf ("pattern "); + break; + case FcMatchFont: + printf ("font "); + break; + case FcMatchScan: + printf ("scan "); + break; + } + switch (test->qual) { + case FcQualAny: + printf ("any "); + break; + case FcQualAll: + printf ("all "); + break; + case FcQualFirst: + printf ("first "); + break; + case FcQualNotFirst: + printf ("not_first "); + break; + } + printf ("%s ", FcObjectName (test->object)); + FcOpPrint (test->op); + printf (" "); + FcExprPrint (test->expr); + printf ("\n"); +} + +void +FcEditPrint (const FcEdit *edit) +{ + printf ("Edit %s ", FcObjectName (edit->object)); + FcOpPrint (edit->op); + printf (" "); + FcExprPrint (edit->expr); +} + +void +FcSubstPrint (const 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 (const 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 FcDebugVal; + +void +FcInitDebug (void) +{ + char *e; + + e = getenv ("FC_DEBUG"); + if (e) + { + printf ("FC_DEBUG=%s\n", e); + FcDebugVal = atoi (e); + if (FcDebugVal < 0) + FcDebugVal = 0; + } +} +#define __fcdbg__ +#include "fcaliastail.h" +#undef __fcdbg__ diff --git a/fontconfig/src/fcdefault.c b/fontconfig/src/fcdefault.c index 92ab8f0e6..a9165facd 100644 --- a/fontconfig/src/fcdefault.c +++ b/fontconfig/src/fcdefault.c @@ -1,181 +1,181 @@ -/*
- * fontconfig/src/fcdefault.c
- *
- * Copyright © 2001 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <locale.h>
-
-static const struct {
- FcObject field;
- FcBool value;
-} FcBoolDefaults[] = {
- { FC_HINTING_OBJECT, FcTrue }, /* !FT_LOAD_NO_HINTING */
- { FC_VERTICAL_LAYOUT_OBJECT, FcFalse }, /* FC_LOAD_VERTICAL_LAYOUT */
- { FC_AUTOHINT_OBJECT, FcFalse }, /* FC_LOAD_FORCE_AUTOHINT */
- { FC_GLOBAL_ADVANCE_OBJECT, FcTrue }, /* !FC_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
- { FC_EMBEDDED_BITMAP_OBJECT, FcTrue }, /* !FC_LOAD_NO_BITMAP */
- { FC_DECORATIVE_OBJECT, FcFalse },
-};
-
-#define NUM_FC_BOOL_DEFAULTS (int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
-
-FcChar8 *
-FcGetDefaultLang (void)
-{
- static char lang_local [128] = {0};
- char *ctype;
- char *territory;
- char *after;
- int lang_len, territory_len;
-
- if (lang_local [0])
- return (FcChar8 *) lang_local;
-
- ctype = setlocale (LC_CTYPE, NULL);
-
- /*
- * Check if setlocale (LC_ALL, "") has been called
- */
- if (!ctype || !strcmp (ctype, "C"))
- {
- ctype = getenv ("LC_ALL");
- if (!ctype)
- {
- ctype = getenv ("LC_CTYPE");
- if (!ctype)
- ctype = getenv ("LANG");
- }
- }
-
- /* ignore missing or empty ctype */
- if (ctype && *ctype != '\0')
- {
- territory = strchr (ctype, '_');
- if (territory)
- {
- lang_len = territory - ctype;
- territory = territory + 1;
- after = strchr (territory, '.');
- if (!after)
- {
- after = strchr (territory, '@');
- if (!after)
- after = territory + strlen (territory);
- }
- territory_len = after - territory;
- if (lang_len + 1 + territory_len + 1 <= (int) sizeof (lang_local))
- {
- strncpy (lang_local, ctype, lang_len);
- lang_local[lang_len] = '-';
- strncpy (lang_local + lang_len + 1, territory, territory_len);
- lang_local[lang_len + 1 + territory_len] = '\0';
- }
- }
- else
- {
- after = strchr (ctype, '.');
- if (!after)
- {
- after = strchr (ctype, '@');
- if (!after)
- after = ctype + strlen (ctype);
- }
- lang_len = after - ctype;
- if (lang_len + 1 <= (int) sizeof (lang_local))
- {
- strncpy (lang_local, ctype, lang_len);
- lang_local[lang_len] = '\0';
- }
- }
- }
-
- /* set default lang to en */
- if (!lang_local [0])
- strcpy (lang_local, "en");
-
- return (FcChar8 *) lang_local;
-}
-
-void
-FcDefaultSubstitute (FcPattern *pattern)
-{
- FcValue v;
- int i;
-
- if (FcPatternObjectGet (pattern, FC_WEIGHT_OBJECT, 0, &v) == FcResultNoMatch )
- FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_MEDIUM);
-
- if (FcPatternObjectGet (pattern, FC_SLANT_OBJECT, 0, &v) == FcResultNoMatch)
- FcPatternObjectAddInteger (pattern, FC_SLANT_OBJECT, FC_SLANT_ROMAN);
-
- if (FcPatternObjectGet (pattern, FC_WIDTH_OBJECT, 0, &v) == FcResultNoMatch)
- FcPatternObjectAddInteger (pattern, FC_WIDTH_OBJECT, FC_WIDTH_NORMAL);
-
- for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
- if (FcPatternObjectGet (pattern, FcBoolDefaults[i].field, 0, &v) == FcResultNoMatch)
- FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
-
- if (FcPatternObjectGet (pattern, FC_PIXEL_SIZE_OBJECT, 0, &v) == FcResultNoMatch)
- {
- double dpi, size, scale;
-
- if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch)
- {
- size = 12.0;
- (void) FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
- FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
- }
- if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
- {
- scale = 1.0;
- (void) FcPatternObjectDel (pattern, FC_SCALE_OBJECT);
- FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale);
- }
- size *= scale;
- if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
- {
- dpi = 75.0;
- (void) FcPatternObjectDel (pattern, FC_DPI_OBJECT);
- FcPatternObjectAddDouble (pattern, FC_DPI_OBJECT, dpi);
- }
- size *= dpi / 72.0;
- FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, size);
- }
-
- if (FcPatternObjectGet (pattern, FC_LANG_OBJECT, 0, &v) == FcResultNoMatch)
- {
- FcPatternObjectAddString (pattern, FC_LANG_OBJECT, FcGetDefaultLang ());
- }
- if (FcPatternObjectGet (pattern, FC_FONTVERSION_OBJECT, 0, &v) == FcResultNoMatch)
- {
- FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff);
- }
-
- if (FcPatternObjectGet (pattern, FC_HINT_STYLE_OBJECT, 0, &v) == FcResultNoMatch)
- {
- FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL);
- }
-}
-#define __fcdefault__
-#include "fcaliastail.h"
-#undef __fcdefault__
+/* + * fontconfig/src/fcdefault.c + * + * Copyright © 2001 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <locale.h> + +static const struct { + FcObject field; + FcBool value; +} FcBoolDefaults[] = { + { FC_HINTING_OBJECT, FcTrue }, /* !FT_LOAD_NO_HINTING */ + { FC_VERTICAL_LAYOUT_OBJECT, FcFalse }, /* FC_LOAD_VERTICAL_LAYOUT */ + { FC_AUTOHINT_OBJECT, FcFalse }, /* FC_LOAD_FORCE_AUTOHINT */ + { FC_GLOBAL_ADVANCE_OBJECT, FcTrue }, /* !FC_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ + { FC_EMBEDDED_BITMAP_OBJECT, FcTrue }, /* !FC_LOAD_NO_BITMAP */ + { FC_DECORATIVE_OBJECT, FcFalse }, +}; + +#define NUM_FC_BOOL_DEFAULTS (int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0]) + +FcChar8 * +FcGetDefaultLang (void) +{ + static char lang_local [128] = {0}; + char *ctype; + char *territory; + char *after; + int lang_len, territory_len; + + if (lang_local [0]) + return (FcChar8 *) lang_local; + + ctype = setlocale (LC_CTYPE, NULL); + + /* + * Check if setlocale (LC_ALL, "") has been called + */ + if (!ctype || !strcmp (ctype, "C")) + { + ctype = getenv ("LC_ALL"); + if (!ctype) + { + ctype = getenv ("LC_CTYPE"); + if (!ctype) + ctype = getenv ("LANG"); + } + } + + /* ignore missing or empty ctype */ + if (ctype && *ctype != '\0') + { + territory = strchr (ctype, '_'); + if (territory) + { + lang_len = territory - ctype; + territory = territory + 1; + after = strchr (territory, '.'); + if (!after) + { + after = strchr (territory, '@'); + if (!after) + after = territory + strlen (territory); + } + territory_len = after - territory; + if (lang_len + 1 + territory_len + 1 <= (int) sizeof (lang_local)) + { + strncpy (lang_local, ctype, lang_len); + lang_local[lang_len] = '-'; + strncpy (lang_local + lang_len + 1, territory, territory_len); + lang_local[lang_len + 1 + territory_len] = '\0'; + } + } + else + { + after = strchr (ctype, '.'); + if (!after) + { + after = strchr (ctype, '@'); + if (!after) + after = ctype + strlen (ctype); + } + lang_len = after - ctype; + if (lang_len + 1 <= (int) sizeof (lang_local)) + { + strncpy (lang_local, ctype, lang_len); + lang_local[lang_len] = '\0'; + } + } + } + + /* set default lang to en */ + if (!lang_local [0]) + strcpy (lang_local, "en"); + + return (FcChar8 *) lang_local; +} + +void +FcDefaultSubstitute (FcPattern *pattern) +{ + FcValue v; + int i; + + if (FcPatternObjectGet (pattern, FC_WEIGHT_OBJECT, 0, &v) == FcResultNoMatch ) + FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_MEDIUM); + + if (FcPatternObjectGet (pattern, FC_SLANT_OBJECT, 0, &v) == FcResultNoMatch) + FcPatternObjectAddInteger (pattern, FC_SLANT_OBJECT, FC_SLANT_ROMAN); + + if (FcPatternObjectGet (pattern, FC_WIDTH_OBJECT, 0, &v) == FcResultNoMatch) + FcPatternObjectAddInteger (pattern, FC_WIDTH_OBJECT, FC_WIDTH_NORMAL); + + for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++) + if (FcPatternObjectGet (pattern, FcBoolDefaults[i].field, 0, &v) == FcResultNoMatch) + FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value); + + if (FcPatternObjectGet (pattern, FC_PIXEL_SIZE_OBJECT, 0, &v) == FcResultNoMatch) + { + double dpi, size, scale; + + if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch) + { + size = 12.0; + (void) FcPatternObjectDel (pattern, FC_SIZE_OBJECT); + FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size); + } + if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch) + { + scale = 1.0; + (void) FcPatternObjectDel (pattern, FC_SCALE_OBJECT); + FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale); + } + size *= scale; + if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch) + { + dpi = 75.0; + (void) FcPatternObjectDel (pattern, FC_DPI_OBJECT); + FcPatternObjectAddDouble (pattern, FC_DPI_OBJECT, dpi); + } + size *= dpi / 72.0; + FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, size); + } + + if (FcPatternObjectGet (pattern, FC_LANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAddString (pattern, FC_LANG_OBJECT, FcGetDefaultLang ()); + } + if (FcPatternObjectGet (pattern, FC_FONTVERSION_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff); + } + + if (FcPatternObjectGet (pattern, FC_HINT_STYLE_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL); + } +} +#define __fcdefault__ +#include "fcaliastail.h" +#undef __fcdefault__ diff --git a/fontconfig/src/fcdir.c b/fontconfig/src/fcdir.c index 7db7961a2..8a2b97625 100644 --- a/fontconfig/src/fcdir.c +++ b/fontconfig/src/fcdir.c @@ -1,325 +1,325 @@ -/*
- * fontconfig/src/fcdir.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <dirent.h>
-
-FcBool
-FcFileIsDir (const FcChar8 *file)
-{
- struct stat statb;
-
- if (FcStat (file, &statb) != 0)
- return FcFalse;
- return S_ISDIR(statb.st_mode);
-}
-
-static FcBool
-FcFileScanFontConfig (FcFontSet *set,
- FcBlanks *blanks,
- const FcChar8 *file,
- FcConfig *config)
-{
- FcPattern *font;
- FcBool ret = FcTrue;
- int id;
- int count = 0;
-
- id = 0;
- do
- {
- font = 0;
- /*
- * Nothing in the cache, scan the file
- */
- 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");
-
- /*
- * Edit pattern with user-defined rules
- */
- if (font && config && !FcConfigSubstitute (config, font, FcMatchScan))
- {
- FcPatternDestroy (font);
- font = NULL;
- ret = FcFalse;
- }
-
- /*
- * Add the font
- */
- if (font)
- {
- if (FcDebug() & FC_DBG_SCANV)
- {
- printf ("Final font pattern:\n");
- FcPatternPrint (font);
- }
- if (!FcFontSetAdd (set, font))
- {
- FcPatternDestroy (font);
- font = NULL;
- ret = FcFalse;
- }
- }
- else if (font)
- FcPatternDestroy (font);
- id++;
- } while (font && ret && id < count);
- return ret;
-}
-
-FcBool
-FcFileScanConfig (FcFontSet *set,
- FcStrSet *dirs,
- FcBlanks *blanks,
- const FcChar8 *file,
- FcConfig *config)
-{
- if (FcFileIsDir (file))
- return FcStrSetAdd (dirs, file);
- else
- return FcFileScanFontConfig (set, blanks, file, config);
-}
-
-FcBool
-FcFileScan (FcFontSet *set,
- FcStrSet *dirs,
- FcFileCache *cache, /* XXX unused */
- FcBlanks *blanks,
- const FcChar8 *file,
- FcBool force)
-{
- return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ());
-}
-
-/*
- * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
- */
-static int
-cmpstringp(const void *p1, const void *p2)
-{
- return strcmp(* (char **) p1, * (char **) p2);
-}
-
-FcBool
-FcDirScanConfig (FcFontSet *set,
- FcStrSet *dirs,
- FcBlanks *blanks,
- const FcChar8 *dir,
- FcBool force, /* XXX unused */
- FcConfig *config)
-{
- DIR *d;
- struct dirent *e;
- FcStrSet *files;
- FcChar8 *file;
- FcChar8 *base;
- FcBool ret = FcTrue;
- int i;
-
- if (!force)
- return FcFalse;
-
- if (!set && !dirs)
- return FcTrue;
-
- if (!blanks)
- blanks = FcConfigGetBlanks (config);
-
- /* freed below */
- file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
- if (!file) {
- ret = FcFalse;
- goto bail;
- }
-
- strcpy ((char *) file, (char *) dir);
- strcat ((char *) file, "/");
- base = file + strlen ((char *) file);
-
- if (FcDebug () & FC_DBG_SCAN)
- printf ("\tScanning dir %s\n", dir);
-
- d = opendir ((char *) dir);
- if (!d)
- {
- /* Don't complain about missing directories */
- if (errno != ENOENT)
- ret = FcFalse;
- goto bail;
- }
-
- files = FcStrSetCreate ();
- if (!files)
- {
- ret = FcFalse;
- goto bail1;
- }
- while ((e = readdir (d)))
- {
- if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
- {
- strcpy ((char *) base, (char *) e->d_name);
- if (!FcStrSetAdd (files, file)) {
- ret = FcFalse;
- goto bail2;
- }
- }
- }
-
- /*
- * Sort files to make things prettier
- */
- qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
-
- /*
- * Scan file files to build font patterns
- */
- for (i = 0; i < files->num; i++)
- FcFileScanConfig (set, dirs, blanks, files->strs[i], config);
-
-bail2:
- FcStrSetDestroy (files);
-bail1:
- closedir (d);
-bail:
- return ret;
-}
-
-FcBool
-FcDirScan (FcFontSet *set,
- FcStrSet *dirs,
- FcFileCache *cache, /* XXX unused */
- FcBlanks *blanks,
- const FcChar8 *dir,
- FcBool force /* XXX unused */)
-{
- if (cache || !force)
- return FcFalse;
-
- return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ());
-}
-
-/*
- * Scan the specified directory and construct a cache of its contents
- */
-FcCache *
-FcDirCacheScan (const FcChar8 *dir, FcConfig *config)
-{
- FcStrSet *dirs;
- FcBool ret = FcTrue;
- FcFontSet *set;
- FcCache *cache = NULL;
- struct stat dir_stat;
-
- if (FcDebug () & FC_DBG_FONTSET)
- printf ("cache scan dir %s\n", dir);
-
- if (FcStat (dir, &dir_stat) < 0)
- {
- if (errno != ENOENT)
- ret = FcFalse;
- goto bail;
- }
-
- set = FcFontSetCreate();
- if (!set)
- {
- ret = FcFalse;
- goto bail;
- }
-
- dirs = FcStrSetCreate ();
- if (!dirs)
- {
- ret = FcFalse;
- goto bail1;
- }
-
- /*
- * Scan the dir
- */
- if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config))
- {
- ret = FcFalse;
- goto bail2;
- }
-
- /*
- * Build the cache object
- */
- cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
- if (!cache)
- {
- ret = FcFalse;
- goto bail2;
- }
-
- /*
- * Write out the cache file, ignoring any troubles
- */
- FcDirCacheWrite (cache, config);
-
- bail2:
- FcStrSetDestroy (dirs);
- bail1:
- FcFontSetDestroy (set);
- bail:
- return cache;
-}
-
-/*
- * Read (or construct) the cache for a directory
- */
-FcCache *
-FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
-{
- FcCache *cache = NULL;
-
- /* Try to use existing cache file */
- if (!force)
- cache = FcDirCacheLoad (dir, config, NULL);
-
- /* Not using existing cache file, construct new cache */
- if (!cache)
- cache = FcDirCacheScan (dir, config);
-
- return cache;
-}
-
-FcBool
-FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
-{
- return FcFalse; /* XXX deprecated */
-}
-#define __fcdir__
-#include "fcaliastail.h"
-#undef __fcdir__
+/* + * fontconfig/src/fcdir.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <dirent.h> + +FcBool +FcFileIsDir (const FcChar8 *file) +{ + struct stat statb; + + if (FcStat (file, &statb) != 0) + return FcFalse; + return S_ISDIR(statb.st_mode); +} + +static FcBool +FcFileScanFontConfig (FcFontSet *set, + FcBlanks *blanks, + const FcChar8 *file, + FcConfig *config) +{ + FcPattern *font; + FcBool ret = FcTrue; + int id; + int count = 0; + + id = 0; + do + { + font = 0; + /* + * Nothing in the cache, scan the file + */ + 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"); + + /* + * Edit pattern with user-defined rules + */ + if (font && config && !FcConfigSubstitute (config, font, FcMatchScan)) + { + FcPatternDestroy (font); + font = NULL; + ret = FcFalse; + } + + /* + * Add the font + */ + if (font) + { + if (FcDebug() & FC_DBG_SCANV) + { + printf ("Final font pattern:\n"); + FcPatternPrint (font); + } + if (!FcFontSetAdd (set, font)) + { + FcPatternDestroy (font); + font = NULL; + ret = FcFalse; + } + } + else if (font) + FcPatternDestroy (font); + id++; + } while (font && ret && id < count); + return ret; +} + +FcBool +FcFileScanConfig (FcFontSet *set, + FcStrSet *dirs, + FcBlanks *blanks, + const FcChar8 *file, + FcConfig *config) +{ + if (FcFileIsDir (file)) + return FcStrSetAdd (dirs, file); + else + return FcFileScanFontConfig (set, blanks, file, config); +} + +FcBool +FcFileScan (FcFontSet *set, + FcStrSet *dirs, + FcFileCache *cache, /* XXX unused */ + FcBlanks *blanks, + const FcChar8 *file, + FcBool force) +{ + return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); +} + +/* + * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage + */ +static int +cmpstringp(const void *p1, const void *p2) +{ + return strcmp(* (char **) p1, * (char **) p2); +} + +FcBool +FcDirScanConfig (FcFontSet *set, + FcStrSet *dirs, + FcBlanks *blanks, + const FcChar8 *dir, + FcBool force, /* XXX unused */ + FcConfig *config) +{ + DIR *d; + struct dirent *e; + FcStrSet *files; + FcChar8 *file; + FcChar8 *base; + FcBool ret = FcTrue; + int i; + + if (!force) + return FcFalse; + + if (!set && !dirs) + return FcTrue; + + if (!blanks) + blanks = FcConfigGetBlanks (config); + + /* freed below */ + file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); + if (!file) { + ret = FcFalse; + goto bail; + } + + strcpy ((char *) file, (char *) dir); + strcat ((char *) file, "/"); + base = file + strlen ((char *) file); + + if (FcDebug () & FC_DBG_SCAN) + printf ("\tScanning dir %s\n", dir); + + d = opendir ((char *) dir); + if (!d) + { + /* Don't complain about missing directories */ + if (errno != ENOENT) + ret = FcFalse; + goto bail; + } + + files = FcStrSetCreate (); + if (!files) + { + ret = FcFalse; + goto bail1; + } + while ((e = readdir (d))) + { + if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) + { + strcpy ((char *) base, (char *) e->d_name); + if (!FcStrSetAdd (files, file)) { + ret = FcFalse; + goto bail2; + } + } + } + + /* + * Sort files to make things prettier + */ + qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); + + /* + * Scan file files to build font patterns + */ + for (i = 0; i < files->num; i++) + FcFileScanConfig (set, dirs, blanks, files->strs[i], config); + +bail2: + FcStrSetDestroy (files); +bail1: + closedir (d); +bail: + return ret; +} + +FcBool +FcDirScan (FcFontSet *set, + FcStrSet *dirs, + FcFileCache *cache, /* XXX unused */ + FcBlanks *blanks, + const FcChar8 *dir, + FcBool force /* XXX unused */) +{ + if (cache || !force) + return FcFalse; + + return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); +} + +/* + * Scan the specified directory and construct a cache of its contents + */ +FcCache * +FcDirCacheScan (const FcChar8 *dir, FcConfig *config) +{ + FcStrSet *dirs; + FcBool ret = FcTrue; + FcFontSet *set; + FcCache *cache = NULL; + struct stat dir_stat; + + if (FcDebug () & FC_DBG_FONTSET) + printf ("cache scan dir %s\n", dir); + + if (FcStat (dir, &dir_stat) < 0) + { + if (errno != ENOENT) + ret = FcFalse; + goto bail; + } + + set = FcFontSetCreate(); + if (!set) + { + ret = FcFalse; + goto bail; + } + + dirs = FcStrSetCreate (); + if (!dirs) + { + ret = FcFalse; + goto bail1; + } + + /* + * Scan the dir + */ + if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config)) + { + ret = FcFalse; + goto bail2; + } + + /* + * Build the cache object + */ + cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); + if (!cache) + { + ret = FcFalse; + goto bail2; + } + + /* + * Write out the cache file, ignoring any troubles + */ + FcDirCacheWrite (cache, config); + + bail2: + FcStrSetDestroy (dirs); + bail1: + FcFontSetDestroy (set); + bail: + return cache; +} + +/* + * Read (or construct) the cache for a directory + */ +FcCache * +FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) +{ + FcCache *cache = NULL; + + /* Try to use existing cache file */ + if (!force) + cache = FcDirCacheLoad (dir, config, NULL); + + /* Not using existing cache file, construct new cache */ + if (!cache) + cache = FcDirCacheScan (dir, config); + + return cache; +} + +FcBool +FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir) +{ + return FcFalse; /* XXX deprecated */ +} +#define __fcdir__ +#include "fcaliastail.h" +#undef __fcdir__ diff --git a/fontconfig/src/fcformat.c b/fontconfig/src/fcformat.c index df184f704..d8518f458 100644 --- a/fontconfig/src/fcformat.c +++ b/fontconfig/src/fcformat.c @@ -1,1214 +1,1214 @@ -/*
- * Copyright © 2008,2009 Red Hat, Inc.
- *
- * Red Hat Author(s): Behdad Esfahbod
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-
-/* The language is documented in doc/fcformat.fncs
- * These are the features implemented:
- *
- * simple %{elt}
- * width %width{elt}
- * index %{elt[idx]}
- * name= %{elt=}
- * :name= %{:elt}
- * default %{elt:-word}
- * count %{#elt}
- * subexpr %{{expr}}
- * filter-out %{-elt1,elt2,elt3{expr}}
- * filter-in %{+elt1,elt2,elt3{expr}}
- * conditional %{?elt1,elt2,!elt3{}{}}
- * enumerate %{[]elt1,elt2{expr}}
- * langset langset enumeration using the same syntax
- * builtin %{=blt}
- * convert %{elt|conv1|conv2|conv3}
- *
- * converters:
- * basename FcStrBasename
- * dirname FcStrDirname
- * downcase FcStrDowncase
- * shescape
- * cescape
- * xmlescape
- * delete delete chars
- * escape escape chars
- * translate translate chars
- *
- * builtins:
- * unparse FcNameUnparse
- * fcmatch fc-match default
- * fclist fc-list default
- * fccat fc-cat default
- * pkgkit PackageKit package tag format
- *
- *
- * Some ideas for future syntax extensions:
- *
- * - verbose builtin that is like FcPatternPrint
- * - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
- * - allow indexing in +, -, ? filtering?
- * - conditional/filtering/deletion on binding (using '(w)'/'(s)'/'(=)' notation)
- */
-
-
-#define FCCAT_FORMAT "\"%{file|basename|cescape}\" %{index} \"%{-file{%{=unparse|cescape}}}\""
-#define FCMATCH_FORMAT "%{file:-<unknown filename>|basename}: \"%{family[0]:-<unknown family>}\" \"%{style[0]:-<unknown style>}\""
-#define FCLIST_FORMAT "%{?file{%{file}: }}%{-file{%{=unparse}}}"
-#define PKGKIT_FORMAT "%{[]family{font(%{family|downcase|delete( )})\n}}%{[]lang{font(:lang=%{lang|downcase|translate(_,-)})\n}}"
-
-
-static void
-message (const char *fmt, ...)
-{
- va_list args;
- va_start (args, fmt);
- fprintf (stderr, "Fontconfig: Pattern format error: ");
- vfprintf (stderr, fmt, args);
- fprintf (stderr, ".\n");
- va_end (args);
-}
-
-
-typedef struct _FcFormatContext
-{
- const FcChar8 *format_orig;
- const FcChar8 *format;
- int format_len;
- FcChar8 *word;
- FcBool word_allocated;
-} FcFormatContext;
-
-static FcBool
-FcFormatContextInit (FcFormatContext *c,
- const FcChar8 *format,
- FcChar8 *scratch,
- int scratch_len)
-{
- c->format_orig = c->format = format;
- c->format_len = strlen ((const char *) format);
-
- if (c->format_len < scratch_len)
- {
- c->word = scratch;
- c->word_allocated = FcFalse;
- }
- else
- {
- c->word = malloc (c->format_len + 1);
- c->word_allocated = FcTrue;
- }
-
- return c->word != NULL;
-}
-
-static void
-FcFormatContextDone (FcFormatContext *c)
-{
- if (c && c->word_allocated)
- {
- free (c->word);
- }
-}
-
-static FcBool
-consume_char (FcFormatContext *c,
- FcChar8 term)
-{
- if (*c->format != term)
- return FcFalse;
-
- c->format++;
- return FcTrue;
-}
-
-static FcBool
-expect_char (FcFormatContext *c,
- FcChar8 term)
-{
- FcBool res = consume_char (c, term);
- if (!res)
- {
- if (c->format == c->format_orig + c->format_len)
- message ("format ended while expecting '%c'",
- term);
- else
- message ("expected '%c' at %d",
- term, c->format - c->format_orig + 1);
- }
- return res;
-}
-
-static FcBool
-FcCharIsPunct (const FcChar8 c)
-{
- if (c < '0')
- return FcTrue;
- if (c <= '9')
- return FcFalse;
- if (c < 'A')
- return FcTrue;
- if (c <= 'Z')
- return FcFalse;
- if (c < 'a')
- return FcTrue;
- if (c <= 'z')
- return FcFalse;
- if (c <= '~')
- return FcTrue;
- return FcFalse;
-}
-
-static char escaped_char(const char ch)
-{
- switch (ch) {
- case 'a': return '\a';
- case 'b': return '\b';
- case 'f': return '\f';
- case 'n': return '\n';
- case 'r': return '\r';
- case 't': return '\t';
- case 'v': return '\v';
- default: return ch;
- }
-}
-
-static FcBool
-read_word (FcFormatContext *c)
-{
- FcChar8 *p;
-
- p = c->word;
-
- while (*c->format)
- {
- if (*c->format == '\\')
- {
- c->format++;
- if (*c->format)
- *p++ = escaped_char (*c->format++);
- continue;
- }
- else if (FcCharIsPunct (*c->format))
- break;
-
- *p++ = *c->format++;
- }
- *p = '\0';
-
- if (p == c->word)
- {
- message ("expected identifier at %d",
- c->format - c->format_orig + 1);
- return FcFalse;
- }
-
- return FcTrue;
-}
-
-static FcBool
-read_chars (FcFormatContext *c,
- FcChar8 term)
-{
- FcChar8 *p;
-
- p = c->word;
-
- while (*c->format && *c->format != '}' && *c->format != term)
- {
- if (*c->format == '\\')
- {
- c->format++;
- if (*c->format)
- *p++ = escaped_char (*c->format++);
- continue;
- }
-
- *p++ = *c->format++;
- }
- *p = '\0';
-
- if (p == c->word)
- {
- message ("expected character data at %d",
- c->format - c->format_orig + 1);
- return FcFalse;
- }
-
- return FcTrue;
-}
-
-static FcBool
-FcPatternFormatToBuf (FcPattern *pat,
- const FcChar8 *format,
- FcStrBuf *buf);
-
-static FcBool
-interpret_builtin (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- FcChar8 *new_str;
- FcBool ret;
-
- if (!expect_char (c, '=') ||
- !read_word (c))
- return FcFalse;
-
- /* try simple builtins first */
- if (0) { }
-#define BUILTIN(name, func) \
- else if (0 == strcmp ((const char *) c->word, name))\
- do { new_str = func (pat); ret = FcTrue; } while (0)
- BUILTIN ("unparse", FcNameUnparse);
- /* BUILTIN ("verbose", FcPatternPrint); XXX */
-#undef BUILTIN
- else
- ret = FcFalse;
-
- if (ret)
- {
- if (new_str)
- {
- FcStrBufString (buf, new_str);
- free (new_str);
- return FcTrue;
- }
- else
- return FcFalse;
- }
-
- /* now try our custom formats */
- if (0) { }
-#define BUILTIN(name, format) \
- else if (0 == strcmp ((const char *) c->word, name))\
- ret = FcPatternFormatToBuf (pat, (const FcChar8 *) format, buf)
- BUILTIN ("fccat", FCCAT_FORMAT);
- BUILTIN ("fcmatch", FCMATCH_FORMAT);
- BUILTIN ("fclist", FCLIST_FORMAT);
- BUILTIN ("pkgkit", PKGKIT_FORMAT);
-#undef BUILTIN
- else
- ret = FcFalse;
-
- if (!ret)
- message ("unknown builtin \"%s\"",
- c->word);
-
- return ret;
-}
-
-static FcBool
-interpret_expr (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf,
- FcChar8 term);
-
-static FcBool
-interpret_subexpr (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- return expect_char (c, '{') &&
- interpret_expr (c, pat, buf, '}') &&
- expect_char (c, '}');
-}
-
-static FcBool
-maybe_interpret_subexpr (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- return (*c->format == '{') ?
- interpret_subexpr (c, pat, buf) :
- FcTrue;
-}
-
-static FcBool
-skip_subexpr (FcFormatContext *c);
-
-static FcBool
-skip_percent (FcFormatContext *c)
-{
- int width;
-
- if (!expect_char (c, '%'))
- return FcFalse;
-
- /* skip an optional width specifier */
- width = strtol ((const char *) c->format, (char **) &c->format, 10);
-
- if (!expect_char (c, '{'))
- return FcFalse;
-
- while(*c->format && *c->format != '}')
- {
- switch (*c->format)
- {
- case '\\':
- c->format++; /* skip over '\\' */
- if (*c->format)
- c->format++;
- continue;
- case '{':
- if (!skip_subexpr (c))
- return FcFalse;
- continue;
- }
- c->format++;
- }
-
- return expect_char (c, '}');
-}
-
-static FcBool
-skip_expr (FcFormatContext *c)
-{
- while(*c->format && *c->format != '}')
- {
- switch (*c->format)
- {
- case '\\':
- c->format++; /* skip over '\\' */
- if (*c->format)
- c->format++;
- continue;
- case '%':
- if (!skip_percent (c))
- return FcFalse;
- continue;
- }
- c->format++;
- }
-
- return FcTrue;
-}
-
-static FcBool
-skip_subexpr (FcFormatContext *c)
-{
- return expect_char (c, '{') &&
- skip_expr (c) &&
- expect_char (c, '}');
-}
-
-static FcBool
-maybe_skip_subexpr (FcFormatContext *c)
-{
- return (*c->format == '{') ?
- skip_subexpr (c) :
- FcTrue;
-}
-
-static FcBool
-interpret_filter_in (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- FcObjectSet *os;
- FcPattern *subpat;
-
- if (!expect_char (c, '+'))
- return FcFalse;
-
- os = FcObjectSetCreate ();
- if (!os)
- return FcFalse;
-
- do
- {
- /* XXX binding */
- if (!read_word (c) ||
- !FcObjectSetAdd (os, (const char *) c->word))
- {
- FcObjectSetDestroy (os);
- return FcFalse;
- }
- }
- while (consume_char (c, ','));
-
- subpat = FcPatternFilter (pat, os);
- FcObjectSetDestroy (os);
-
- if (!subpat ||
- !interpret_subexpr (c, subpat, buf))
- return FcFalse;
-
- FcPatternDestroy (subpat);
- return FcTrue;
-}
-
-static FcBool
-interpret_filter_out (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- FcPattern *subpat;
-
- if (!expect_char (c, '-'))
- return FcFalse;
-
- subpat = FcPatternDuplicate (pat);
- if (!subpat)
- return FcFalse;
-
- do
- {
- if (!read_word (c))
- {
- FcPatternDestroy (subpat);
- return FcFalse;
- }
-
- FcPatternDel (subpat, (const char *) c->word);
- }
- while (consume_char (c, ','));
-
- if (!interpret_subexpr (c, subpat, buf))
- return FcFalse;
-
- FcPatternDestroy (subpat);
- return FcTrue;
-}
-
-static FcBool
-interpret_cond (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- FcBool pass;
-
- if (!expect_char (c, '?'))
- return FcFalse;
-
- pass = FcTrue;
-
- do
- {
- FcBool negate;
- FcValue v;
-
- negate = consume_char (c, '!');
-
- if (!read_word (c))
- return FcFalse;
-
- pass = pass &&
- (negate ^
- (FcResultMatch ==
- FcPatternGet (pat, (const char *) c->word, 0, &v)));
- }
- while (consume_char (c, ','));
-
- if (pass)
- {
- if (!interpret_subexpr (c, pat, buf) ||
- !maybe_skip_subexpr (c))
- return FcFalse;
- }
- else
- {
- if (!skip_subexpr (c) ||
- !maybe_interpret_subexpr (c, pat, buf))
- return FcFalse;
- }
-
- return FcTrue;
-}
-
-static FcBool
-interpret_count (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- int count;
- FcPatternElt *e;
- FcChar8 buf_static[64];
-
- if (!expect_char (c, '#'))
- return FcFalse;
-
- if (!read_word (c))
- return FcFalse;
-
- count = 0;
- e = FcPatternObjectFindElt (pat,
- FcObjectFromName ((const char *) c->word));
- if (e)
- {
- FcValueListPtr l;
- count++;
- for (l = FcPatternEltValues(e);
- l->next;
- l = l->next)
- count++;
- }
-
- snprintf ((char *) buf_static, sizeof (buf_static), "%d", count);
- FcStrBufString (buf, buf_static);
-
- return FcTrue;
-}
-
-static FcBool
-interpret_enumerate (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- FcObjectSet *os;
- FcPattern *subpat;
- const FcChar8 *format_save;
- int idx;
- FcBool ret, done;
- FcStrList *lang_strs;
-
- if (!expect_char (c, '[') ||
- !expect_char (c, ']'))
- return FcFalse;
-
- os = FcObjectSetCreate ();
- if (!os)
- return FcFalse;
-
- ret = FcTrue;
-
- do
- {
- if (!read_word (c) ||
- !FcObjectSetAdd (os, (const char *) c->word))
- {
- FcObjectSetDestroy (os);
- return FcFalse;
- }
- }
- while (consume_char (c, ','));
-
- /* If we have one element and it's of type FcLangSet, we want
- * to enumerate the languages in it. */
- lang_strs = NULL;
- if (os->nobject == 1)
- {
- FcLangSet *langset;
- if (FcResultMatch ==
- FcPatternGetLangSet (pat, os->objects[0], 0, &langset))
- {
- FcStrSet *ss;
- if (!(ss = FcLangSetGetLangs (langset)) ||
- !(lang_strs = FcStrListCreate (ss)))
- goto bail0;
- }
- }
-
- subpat = FcPatternDuplicate (pat);
- if (!subpat)
- goto bail0;
-
- format_save = c->format;
- idx = 0;
- do
- {
- int i;
-
- done = FcTrue;
-
- if (lang_strs)
- {
- FcChar8 *lang;
-
- FcPatternDel (subpat, os->objects[0]);
- if ((lang = FcStrListNext (lang_strs)))
- {
- /* XXX binding? */
- FcPatternAddString (subpat, os->objects[0], lang);
- done = FcFalse;
- }
- }
- else
- {
- for (i = 0; i < os->nobject; i++)
- {
- FcValue v;
-
- /* XXX this can be optimized by accessing valuelist linked lists
- * directly and remembering where we were. Most (all) value lists
- * in normal uses are pretty short though (language tags are
- * stored as a LangSet, not separate values.). */
- FcPatternDel (subpat, os->objects[i]);
- if (FcResultMatch ==
- FcPatternGet (pat, os->objects[i], idx, &v))
- {
- /* XXX binding */
- FcPatternAdd (subpat, os->objects[i], v, FcFalse);
- done = FcFalse;
- }
- }
- }
-
- if (!done)
- {
- c->format = format_save;
- ret = interpret_subexpr (c, subpat, buf);
- if (!ret)
- goto bail;
- }
-
- idx++;
- } while (!done);
-
- if (c->format == format_save)
- skip_subexpr (c);
-
-bail:
- FcPatternDestroy (subpat);
-bail0:
- if (lang_strs)
- FcStrListDone (lang_strs);
- FcObjectSetDestroy (os);
-
- return ret;
-}
-
-static FcBool
-interpret_simple (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- FcPatternElt *e;
- FcBool add_colon = FcFalse;
- FcBool add_elt_name = FcFalse;
- int idx;
- FcChar8 *else_string;
-
- if (consume_char (c, ':'))
- add_colon = FcTrue;
-
- if (!read_word (c))
- return FcFalse;
-
- idx = -1;
- if (consume_char (c, '['))
- {
- idx = strtol ((const char *) c->format, (char **) &c->format, 10);
- if (idx < 0)
- {
- message ("expected non-negative number at %d",
- c->format-1 - c->format_orig + 1);
- return FcFalse;
- }
- if (!expect_char (c, ']'))
- return FcFalse;
- }
-
- if (consume_char (c, '='))
- add_elt_name = FcTrue;
-
- /* modifiers */
- else_string = NULL;
- if (consume_char (c, ':'))
- {
- FcChar8 *orig;
- /* divert the c->word for now */
- orig = c->word;
- c->word = c->word + strlen ((const char *) c->word) + 1;
- /* for now we just support 'default value' */
- if (!expect_char (c, '-') ||
- !read_chars (c, '|'))
- {
- c->word = orig;
- return FcFalse;
- }
- else_string = c->word;
- c->word = orig;
- }
-
- e = FcPatternObjectFindElt (pat,
- FcObjectFromName ((const char *) c->word));
- if (e || else_string)
- {
- FcValueListPtr l = NULL;
-
- if (add_colon)
- FcStrBufChar (buf, ':');
- if (add_elt_name)
- {
- FcStrBufString (buf, c->word);
- FcStrBufChar (buf, '=');
- }
-
- if (e)
- l = FcPatternEltValues(e);
-
- if (idx != -1)
- {
- while (l && idx > 0)
- {
- l = FcValueListNext(l);
- idx--;
- }
- if (l && idx == 0)
- {
- if (!FcNameUnparseValue (buf, &l->value, '\0'))
- return FcFalse;
- }
- else goto notfound;
- }
- else if (l)
- {
- FcNameUnparseValueList (buf, l, '\0');
- }
- else
- {
- notfound:
- if (else_string)
- FcStrBufString (buf, else_string);
- }
- }
-
- return FcTrue;
-}
-
-static FcBool
-cescape (FcFormatContext *c,
- const FcChar8 *str,
- FcStrBuf *buf)
-{
- /* XXX escape \n etc? */
-
- while(*str)
- {
- switch (*str)
- {
- case '\\':
- case '"':
- FcStrBufChar (buf, '\\');
- break;
- }
- FcStrBufChar (buf, *str++);
- }
- return FcTrue;
-}
-
-static FcBool
-shescape (FcFormatContext *c,
- const FcChar8 *str,
- FcStrBuf *buf)
-{
- FcStrBufChar (buf, '\'');
- while(*str)
- {
- if (*str == '\'')
- FcStrBufString (buf, (const FcChar8 *) "'\\''");
- else
- FcStrBufChar (buf, *str);
- str++;
- }
- FcStrBufChar (buf, '\'');
- return FcTrue;
-}
-
-static FcBool
-xmlescape (FcFormatContext *c,
- const FcChar8 *str,
- FcStrBuf *buf)
-{
- /* XXX escape \n etc? */
-
- while(*str)
- {
- switch (*str)
- {
- case '&': FcStrBufString (buf, (const FcChar8 *) "&"); break;
- case '<': FcStrBufString (buf, (const FcChar8 *) "<"); break;
- case '>': FcStrBufString (buf, (const FcChar8 *) ">"); break;
- default: FcStrBufChar (buf, *str); break;
- }
- str++;
- }
- return FcTrue;
-}
-
-static FcBool
-delete_chars (FcFormatContext *c,
- const FcChar8 *str,
- FcStrBuf *buf)
-{
- /* XXX not UTF-8 aware */
-
- if (!expect_char (c, '(') ||
- !read_chars (c, ')') ||
- !expect_char (c, ')'))
- return FcFalse;
-
- while(*str)
- {
- FcChar8 *p;
-
- p = (FcChar8 *) strpbrk ((const char *) str, (const char *) c->word);
- if (p)
- {
- FcStrBufData (buf, str, p - str);
- str = p + 1;
- }
- else
- {
- FcStrBufString (buf, str);
- break;
- }
-
- }
-
- return FcTrue;
-}
-
-static FcBool
-escape_chars (FcFormatContext *c,
- const FcChar8 *str,
- FcStrBuf *buf)
-{
- /* XXX not UTF-8 aware */
-
- if (!expect_char (c, '(') ||
- !read_chars (c, ')') ||
- !expect_char (c, ')'))
- return FcFalse;
-
- while(*str)
- {
- FcChar8 *p;
-
- p = (FcChar8 *) strpbrk ((const char *) str, (const char *) c->word);
- if (p)
- {
- FcStrBufData (buf, str, p - str);
- FcStrBufChar (buf, c->word[0]);
- FcStrBufChar (buf, *p);
- str = p + 1;
- }
- else
- {
- FcStrBufString (buf, str);
- break;
- }
-
- }
-
- return FcTrue;
-}
-
-static FcBool
-translate_chars (FcFormatContext *c,
- const FcChar8 *str,
- FcStrBuf *buf)
-{
- char *from, *to, repeat;
- int from_len, to_len;
-
- /* XXX not UTF-8 aware */
-
- if (!expect_char (c, '(') ||
- !read_chars (c, ',') ||
- !expect_char (c, ','))
- return FcFalse;
-
- from = (char *) c->word;
- from_len = strlen (from);
- to = from + from_len + 1;
-
- /* hack: we temporarily divert c->word */
- c->word = (FcChar8 *) to;
- if (!read_chars (c, ')'))
- {
- c->word = (FcChar8 *) from;
- return FcFalse;
- }
- c->word = (FcChar8 *) from;
-
- to_len = strlen (to);
- repeat = to[to_len - 1];
-
- if (!expect_char (c, ')'))
- return FcFalse;
-
- while(*str)
- {
- FcChar8 *p;
-
- p = (FcChar8 *) strpbrk ((const char *) str, (const char *) from);
- if (p)
- {
- int i;
- FcStrBufData (buf, str, p - str);
- i = strchr (from, *p) - from;
- FcStrBufChar (buf, i < to_len ? to[i] : repeat);
- str = p + 1;
- }
- else
- {
- FcStrBufString (buf, str);
- break;
- }
-
- }
-
- return FcTrue;
-}
-
-static FcBool
-interpret_convert (FcFormatContext *c,
- FcStrBuf *buf,
- int start)
-{
- const FcChar8 *str;
- FcChar8 *new_str;
- FcStrBuf new_buf;
- FcChar8 buf_static[8192];
- FcBool ret;
-
- if (!expect_char (c, '|') ||
- !read_word (c))
- return FcFalse;
-
- /* prepare the buffer */
- FcStrBufChar (buf, '\0');
- if (buf->failed)
- return FcFalse;
- str = buf->buf + start;
- buf->len = start;
-
- /* try simple converters first */
- if (0) { }
-#define CONVERTER(name, func) \
- else if (0 == strcmp ((const char *) c->word, name))\
- do { new_str = func (str); ret = FcTrue; } while (0)
- CONVERTER ("downcase", FcStrDowncase);
- CONVERTER ("basename", FcStrBasename);
- CONVERTER ("dirname", FcStrDirname);
-#undef CONVERTER
- else
- ret = FcFalse;
-
- if (ret)
- {
- if (new_str)
- {
- FcStrBufString (buf, new_str);
- free (new_str);
- return FcTrue;
- }
- else
- return FcFalse;
- }
-
- FcStrBufInit (&new_buf, buf_static, sizeof (buf_static));
-
- /* now try our custom converters */
- if (0) { }
-#define CONVERTER(name, func) \
- else if (0 == strcmp ((const char *) c->word, name))\
- ret = func (c, str, &new_buf)
- CONVERTER ("cescape", cescape);
- CONVERTER ("shescape", shescape);
- CONVERTER ("xmlescape", xmlescape);
- CONVERTER ("delete", delete_chars);
- CONVERTER ("escape", escape_chars);
- CONVERTER ("translate", translate_chars);
-#undef CONVERTER
- else
- ret = FcFalse;
-
- if (ret)
- {
- FcStrBufChar (&new_buf, '\0');
- FcStrBufString (buf, new_buf.buf);
- }
- else
- message ("unknown converter \"%s\"",
- c->word);
-
- FcStrBufDestroy (&new_buf);
-
- return ret;
-}
-
-static FcBool
-maybe_interpret_converts (FcFormatContext *c,
- FcStrBuf *buf,
- int start)
-{
- while (*c->format == '|')
- if (!interpret_convert (c, buf, start))
- return FcFalse;
-
- return FcTrue;
-}
-
-static FcBool
-align_to_width (FcStrBuf *buf,
- int start,
- int width)
-{
- int len;
-
- if (buf->failed)
- return FcFalse;
-
- len = buf->len - start;
- if (len < -width)
- {
- /* left align */
- while (len++ < -width)
- FcStrBufChar (buf, ' ');
- }
- else if (len < width)
- {
- int old_len;
- old_len = len;
- /* right align */
- while (len++ < width)
- FcStrBufChar (buf, ' ');
- if (buf->failed)
- return FcFalse;
- len = old_len;
- memmove (buf->buf + buf->len - len,
- buf->buf + buf->len - width,
- len);
- memset (buf->buf + buf->len - width,
- ' ',
- width - len);
- }
-
- return !buf->failed;
-}
-static FcBool
-interpret_percent (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
-{
- int width, start;
- FcBool ret;
-
- if (!expect_char (c, '%'))
- return FcFalse;
-
- if (consume_char (c, '%')) /* "%%" */
- {
- FcStrBufChar (buf, '%');
- return FcTrue;
- }
-
- /* parse an optional width specifier */
- width = strtol ((const char *) c->format, (char **) &c->format, 10);
-
- if (!expect_char (c, '{'))
- return FcFalse;
-
- start = buf->len;
-
- switch (*c->format) {
- case '=': ret = interpret_builtin (c, pat, buf); break;
- case '{': ret = interpret_subexpr (c, pat, buf); break;
- case '+': ret = interpret_filter_in (c, pat, buf); break;
- case '-': ret = interpret_filter_out (c, pat, buf); break;
- case '?': ret = interpret_cond (c, pat, buf); break;
- case '#': ret = interpret_count (c, pat, buf); break;
- case '[': ret = interpret_enumerate (c, pat, buf); break;
- default: ret = interpret_simple (c, pat, buf); break;
- }
-
- return ret &&
- maybe_interpret_converts (c, buf, start) &&
- align_to_width (buf, start, width) &&
- expect_char (c, '}');
-}
-
-static FcBool
-interpret_expr (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf,
- FcChar8 term)
-{
- while (*c->format && *c->format != term)
- {
- switch (*c->format)
- {
- case '\\':
- c->format++; /* skip over '\\' */
- if (*c->format)
- FcStrBufChar (buf, escaped_char (*c->format++));
- continue;
- case '%':
- if (!interpret_percent (c, pat, buf))
- return FcFalse;
- continue;
- }
- FcStrBufChar (buf, *c->format++);
- }
- return FcTrue;
-}
-
-static FcBool
-FcPatternFormatToBuf (FcPattern *pat,
- const FcChar8 *format,
- FcStrBuf *buf)
-{
- FcFormatContext c;
- FcChar8 word_static[1024];
- FcBool ret;
-
- if (!FcFormatContextInit (&c, format, word_static, sizeof (word_static)))
- return FcFalse;
-
- ret = interpret_expr (&c, pat, buf, '\0');
-
- FcFormatContextDone (&c);
-
- return ret;
-}
-
-FcChar8 *
-FcPatternFormat (FcPattern *pat,
- const FcChar8 *format)
-{
- FcStrBuf buf;
- FcChar8 buf_static[8192 - 1024];
- FcBool ret;
-
- FcStrBufInit (&buf, buf_static, sizeof (buf_static));
-
- ret = FcPatternFormatToBuf (pat, format, &buf);
-
- if (ret)
- return FcStrBufDone (&buf);
- else
- {
- FcStrBufDestroy (&buf);
- return NULL;
- }
-}
-
-#define __fcformat__
-#include "fcaliastail.h"
-#undef __fcformat__
+/* + * Copyright © 2008,2009 Red Hat, Inc. + * + * Red Hat Author(s): Behdad Esfahbod + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + + +/* The language is documented in doc/fcformat.fncs + * These are the features implemented: + * + * simple %{elt} + * width %width{elt} + * index %{elt[idx]} + * name= %{elt=} + * :name= %{:elt} + * default %{elt:-word} + * count %{#elt} + * subexpr %{{expr}} + * filter-out %{-elt1,elt2,elt3{expr}} + * filter-in %{+elt1,elt2,elt3{expr}} + * conditional %{?elt1,elt2,!elt3{}{}} + * enumerate %{[]elt1,elt2{expr}} + * langset langset enumeration using the same syntax + * builtin %{=blt} + * convert %{elt|conv1|conv2|conv3} + * + * converters: + * basename FcStrBasename + * dirname FcStrDirname + * downcase FcStrDowncase + * shescape + * cescape + * xmlescape + * delete delete chars + * escape escape chars + * translate translate chars + * + * builtins: + * unparse FcNameUnparse + * fcmatch fc-match default + * fclist fc-list default + * fccat fc-cat default + * pkgkit PackageKit package tag format + * + * + * Some ideas for future syntax extensions: + * + * - verbose builtin that is like FcPatternPrint + * - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}' + * - allow indexing in +, -, ? filtering? + * - conditional/filtering/deletion on binding (using '(w)'/'(s)'/'(=)' notation) + */ + + +#define FCCAT_FORMAT "\"%{file|basename|cescape}\" %{index} \"%{-file{%{=unparse|cescape}}}\"" +#define FCMATCH_FORMAT "%{file:-<unknown filename>|basename}: \"%{family[0]:-<unknown family>}\" \"%{style[0]:-<unknown style>}\"" +#define FCLIST_FORMAT "%{?file{%{file}: }}%{-file{%{=unparse}}}" +#define PKGKIT_FORMAT "%{[]family{font(%{family|downcase|delete( )})\n}}%{[]lang{font(:lang=%{lang|downcase|translate(_,-)})\n}}" + + +static void +message (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + fprintf (stderr, "Fontconfig: Pattern format error: "); + vfprintf (stderr, fmt, args); + fprintf (stderr, ".\n"); + va_end (args); +} + + +typedef struct _FcFormatContext +{ + const FcChar8 *format_orig; + const FcChar8 *format; + int format_len; + FcChar8 *word; + FcBool word_allocated; +} FcFormatContext; + +static FcBool +FcFormatContextInit (FcFormatContext *c, + const FcChar8 *format, + FcChar8 *scratch, + int scratch_len) +{ + c->format_orig = c->format = format; + c->format_len = strlen ((const char *) format); + + if (c->format_len < scratch_len) + { + c->word = scratch; + c->word_allocated = FcFalse; + } + else + { + c->word = malloc (c->format_len + 1); + c->word_allocated = FcTrue; + } + + return c->word != NULL; +} + +static void +FcFormatContextDone (FcFormatContext *c) +{ + if (c && c->word_allocated) + { + free (c->word); + } +} + +static FcBool +consume_char (FcFormatContext *c, + FcChar8 term) +{ + if (*c->format != term) + return FcFalse; + + c->format++; + return FcTrue; +} + +static FcBool +expect_char (FcFormatContext *c, + FcChar8 term) +{ + FcBool res = consume_char (c, term); + if (!res) + { + if (c->format == c->format_orig + c->format_len) + message ("format ended while expecting '%c'", + term); + else + message ("expected '%c' at %d", + term, c->format - c->format_orig + 1); + } + return res; +} + +static FcBool +FcCharIsPunct (const FcChar8 c) +{ + if (c < '0') + return FcTrue; + if (c <= '9') + return FcFalse; + if (c < 'A') + return FcTrue; + if (c <= 'Z') + return FcFalse; + if (c < 'a') + return FcTrue; + if (c <= 'z') + return FcFalse; + if (c <= '~') + return FcTrue; + return FcFalse; +} + +static char escaped_char(const char ch) +{ + switch (ch) { + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + default: return ch; + } +} + +static FcBool +read_word (FcFormatContext *c) +{ + FcChar8 *p; + + p = c->word; + + while (*c->format) + { + if (*c->format == '\\') + { + c->format++; + if (*c->format) + *p++ = escaped_char (*c->format++); + continue; + } + else if (FcCharIsPunct (*c->format)) + break; + + *p++ = *c->format++; + } + *p = '\0'; + + if (p == c->word) + { + message ("expected identifier at %d", + c->format - c->format_orig + 1); + return FcFalse; + } + + return FcTrue; +} + +static FcBool +read_chars (FcFormatContext *c, + FcChar8 term) +{ + FcChar8 *p; + + p = c->word; + + while (*c->format && *c->format != '}' && *c->format != term) + { + if (*c->format == '\\') + { + c->format++; + if (*c->format) + *p++ = escaped_char (*c->format++); + continue; + } + + *p++ = *c->format++; + } + *p = '\0'; + + if (p == c->word) + { + message ("expected character data at %d", + c->format - c->format_orig + 1); + return FcFalse; + } + + return FcTrue; +} + +static FcBool +FcPatternFormatToBuf (FcPattern *pat, + const FcChar8 *format, + FcStrBuf *buf); + +static FcBool +interpret_builtin (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcChar8 *new_str; + FcBool ret; + + if (!expect_char (c, '=') || + !read_word (c)) + return FcFalse; + + /* try simple builtins first */ + if (0) { } +#define BUILTIN(name, func) \ + else if (0 == strcmp ((const char *) c->word, name))\ + do { new_str = func (pat); ret = FcTrue; } while (0) + BUILTIN ("unparse", FcNameUnparse); + /* BUILTIN ("verbose", FcPatternPrint); XXX */ +#undef BUILTIN + else + ret = FcFalse; + + if (ret) + { + if (new_str) + { + FcStrBufString (buf, new_str); + free (new_str); + return FcTrue; + } + else + return FcFalse; + } + + /* now try our custom formats */ + if (0) { } +#define BUILTIN(name, format) \ + else if (0 == strcmp ((const char *) c->word, name))\ + ret = FcPatternFormatToBuf (pat, (const FcChar8 *) format, buf) + BUILTIN ("fccat", FCCAT_FORMAT); + BUILTIN ("fcmatch", FCMATCH_FORMAT); + BUILTIN ("fclist", FCLIST_FORMAT); + BUILTIN ("pkgkit", PKGKIT_FORMAT); +#undef BUILTIN + else + ret = FcFalse; + + if (!ret) + message ("unknown builtin \"%s\"", + c->word); + + return ret; +} + +static FcBool +interpret_expr (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf, + FcChar8 term); + +static FcBool +interpret_subexpr (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + return expect_char (c, '{') && + interpret_expr (c, pat, buf, '}') && + expect_char (c, '}'); +} + +static FcBool +maybe_interpret_subexpr (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + return (*c->format == '{') ? + interpret_subexpr (c, pat, buf) : + FcTrue; +} + +static FcBool +skip_subexpr (FcFormatContext *c); + +static FcBool +skip_percent (FcFormatContext *c) +{ + int width; + + if (!expect_char (c, '%')) + return FcFalse; + + /* skip an optional width specifier */ + width = strtol ((const char *) c->format, (char **) &c->format, 10); + + if (!expect_char (c, '{')) + return FcFalse; + + while(*c->format && *c->format != '}') + { + switch (*c->format) + { + case '\\': + c->format++; /* skip over '\\' */ + if (*c->format) + c->format++; + continue; + case '{': + if (!skip_subexpr (c)) + return FcFalse; + continue; + } + c->format++; + } + + return expect_char (c, '}'); +} + +static FcBool +skip_expr (FcFormatContext *c) +{ + while(*c->format && *c->format != '}') + { + switch (*c->format) + { + case '\\': + c->format++; /* skip over '\\' */ + if (*c->format) + c->format++; + continue; + case '%': + if (!skip_percent (c)) + return FcFalse; + continue; + } + c->format++; + } + + return FcTrue; +} + +static FcBool +skip_subexpr (FcFormatContext *c) +{ + return expect_char (c, '{') && + skip_expr (c) && + expect_char (c, '}'); +} + +static FcBool +maybe_skip_subexpr (FcFormatContext *c) +{ + return (*c->format == '{') ? + skip_subexpr (c) : + FcTrue; +} + +static FcBool +interpret_filter_in (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcObjectSet *os; + FcPattern *subpat; + + if (!expect_char (c, '+')) + return FcFalse; + + os = FcObjectSetCreate (); + if (!os) + return FcFalse; + + do + { + /* XXX binding */ + if (!read_word (c) || + !FcObjectSetAdd (os, (const char *) c->word)) + { + FcObjectSetDestroy (os); + return FcFalse; + } + } + while (consume_char (c, ',')); + + subpat = FcPatternFilter (pat, os); + FcObjectSetDestroy (os); + + if (!subpat || + !interpret_subexpr (c, subpat, buf)) + return FcFalse; + + FcPatternDestroy (subpat); + return FcTrue; +} + +static FcBool +interpret_filter_out (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcPattern *subpat; + + if (!expect_char (c, '-')) + return FcFalse; + + subpat = FcPatternDuplicate (pat); + if (!subpat) + return FcFalse; + + do + { + if (!read_word (c)) + { + FcPatternDestroy (subpat); + return FcFalse; + } + + FcPatternDel (subpat, (const char *) c->word); + } + while (consume_char (c, ',')); + + if (!interpret_subexpr (c, subpat, buf)) + return FcFalse; + + FcPatternDestroy (subpat); + return FcTrue; +} + +static FcBool +interpret_cond (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcBool pass; + + if (!expect_char (c, '?')) + return FcFalse; + + pass = FcTrue; + + do + { + FcBool negate; + FcValue v; + + negate = consume_char (c, '!'); + + if (!read_word (c)) + return FcFalse; + + pass = pass && + (negate ^ + (FcResultMatch == + FcPatternGet (pat, (const char *) c->word, 0, &v))); + } + while (consume_char (c, ',')); + + if (pass) + { + if (!interpret_subexpr (c, pat, buf) || + !maybe_skip_subexpr (c)) + return FcFalse; + } + else + { + if (!skip_subexpr (c) || + !maybe_interpret_subexpr (c, pat, buf)) + return FcFalse; + } + + return FcTrue; +} + +static FcBool +interpret_count (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + int count; + FcPatternElt *e; + FcChar8 buf_static[64]; + + if (!expect_char (c, '#')) + return FcFalse; + + if (!read_word (c)) + return FcFalse; + + count = 0; + e = FcPatternObjectFindElt (pat, + FcObjectFromName ((const char *) c->word)); + if (e) + { + FcValueListPtr l; + count++; + for (l = FcPatternEltValues(e); + l->next; + l = l->next) + count++; + } + + snprintf ((char *) buf_static, sizeof (buf_static), "%d", count); + FcStrBufString (buf, buf_static); + + return FcTrue; +} + +static FcBool +interpret_enumerate (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcObjectSet *os; + FcPattern *subpat; + const FcChar8 *format_save; + int idx; + FcBool ret, done; + FcStrList *lang_strs; + + if (!expect_char (c, '[') || + !expect_char (c, ']')) + return FcFalse; + + os = FcObjectSetCreate (); + if (!os) + return FcFalse; + + ret = FcTrue; + + do + { + if (!read_word (c) || + !FcObjectSetAdd (os, (const char *) c->word)) + { + FcObjectSetDestroy (os); + return FcFalse; + } + } + while (consume_char (c, ',')); + + /* If we have one element and it's of type FcLangSet, we want + * to enumerate the languages in it. */ + lang_strs = NULL; + if (os->nobject == 1) + { + FcLangSet *langset; + if (FcResultMatch == + FcPatternGetLangSet (pat, os->objects[0], 0, &langset)) + { + FcStrSet *ss; + if (!(ss = FcLangSetGetLangs (langset)) || + !(lang_strs = FcStrListCreate (ss))) + goto bail0; + } + } + + subpat = FcPatternDuplicate (pat); + if (!subpat) + goto bail0; + + format_save = c->format; + idx = 0; + do + { + int i; + + done = FcTrue; + + if (lang_strs) + { + FcChar8 *lang; + + FcPatternDel (subpat, os->objects[0]); + if ((lang = FcStrListNext (lang_strs))) + { + /* XXX binding? */ + FcPatternAddString (subpat, os->objects[0], lang); + done = FcFalse; + } + } + else + { + for (i = 0; i < os->nobject; i++) + { + FcValue v; + + /* XXX this can be optimized by accessing valuelist linked lists + * directly and remembering where we were. Most (all) value lists + * in normal uses are pretty short though (language tags are + * stored as a LangSet, not separate values.). */ + FcPatternDel (subpat, os->objects[i]); + if (FcResultMatch == + FcPatternGet (pat, os->objects[i], idx, &v)) + { + /* XXX binding */ + FcPatternAdd (subpat, os->objects[i], v, FcFalse); + done = FcFalse; + } + } + } + + if (!done) + { + c->format = format_save; + ret = interpret_subexpr (c, subpat, buf); + if (!ret) + goto bail; + } + + idx++; + } while (!done); + + if (c->format == format_save) + skip_subexpr (c); + +bail: + FcPatternDestroy (subpat); +bail0: + if (lang_strs) + FcStrListDone (lang_strs); + FcObjectSetDestroy (os); + + return ret; +} + +static FcBool +interpret_simple (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcPatternElt *e; + FcBool add_colon = FcFalse; + FcBool add_elt_name = FcFalse; + int idx; + FcChar8 *else_string; + + if (consume_char (c, ':')) + add_colon = FcTrue; + + if (!read_word (c)) + return FcFalse; + + idx = -1; + if (consume_char (c, '[')) + { + idx = strtol ((const char *) c->format, (char **) &c->format, 10); + if (idx < 0) + { + message ("expected non-negative number at %d", + c->format-1 - c->format_orig + 1); + return FcFalse; + } + if (!expect_char (c, ']')) + return FcFalse; + } + + if (consume_char (c, '=')) + add_elt_name = FcTrue; + + /* modifiers */ + else_string = NULL; + if (consume_char (c, ':')) + { + FcChar8 *orig; + /* divert the c->word for now */ + orig = c->word; + c->word = c->word + strlen ((const char *) c->word) + 1; + /* for now we just support 'default value' */ + if (!expect_char (c, '-') || + !read_chars (c, '|')) + { + c->word = orig; + return FcFalse; + } + else_string = c->word; + c->word = orig; + } + + e = FcPatternObjectFindElt (pat, + FcObjectFromName ((const char *) c->word)); + if (e || else_string) + { + FcValueListPtr l = NULL; + + if (add_colon) + FcStrBufChar (buf, ':'); + if (add_elt_name) + { + FcStrBufString (buf, c->word); + FcStrBufChar (buf, '='); + } + + if (e) + l = FcPatternEltValues(e); + + if (idx != -1) + { + while (l && idx > 0) + { + l = FcValueListNext(l); + idx--; + } + if (l && idx == 0) + { + if (!FcNameUnparseValue (buf, &l->value, '\0')) + return FcFalse; + } + else goto notfound; + } + else if (l) + { + FcNameUnparseValueList (buf, l, '\0'); + } + else + { + notfound: + if (else_string) + FcStrBufString (buf, else_string); + } + } + + return FcTrue; +} + +static FcBool +cescape (FcFormatContext *c, + const FcChar8 *str, + FcStrBuf *buf) +{ + /* XXX escape \n etc? */ + + while(*str) + { + switch (*str) + { + case '\\': + case '"': + FcStrBufChar (buf, '\\'); + break; + } + FcStrBufChar (buf, *str++); + } + return FcTrue; +} + +static FcBool +shescape (FcFormatContext *c, + const FcChar8 *str, + FcStrBuf *buf) +{ + FcStrBufChar (buf, '\''); + while(*str) + { + if (*str == '\'') + FcStrBufString (buf, (const FcChar8 *) "'\\''"); + else + FcStrBufChar (buf, *str); + str++; + } + FcStrBufChar (buf, '\''); + return FcTrue; +} + +static FcBool +xmlescape (FcFormatContext *c, + const FcChar8 *str, + FcStrBuf *buf) +{ + /* XXX escape \n etc? */ + + while(*str) + { + switch (*str) + { + case '&': FcStrBufString (buf, (const FcChar8 *) "&"); break; + case '<': FcStrBufString (buf, (const FcChar8 *) "<"); break; + case '>': FcStrBufString (buf, (const FcChar8 *) ">"); break; + default: FcStrBufChar (buf, *str); break; + } + str++; + } + return FcTrue; +} + +static FcBool +delete_chars (FcFormatContext *c, + const FcChar8 *str, + FcStrBuf *buf) +{ + /* XXX not UTF-8 aware */ + + if (!expect_char (c, '(') || + !read_chars (c, ')') || + !expect_char (c, ')')) + return FcFalse; + + while(*str) + { + FcChar8 *p; + + p = (FcChar8 *) strpbrk ((const char *) str, (const char *) c->word); + if (p) + { + FcStrBufData (buf, str, p - str); + str = p + 1; + } + else + { + FcStrBufString (buf, str); + break; + } + + } + + return FcTrue; +} + +static FcBool +escape_chars (FcFormatContext *c, + const FcChar8 *str, + FcStrBuf *buf) +{ + /* XXX not UTF-8 aware */ + + if (!expect_char (c, '(') || + !read_chars (c, ')') || + !expect_char (c, ')')) + return FcFalse; + + while(*str) + { + FcChar8 *p; + + p = (FcChar8 *) strpbrk ((const char *) str, (const char *) c->word); + if (p) + { + FcStrBufData (buf, str, p - str); + FcStrBufChar (buf, c->word[0]); + FcStrBufChar (buf, *p); + str = p + 1; + } + else + { + FcStrBufString (buf, str); + break; + } + + } + + return FcTrue; +} + +static FcBool +translate_chars (FcFormatContext *c, + const FcChar8 *str, + FcStrBuf *buf) +{ + char *from, *to, repeat; + int from_len, to_len; + + /* XXX not UTF-8 aware */ + + if (!expect_char (c, '(') || + !read_chars (c, ',') || + !expect_char (c, ',')) + return FcFalse; + + from = (char *) c->word; + from_len = strlen (from); + to = from + from_len + 1; + + /* hack: we temporarily divert c->word */ + c->word = (FcChar8 *) to; + if (!read_chars (c, ')')) + { + c->word = (FcChar8 *) from; + return FcFalse; + } + c->word = (FcChar8 *) from; + + to_len = strlen (to); + repeat = to[to_len - 1]; + + if (!expect_char (c, ')')) + return FcFalse; + + while(*str) + { + FcChar8 *p; + + p = (FcChar8 *) strpbrk ((const char *) str, (const char *) from); + if (p) + { + int i; + FcStrBufData (buf, str, p - str); + i = strchr (from, *p) - from; + FcStrBufChar (buf, i < to_len ? to[i] : repeat); + str = p + 1; + } + else + { + FcStrBufString (buf, str); + break; + } + + } + + return FcTrue; +} + +static FcBool +interpret_convert (FcFormatContext *c, + FcStrBuf *buf, + int start) +{ + const FcChar8 *str; + FcChar8 *new_str; + FcStrBuf new_buf; + FcChar8 buf_static[8192]; + FcBool ret; + + if (!expect_char (c, '|') || + !read_word (c)) + return FcFalse; + + /* prepare the buffer */ + FcStrBufChar (buf, '\0'); + if (buf->failed) + return FcFalse; + str = buf->buf + start; + buf->len = start; + + /* try simple converters first */ + if (0) { } +#define CONVERTER(name, func) \ + else if (0 == strcmp ((const char *) c->word, name))\ + do { new_str = func (str); ret = FcTrue; } while (0) + CONVERTER ("downcase", FcStrDowncase); + CONVERTER ("basename", FcStrBasename); + CONVERTER ("dirname", FcStrDirname); +#undef CONVERTER + else + ret = FcFalse; + + if (ret) + { + if (new_str) + { + FcStrBufString (buf, new_str); + free (new_str); + return FcTrue; + } + else + return FcFalse; + } + + FcStrBufInit (&new_buf, buf_static, sizeof (buf_static)); + + /* now try our custom converters */ + if (0) { } +#define CONVERTER(name, func) \ + else if (0 == strcmp ((const char *) c->word, name))\ + ret = func (c, str, &new_buf) + CONVERTER ("cescape", cescape); + CONVERTER ("shescape", shescape); + CONVERTER ("xmlescape", xmlescape); + CONVERTER ("delete", delete_chars); + CONVERTER ("escape", escape_chars); + CONVERTER ("translate", translate_chars); +#undef CONVERTER + else + ret = FcFalse; + + if (ret) + { + FcStrBufChar (&new_buf, '\0'); + FcStrBufString (buf, new_buf.buf); + } + else + message ("unknown converter \"%s\"", + c->word); + + FcStrBufDestroy (&new_buf); + + return ret; +} + +static FcBool +maybe_interpret_converts (FcFormatContext *c, + FcStrBuf *buf, + int start) +{ + while (*c->format == '|') + if (!interpret_convert (c, buf, start)) + return FcFalse; + + return FcTrue; +} + +static FcBool +align_to_width (FcStrBuf *buf, + int start, + int width) +{ + int len; + + if (buf->failed) + return FcFalse; + + len = buf->len - start; + if (len < -width) + { + /* left align */ + while (len++ < -width) + FcStrBufChar (buf, ' '); + } + else if (len < width) + { + int old_len; + old_len = len; + /* right align */ + while (len++ < width) + FcStrBufChar (buf, ' '); + if (buf->failed) + return FcFalse; + len = old_len; + memmove (buf->buf + buf->len - len, + buf->buf + buf->len - width, + len); + memset (buf->buf + buf->len - width, + ' ', + width - len); + } + + return !buf->failed; +} +static FcBool +interpret_percent (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + int width, start; + FcBool ret; + + if (!expect_char (c, '%')) + return FcFalse; + + if (consume_char (c, '%')) /* "%%" */ + { + FcStrBufChar (buf, '%'); + return FcTrue; + } + + /* parse an optional width specifier */ + width = strtol ((const char *) c->format, (char **) &c->format, 10); + + if (!expect_char (c, '{')) + return FcFalse; + + start = buf->len; + + switch (*c->format) { + case '=': ret = interpret_builtin (c, pat, buf); break; + case '{': ret = interpret_subexpr (c, pat, buf); break; + case '+': ret = interpret_filter_in (c, pat, buf); break; + case '-': ret = interpret_filter_out (c, pat, buf); break; + case '?': ret = interpret_cond (c, pat, buf); break; + case '#': ret = interpret_count (c, pat, buf); break; + case '[': ret = interpret_enumerate (c, pat, buf); break; + default: ret = interpret_simple (c, pat, buf); break; + } + + return ret && + maybe_interpret_converts (c, buf, start) && + align_to_width (buf, start, width) && + expect_char (c, '}'); +} + +static FcBool +interpret_expr (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf, + FcChar8 term) +{ + while (*c->format && *c->format != term) + { + switch (*c->format) + { + case '\\': + c->format++; /* skip over '\\' */ + if (*c->format) + FcStrBufChar (buf, escaped_char (*c->format++)); + continue; + case '%': + if (!interpret_percent (c, pat, buf)) + return FcFalse; + continue; + } + FcStrBufChar (buf, *c->format++); + } + return FcTrue; +} + +static FcBool +FcPatternFormatToBuf (FcPattern *pat, + const FcChar8 *format, + FcStrBuf *buf) +{ + FcFormatContext c; + FcChar8 word_static[1024]; + FcBool ret; + + if (!FcFormatContextInit (&c, format, word_static, sizeof (word_static))) + return FcFalse; + + ret = interpret_expr (&c, pat, buf, '\0'); + + FcFormatContextDone (&c); + + return ret; +} + +FcChar8 * +FcPatternFormat (FcPattern *pat, + const FcChar8 *format) +{ + FcStrBuf buf; + FcChar8 buf_static[8192 - 1024]; + FcBool ret; + + FcStrBufInit (&buf, buf_static, sizeof (buf_static)); + + ret = FcPatternFormatToBuf (pat, format, &buf); + + if (ret) + return FcStrBufDone (&buf); + else + { + FcStrBufDestroy (&buf); + return NULL; + } +} + +#define __fcformat__ +#include "fcaliastail.h" +#undef __fcformat__ diff --git a/fontconfig/src/fcfreetype.c b/fontconfig/src/fcfreetype.c index 78a37b0a9..d37af2d0e 100644 --- a/fontconfig/src/fcfreetype.c +++ b/fontconfig/src/fcfreetype.c @@ -1,3005 +1,3005 @@ -/*
- * fontconfig/src/fcfreetype.c
- *
- * Copyright © 2001 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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.
- */
-
-/*
- Copyright © 2002-2003 by Juliusz Chroboczek
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-
-#include "fcint.h"
-#include "fcftint.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_TRUETYPE_TABLES_H
-#include FT_SFNT_NAMES_H
-#include FT_TRUETYPE_IDS_H
-#include FT_TYPE1_TABLES_H
-#if HAVE_FT_GET_X11_FONT_FORMAT
-#include FT_XFREE86_H
-#endif
-#if HAVE_FT_GET_BDF_PROPERTY
-#include FT_BDF_H
-#include FT_MODULE_H
-#endif
-
-#include "ftglue.h"
-
-#if HAVE_WARNING_CPP_DIRECTIVE
-#if !HAVE_FT_GET_BDF_PROPERTY
-#warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later"
-#endif
-
-#if !HAVE_FT_GET_PS_FONT_INFO
-#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
-#endif
-#endif
-
-/*
- * Keep Han languages separated by eliminating languages
- * that the codePageRange bits says aren't supported
- */
-
-static const struct {
- char bit;
- const FcChar8 lang[6];
-} FcCodePageRange[] = {
- { 17, "ja" },
- { 18, "zh-cn" },
- { 19, "ko" },
- { 20, "zh-tw" },
-};
-
-#define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
-
-FcBool
-FcFreeTypeIsExclusiveLang (const FcChar8 *lang)
-{
- int i;
-
- for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
- {
- if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual)
- return FcTrue;
- }
- return FcFalse;
-}
-
-typedef struct {
- const FT_UShort platform_id;
- const FT_UShort encoding_id;
- const char fromcode[12];
-} FcFtEncoding;
-
-#define TT_ENCODING_DONT_CARE 0xffff
-#define FC_ENCODING_MAC_ROMAN "MACINTOSH"
-
-static const FcFtEncoding fcFtEncoding[] = {
- { TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UTF-16BE" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, "UTF-16BE" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB2312" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" },
- { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UTF-16BE" },
- { TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" },
- { TT_PLATFORM_ISO, TT_ISO_ID_10646, "UTF-16BE" },
- { TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" },
-};
-
-#define NUM_FC_FT_ENCODING (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
-
-typedef struct {
- const FT_UShort platform_id;
- const FT_UShort language_id;
- const char lang[8];
-} FcFtLanguage;
-
-#define TT_LANGUAGE_DONT_CARE 0xffff
-
-static const FcFtLanguage fcFtLanguage[] = {
- { TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" },
-/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" },
-
-#if 0 /* these seem to be errors that have been dropped */
-
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC },
-
-#endif
-
- /* The following codes are new as of 2000-03-10 */
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" },
- { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
-
-#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
- /* this seems to be an error that have been dropped */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" },
-#endif
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" },
-
- /* new as of 2001-01-01 */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" },
-
- /* the following seems to be inconsistent;
- here is the current "official" way: */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" },
- /* and here is what is used by Passport SDK */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" },
- /* end of inconsistency */
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" },
- /* the following one is only encountered in Microsoft RTF specification */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" },
- /* the following one is not in the Passport list, looks like an omission */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" },
-
- /* new as of 2001-03-01 (from Office Xp) */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" },
-#if 0
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
-#endif
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" },
-
- /* New additions from Windows Xp/Passport SDK 2001-11-10. */
-
- /* don't ask what this one means... It is commented out currently. */
-#if 0
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 },
-#endif
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" },
- /* The following two IDs blatantly violate MS specs by using a */
- /* sublanguage >,. */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" },
-
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
-#if 0
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA },
-#endif
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" },
- /* language codes from, to, are (still) unknown. */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" },
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" },
-#if 0
- /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
- /* not written (but OTOH the peculiar writing system is worth */
- /* studying). */
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA },
-#endif
- { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
-};
-
-#define NUM_FC_FT_LANGUAGE (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
-
-typedef struct {
- FT_UShort language_id;
- char fromcode[12];
-} FcMacRomanFake;
-
-static const FcMacRomanFake fcMacRomanFake[] = {
- { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" },
- { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" },
-};
-
-static FcChar8 *
-FcFontCapabilities(FT_Face face);
-
-#define NUM_FC_MAC_ROMAN_FAKE (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
-
-#if USE_ICONV
-#include <iconv.h>
-#endif
-
-/*
- * A shift-JIS will have many high bits turned on
- */
-static FcBool
-FcLooksLikeSJIS (FcChar8 *string, int len)
-{
- int nhigh = 0, nlow = 0;
-
- while (len-- > 0)
- {
- if (*string++ & 0x80) nhigh++;
- else nlow++;
- }
- /*
- * Heuristic -- if more than 1/3 of the bytes have the high-bit set,
- * this is likely to be SJIS and not ROMAN
- */
- if (nhigh * 2 > nlow)
- return FcTrue;
- return FcFalse;
-}
-
-static FcChar8 *
-FcSfntNameTranscode (FT_SfntName *sname)
-{
- int i;
- const char *fromcode;
-#if USE_ICONV
- iconv_t cd;
-#endif
- FcChar8 *utf8;
-
- for (i = 0; i < NUM_FC_FT_ENCODING; i++)
- if (fcFtEncoding[i].platform_id == sname->platform_id &&
- (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
- fcFtEncoding[i].encoding_id == sname->encoding_id))
- break;
- if (i == NUM_FC_FT_ENCODING)
- return 0;
- fromcode = fcFtEncoding[i].fromcode;
-
- /*
- * Many names encoded for TT_PLATFORM_MACINTOSH are broken
- * in various ways. Kludge around them.
- */
- if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
- {
- if (sname->language_id == TT_MAC_LANGID_ENGLISH &&
- FcLooksLikeSJIS (sname->string, sname->string_len))
- {
- fromcode = "SJIS";
- }
- else if (sname->language_id >= 0x100)
- {
- /*
- * "real" Mac language IDs are all less than 150.
- * Names using one of the MS language IDs are assumed
- * to use an associated encoding (Yes, this is a kludge)
- */
- int f;
-
- fromcode = NULL;
- for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
- if (fcMacRomanFake[f].language_id == sname->language_id)
- {
- fromcode = fcMacRomanFake[f].fromcode;
- break;
- }
- if (!fromcode)
- return 0;
- }
- }
- if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
- {
- FcChar8 *src = sname->string;
- int src_len = sname->string_len;
- int len;
- int wchar;
- int ilen, olen;
- FcChar8 *u8;
- FcChar32 ucs4;
-
- /*
- * Convert Utf16 to Utf8
- */
-
- if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
- return 0;
-
- /*
- * Allocate plenty of space. Freed below
- */
- utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
- if (!utf8)
- return 0;
-
- u8 = utf8;
-
- while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
- {
- src_len -= ilen;
- src += ilen;
- olen = FcUcs4ToUtf8 (ucs4, u8);
- u8 += olen;
- }
- *u8 = '\0';
- goto done;
- }
- if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
- {
- FcChar8 *src = sname->string;
- int src_len = sname->string_len;
- int olen;
- FcChar8 *u8;
- FcChar32 ucs4;
-
- /*
- * Convert Latin1 to Utf8. Freed below
- */
- utf8 = malloc (src_len * 2 + 1);
- if (!utf8)
- return 0;
-
- u8 = utf8;
- while (src_len > 0)
- {
- ucs4 = *src++;
- src_len--;
- olen = FcUcs4ToUtf8 (ucs4, u8);
- u8 += olen;
- }
- *u8 = '\0';
- goto done;
- }
- if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
- {
- FcChar8 *u8;
- const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
- FcChar8 *src = (FcChar8 *) sname->string;
- int src_len = sname->string_len;
-
- /*
- * Convert AppleRoman to Utf8
- */
- if (!map)
- return 0;
-
- utf8 = malloc (sname->string_len * 3 + 1);
- if (!utf8)
- return 0;
-
- u8 = utf8;
- while (src_len > 0)
- {
- FcChar32 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
- int olen = FcUcs4ToUtf8 (ucs4, u8);
- src_len--;
- u8 += olen;
- }
- *u8 = '\0';
- goto done;
- }
-#if USE_ICONV
- cd = iconv_open ("UTF-8", fromcode);
- if (cd && cd != (iconv_t) (-1))
- {
- size_t in_bytes_left = sname->string_len;
- size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
- char *inbuf, *outbuf;
-
- utf8 = malloc (out_bytes_left + 1);
- if (!utf8)
- {
- iconv_close (cd);
- return 0;
- }
-
- outbuf = (char *) utf8;
- inbuf = (char *) sname->string;
-
- while (in_bytes_left)
- {
- size_t did = iconv (cd,
- &inbuf, &in_bytes_left,
- &outbuf, &out_bytes_left);
- if (did == (size_t) (-1))
- {
- iconv_close (cd);
- free (utf8);
- return 0;
- }
- }
- iconv_close (cd);
- *outbuf = '\0';
- goto done;
- }
-#endif
- return 0;
-done:
- if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
- {
- free (utf8);
- return 0;
- }
- return utf8;
-}
-
-static const FcChar8 *
-FcSfntNameLanguage (FT_SfntName *sname)
-{
- int i;
- FT_UShort platform_id = sname->platform_id;
- FT_UShort language_id = sname->language_id;
-
- /*
- * Many names encoded for TT_PLATFORM_MACINTOSH are broken
- * in various ways. Kludge around them.
- */
- if (platform_id == TT_PLATFORM_MACINTOSH &&
- sname->encoding_id == TT_MAC_ID_ROMAN &&
- FcLooksLikeSJIS (sname->string, sname->string_len))
- {
- language_id = TT_MAC_LANGID_JAPANESE;
- }
-
- for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
- if (fcFtLanguage[i].platform_id == platform_id &&
- (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
- fcFtLanguage[i].language_id == language_id))
- {
- if (fcFtLanguage[i].lang[0] == '\0')
- return NULL;
- else
- return (FcChar8 *) fcFtLanguage[i].lang;
- }
- return 0;
-}
-
-/* Order is significant. For example, some B&H fonts are hinted by
- URW++, and both strings appear in the notice. */
-
-static const char notice_foundry_data[] =
- "Bigelow\0b&h\0"
- "Adobe\0adobe\0"
- "Bitstream\0bitstream\0"
- "Monotype\0monotype\0"
- "Linotype\0linotype\0"
- "LINOTYPE-HELL\0linotype\0"
- "IBM\0ibm\0"
- "URW\0urw\0"
- "International Typeface Corporation\0itc\0"
- "Tiro Typeworks\0tiro\0"
- "XFree86\0xfree86\0"
- "Microsoft\0microsoft\0"
- "Omega\0omega\0"
- "Font21\0hwan\0"
- "HanYang System\0hanyang";
-
-struct _notice_foundry {
- /* these are the offsets into the
- * notice_foundry_data array.
- */
- unsigned char notice_offset;
- unsigned char foundry_offset;
-};
-
-static const struct _notice_foundry FcNoticeFoundries[] = {
- { 0, 8 },
- { 12, 18 },
- { 24, 34 },
- { 44, 53 },
- { 62, 71 },
- { 80, 94 },
- { 103, 107 },
- { 111, 115 },
- { 119, 154 },
- { 158, 173 },
- { 178, 186 },
- { 194, 204 },
- { 214, 220 },
- { 226, 233 },
- { 238, 253 }
-};
-
-#define NUM_NOTICE_FOUNDRIES (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
-
-static const FcChar8 *
-FcNoticeFoundry(const FT_String *notice)
-{
- int i;
-
- if (notice)
- for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
- {
- const struct _notice_foundry *nf = &FcNoticeFoundries[i];
- const char *n = notice_foundry_data + nf->notice_offset;
- const char *f = notice_foundry_data + nf->foundry_offset;
-
- if (strstr ((const char *) notice, n))
- return (const FcChar8 *) f;
- }
- return 0;
-}
-
-static FcBool
-FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
-{
- /* vendor is not necessarily NUL-terminated. */
- int i, len;
-
- len = strlen((char *) vendor_string);
- if (memcmp(vendor, vendor_string, len) != 0)
- return FcFalse;
- for (i = len; i < 4; i++)
- if (vendor[i] != ' ' && vendor[i] != '\0')
- return FcFalse;
- return FcTrue;
-}
-
-/* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
-
-/* It should not contain useless entries (such as UNKN) nor duplicate
- entries for padding both with spaces and NULs. */
-
-static const struct {
- const FT_Char vendor[5];
- const FcChar8 foundry[13];
-} FcVendorFoundries[] = {
- { "ADBE", "adobe"},
- { "AGFA", "agfa"},
- { "ALTS", "altsys"},
- { "APPL", "apple"},
- { "ARPH", "arphic"},
- { "ATEC", "alltype"},
- { "B&H", "b&h"},
- { "BITS", "bitstream"},
- { "CANO", "cannon"},
- { "DYNA", "dynalab"},
- { "EPSN", "epson"},
- { "FJ", "fujitsu"},
- { "IBM", "ibm"},
- { "ITC", "itc"},
- { "IMPR", "impress"},
- { "LARA", "larabiefonts"},
- { "LEAF", "interleaf"},
- { "LETR", "letraset"},
- { "LINO", "linotype"},
- { "MACR", "macromedia"},
- { "MONO", "monotype"},
- { "MS", "microsoft"},
- { "MT", "monotype"},
- { "NEC", "nec"},
- { "PARA", "paratype"},
- { "QMSI", "qms"},
- { "RICO", "ricoh"},
- { "URW", "urw"},
- { "Y&Y", "y&y"}
-};
-
-#define NUM_VENDOR_FOUNDRIES (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
-
-static const FcChar8 *
-FcVendorFoundry(const FT_Char vendor[4])
-{
- int i;
-
- if (vendor)
- for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
- if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
- return FcVendorFoundries[i].foundry;
- return 0;
-}
-
-typedef struct _FcStringConst {
- const FcChar8 *name;
- int value;
-} FcStringConst;
-
-static int
-FcStringIsConst (const FcChar8 *string,
- const FcStringConst *c,
- int nc)
-{
- int i;
-
- for (i = 0; i < nc; i++)
- if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
- return c[i].value;
- return -1;
-}
-
-static int
-FcStringContainsConst (const FcChar8 *string,
- const FcStringConst *c,
- int nc)
-{
- int i;
-
- for (i = 0; i < nc; i++)
- {
- if (c[i].name[0] == '<')
- {
- if (FcStrContainsWord (string, c[i].name + 1))
- return c[i].value;
- }
- else
- {
- if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
- return c[i].value;
- }
- }
- return -1;
-}
-
-typedef FcChar8 *FC8;
-
-static const FcStringConst weightConsts[] = {
- { (FC8) "thin", FC_WEIGHT_THIN },
- { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT },
- { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT },
- { (FC8) "light", FC_WEIGHT_LIGHT },
- { (FC8) "book", FC_WEIGHT_BOOK },
- { (FC8) "regular", FC_WEIGHT_REGULAR },
- { (FC8) "normal", FC_WEIGHT_NORMAL },
- { (FC8) "medium", FC_WEIGHT_MEDIUM },
- { (FC8) "demibold", FC_WEIGHT_DEMIBOLD },
- { (FC8) "demi", FC_WEIGHT_DEMIBOLD },
- { (FC8) "semibold", FC_WEIGHT_SEMIBOLD },
- { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD },
- { (FC8) "superbold", FC_WEIGHT_EXTRABOLD },
- { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD },
- { (FC8) "bold", FC_WEIGHT_BOLD },
- { (FC8) "ultrablack", FC_WEIGHT_ULTRABLACK },
- { (FC8) "superblack", FC_WEIGHT_EXTRABLACK },
- { (FC8) "extrablack", FC_WEIGHT_EXTRABLACK },
- { (FC8) "<ultra", FC_WEIGHT_ULTRABOLD }, /* only if a word */
- { (FC8) "black", FC_WEIGHT_BLACK },
- { (FC8) "heavy", FC_WEIGHT_HEAVY },
-};
-
-#define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
-
-#define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
-#define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
-
-static const FcStringConst widthConsts[] = {
- { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED },
- { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED },
- { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED },
- { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
- { (FC8) "normal", FC_WIDTH_NORMAL },
- { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED },
- { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
- { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
- { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
- { (FC8) "extended", FC_WIDTH_EXPANDED },
-};
-
-#define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
-
-#define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
-#define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
-
-static const FcStringConst slantConsts[] = {
- { (FC8) "italic", FC_SLANT_ITALIC },
- { (FC8) "kursiv", FC_SLANT_ITALIC },
- { (FC8) "oblique", FC_SLANT_OBLIQUE },
-};
-
-#define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
-
-#define FcIsSlant(s) FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
-#define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
-
-static const FcStringConst decorativeConsts[] = {
- { (FC8) "shadow", FcTrue },
- { (FC8) "caps", FcTrue },
- { (FC8) "antiqua", FcTrue },
- { (FC8) "romansc", FcTrue },
- { (FC8) "embosed", FcTrue },
- { (FC8) "dunhill", FcTrue },
-};
-
-#define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
-
-#define FcIsDecorative(s) FcStringIsConst(s,decorativeConsts,NUM_DECORATIVE_CONSTS)
-#define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
-
-static double
-FcGetPixelSize (FT_Face face, int i)
-{
-#if HAVE_FT_GET_BDF_PROPERTY
- if (face->num_fixed_sizes == 1)
- {
- BDF_PropertyRec prop;
- int rc;
-
- rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
- if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
- return (double) prop.u.integer;
- }
-#endif
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
- return (double) face->available_sizes[i].y_ppem / 64.0;
-#else
- return (double) face->available_sizes[i].height;
-#endif
-}
-
-static FcBool
-FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
-{
- int e;
- FcChar8 *old;
- for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
- if (!FcStrCmpIgnoreBlanksAndCase (old, string))
- {
- return FcTrue;
- }
- return FcFalse;
-}
-
-static const FT_UShort platform_order[] = {
- TT_PLATFORM_MICROSOFT,
- TT_PLATFORM_APPLE_UNICODE,
- TT_PLATFORM_MACINTOSH,
-};
-#define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
-
-static const FT_UShort nameid_order[] = {
-#ifdef TT_NAME_ID_WWS_FAMILY
- TT_NAME_ID_WWS_FAMILY,
-#endif
- TT_NAME_ID_PREFERRED_FAMILY,
- TT_NAME_ID_FONT_FAMILY,
- TT_NAME_ID_MAC_FULL_NAME,
- TT_NAME_ID_FULL_NAME,
-#ifdef TT_NAME_ID_WWS_SUBFAMILY
- TT_NAME_ID_WWS_SUBFAMILY,
-#endif
- TT_NAME_ID_PREFERRED_SUBFAMILY,
- TT_NAME_ID_FONT_SUBFAMILY,
- TT_NAME_ID_TRADEMARK,
- TT_NAME_ID_MANUFACTURER,
-};
-
-#define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0]))
-FcPattern *
-FcFreeTypeQueryFace (const FT_Face face,
- const FcChar8 *file,
- int id,
- FcBlanks *blanks)
-{
- FcPattern *pat;
- int slant = -1;
- int weight = -1;
- int width = -1;
- FcBool decorative = FcFalse;
- int i;
- FcCharSet *cs;
- FcLangSet *ls;
-#if 0
- FcChar8 *family = 0;
-#endif
- FcChar8 *complex_;
- const FcChar8 *foundry = 0;
- int spacing;
- TT_OS2 *os2;
-#if HAVE_FT_GET_PS_FONT_INFO
- PS_FontInfoRec psfontinfo;
-#endif
-#if HAVE_FT_GET_BDF_PROPERTY
- BDF_PropertyRec prop;
-#endif
- TT_Header *head;
- const FcChar8 *exclusiveLang = 0;
- FT_SfntName sname;
- FT_UInt snamei, snamec;
-
- int nfamily = 0;
- int nfamily_lang = 0;
- int nstyle = 0;
- int nstyle_lang = 0;
- int nfullname = 0;
- int nfullname_lang = 0;
- int p, platform;
- int n, nameid;
-
- FcChar8 *style = 0;
- int st;
-
- 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;
-
-
- /*
- * Get the OS/2 table
- */
- os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
-
- /*
- * Look first in the OS/2 table for the foundry, if
- * not found here, the various notices will be searched for
- * that information, either from the sfnt name tables or
- * the Postscript FontInfo dictionary. Finally, the
- * BDF properties will queried.
- */
-
- if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
- foundry = FcVendorFoundry(os2->achVendID);
-
- if (FcDebug () & FC_DBG_SCANV)
- printf ("\n");
- /*
- * Grub through the name table looking for family
- * and style names. FreeType makes quite a hash
- * of them
- */
- snamec = FT_Get_Sfnt_Name_Count (face);
- for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
- {
- if (p < NUM_PLATFORM_ORDER)
- platform = platform_order[p];
- else
- platform = 0xffff;
-
- /*
- * Order nameids so preferred names appear first
- * in the resulting list
- */
- for (n = 0; n < NUM_NAMEID_ORDER; n++)
- {
- nameid = nameid_order[n];
-
- for (snamei = 0; snamei < snamec; snamei++)
- {
- FcChar8 *utf8;
- const FcChar8 *lang;
- const char *elt = 0, *eltlang = 0;
- int *np = 0, *nlangp = 0;
-
- if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
- continue;
- if (sname.name_id != nameid)
- continue;
-
- /*
- * Sort platforms in preference order, accepting
- * all other platforms last
- */
- if (p < NUM_PLATFORM_ORDER)
- {
- if (sname.platform_id != platform)
- continue;
- }
- else
- {
- int sp;
-
- for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
- if (sname.platform_id == platform_order[sp])
- break;
- if (sp != NUM_PLATFORM_ORDER)
- continue;
- }
- utf8 = FcSfntNameTranscode (&sname);
- lang = FcSfntNameLanguage (&sname);
-
- if (!utf8)
- continue;
-
- switch (sname.name_id) {
-#ifdef TT_NAME_ID_WWS_FAMILY
- case TT_NAME_ID_WWS_FAMILY:
-#endif
- case TT_NAME_ID_PREFERRED_FAMILY:
- case TT_NAME_ID_FONT_FAMILY:
-#if 0
- case TT_NAME_ID_PS_NAME:
- case TT_NAME_ID_UNIQUE_ID:
-#endif
- if (FcDebug () & FC_DBG_SCANV)
- printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
- sname.name_id, sname.platform_id,
- sname.encoding_id, sname.language_id,
- utf8);
-
- elt = FC_FAMILY;
- eltlang = FC_FAMILYLANG;
- np = &nfamily;
- nlangp = &nfamily_lang;
- break;
- case TT_NAME_ID_MAC_FULL_NAME:
- case TT_NAME_ID_FULL_NAME:
- if (FcDebug () & FC_DBG_SCANV)
- printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
- sname.name_id, sname.platform_id,
- sname.encoding_id, sname.language_id,
- utf8);
-
- elt = FC_FULLNAME;
- eltlang = FC_FULLNAMELANG;
- np = &nfullname;
- nlangp = &nfullname_lang;
- break;
-#ifdef TT_NAME_ID_WWS_SUBFAMILY
- case TT_NAME_ID_WWS_SUBFAMILY:
-#endif
- case TT_NAME_ID_PREFERRED_SUBFAMILY:
- case TT_NAME_ID_FONT_SUBFAMILY:
- if (FcDebug () & FC_DBG_SCANV)
- printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
- sname.name_id, sname.platform_id,
- sname.encoding_id, sname.language_id,
- utf8);
-
- elt = FC_STYLE;
- eltlang = FC_STYLELANG;
- np = &nstyle;
- nlangp = &nstyle_lang;
- break;
- case TT_NAME_ID_TRADEMARK:
- case TT_NAME_ID_MANUFACTURER:
- /* If the foundry wasn't found in the OS/2 table, look here */
- if(!foundry)
- foundry = FcNoticeFoundry((FT_String *) utf8);
- break;
- }
- if (elt)
- {
- if (FcStringInPatternElement (pat, elt, utf8))
- {
- free (utf8);
- continue;
- }
-
- /* add new element */
- if (!FcPatternAddString (pat, elt, utf8))
- {
- free (utf8);
- goto bail1;
- }
- free (utf8);
- if (lang)
- {
- /* pad lang list with 'xx' to line up with elt */
- while (*nlangp < *np)
- {
- if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
- goto bail1;
- ++*nlangp;
- }
- if (!FcPatternAddString (pat, eltlang, lang))
- goto bail1;
- ++*nlangp;
- }
- ++*np;
- }
- else
- free (utf8);
- }
- }
- }
-
- if (!nfamily && face->family_name &&
- FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
- {
- if (FcDebug () & FC_DBG_SCANV)
- printf ("using FreeType family \"%s\"\n", face->family_name);
- if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
- goto bail1;
- ++nfamily;
- }
-
- if (!nstyle && face->style_name &&
- FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
- {
- if (FcDebug () & FC_DBG_SCANV)
- printf ("using FreeType style \"%s\"\n", face->style_name);
- if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
- goto bail1;
- ++nstyle;
- }
-
- if (!nfamily)
- {
- FcChar8 *start, *end;
- FcChar8 *family;
-
- start = (FcChar8 *) strrchr ((char *) file, '/');
- if (start)
- start++;
- else
- start = (FcChar8 *) file;
- end = (FcChar8 *) strrchr ((char *) start, '.');
- if (!end)
- end = start + strlen ((char *) start);
- /* freed below */
- family = malloc (end - start + 1);
- strncpy ((char *) family, (char *) start, end - start);
- family[end - start] = '\0';
- if (FcDebug () & FC_DBG_SCANV)
- printf ("using filename for family %s\n", family);
- if (!FcPatternAddString (pat, FC_FAMILY, family))
- {
- free (family);
- goto bail1;
- }
- free (family);
- ++nfamily;
- }
-
- if (!FcPatternAddString (pat, FC_FILE, file))
- goto bail1;
-
- if (!FcPatternAddInteger (pat, FC_INDEX, id))
- goto bail1;
-
-#if 0
- /*
- * don't even try this -- CJK 'monospace' fonts are really
- * dual width, and most other fonts don't bother to set
- * the attribute. Sigh.
- */
- if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
- if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
- goto bail1;
-#endif
-
- /*
- * Find the font revision (if available)
- */
- head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
- if (head)
- {
- if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
- goto bail1;
- }
- else
- {
- if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
- goto bail1;
- }
-
- 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 the font advertises support for multiple
- * "exclusive" languages, then include support
- * for any language found to have coverage
- */
- if (exclusiveLang)
- {
- exclusiveLang = 0;
- break;
- }
- exclusiveLang = FcCodePageRange[i].lang;
- }
- }
- }
-
- if (os2 && os2->version != 0xffff)
- {
- if (os2->usWeightClass == 0)
- ;
- else if (os2->usWeightClass < 150)
- weight = FC_WEIGHT_THIN;
- else if (os2->usWeightClass < 250)
- weight = FC_WEIGHT_EXTRALIGHT;
- else if (os2->usWeightClass < 350)
- weight = FC_WEIGHT_LIGHT;
- else if (os2->usWeightClass < 450)
- weight = FC_WEIGHT_REGULAR;
- else if (os2->usWeightClass < 550)
- weight = FC_WEIGHT_MEDIUM;
- else if (os2->usWeightClass < 650)
- weight = FC_WEIGHT_SEMIBOLD;
- else if (os2->usWeightClass < 750)
- weight = FC_WEIGHT_BOLD;
- else if (os2->usWeightClass < 850)
- weight = FC_WEIGHT_EXTRABOLD;
- else if (os2->usWeightClass < 925)
- weight = FC_WEIGHT_BLACK;
- else if (os2->usWeightClass < 1000)
- weight = FC_WEIGHT_EXTRABLACK;
- if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
- printf ("\tos2 weight class %d maps to weight %d\n",
- os2->usWeightClass, weight);
-
- switch (os2->usWidthClass) {
- case 1: width = FC_WIDTH_ULTRACONDENSED; break;
- case 2: width = FC_WIDTH_EXTRACONDENSED; break;
- case 3: width = FC_WIDTH_CONDENSED; break;
- case 4: width = FC_WIDTH_SEMICONDENSED; break;
- case 5: width = FC_WIDTH_NORMAL; break;
- case 6: width = FC_WIDTH_SEMIEXPANDED; break;
- case 7: width = FC_WIDTH_EXPANDED; break;
- case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
- case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
- }
- if ((FcDebug() & FC_DBG_SCANV) && width != -1)
- printf ("\tos2 width class %d maps to width %d\n",
- os2->usWidthClass, width);
- }
- if (os2 && (complex_ = FcFontCapabilities(face)))
- {
- if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
- {
- free (complex_);
- goto bail1;
- }
- free (complex_);
- }
-
- /*
- * Type 1: Check for FontInfo dictionary information
- * Code from g2@magestudios.net (Gerard Escalante)
- */
-
-#if HAVE_FT_GET_PS_FONT_INFO
- if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
- {
- if (weight == -1 && psfontinfo.weight)
- {
- weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
- if (FcDebug() & FC_DBG_SCANV)
- printf ("\tType1 weight %s maps to %d\n",
- psfontinfo.weight, weight);
- }
-
-#if 0
- /*
- * Don't bother with italic_angle; FreeType already extracts that
- * information for us and sticks it into style_flags
- */
- if (psfontinfo.italic_angle)
- slant = FC_SLANT_ITALIC;
- else
- slant = FC_SLANT_ROMAN;
-#endif
-
- if(!foundry)
- foundry = FcNoticeFoundry(psfontinfo.notice);
- }
-#endif /* HAVE_FT_GET_PS_FONT_INFO */
-
-#if HAVE_FT_GET_BDF_PROPERTY
- /*
- * Finally, look for a FOUNDRY BDF property if no other
- * mechanism has managed to locate a foundry
- */
-
- if (!foundry)
- {
- int rc;
- rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
- if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
- foundry = (FcChar8 *) prop.u.atom;
- }
-
- if (width == -1)
- {
- if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
- (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
- prop.type == BDF_PROPERTY_TYPE_CARDINAL))
- {
- FT_Int32 value;
-
- if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
- value = prop.u.integer;
- else
- value = (FT_Int32) prop.u.cardinal;
- switch ((value + 5) / 10) {
- case 1: width = FC_WIDTH_ULTRACONDENSED; break;
- case 2: width = FC_WIDTH_EXTRACONDENSED; break;
- case 3: width = FC_WIDTH_CONDENSED; break;
- case 4: width = FC_WIDTH_SEMICONDENSED; break;
- case 5: width = FC_WIDTH_NORMAL; break;
- case 6: width = FC_WIDTH_SEMIEXPANDED; break;
- case 7: width = FC_WIDTH_EXPANDED; break;
- case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
- case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
- }
- }
- if (width == -1 &&
- FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
- prop.type == BDF_PROPERTY_TYPE_ATOM)
- {
- width = FcIsWidth ((FcChar8 *) prop.u.atom);
- if (FcDebug () & FC_DBG_SCANV)
- printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
- }
- }
-#endif
-
- /*
- * Look for weight, width and slant names in the style value
- */
- for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
- {
- if (weight == -1)
- {
- weight = FcContainsWeight (style);
- if (FcDebug() & FC_DBG_SCANV)
- printf ("\tStyle %s maps to weight %d\n", style, weight);
- }
- if (width == -1)
- {
- width = FcContainsWidth (style);
- if (FcDebug() & FC_DBG_SCANV)
- printf ("\tStyle %s maps to width %d\n", style, width);
- }
- if (slant == -1)
- {
- slant = FcContainsSlant (style);
- if (FcDebug() & FC_DBG_SCANV)
- printf ("\tStyle %s maps to slant %d\n", style, slant);
- }
- if (decorative == FcFalse)
- {
- decorative = FcContainsDecorative (style) > 0;
- if (FcDebug() & FC_DBG_SCANV)
- printf ("\tStyle %s maps to decorative %d\n", style, decorative);
- }
- }
- /*
- * Pull default values from the FreeType flags if more
- * specific values not found above
- */
- if (slant == -1)
- {
- slant = FC_SLANT_ROMAN;
- if (face->style_flags & FT_STYLE_FLAG_ITALIC)
- slant = FC_SLANT_ITALIC;
- }
-
- if (weight == -1)
- {
- weight = FC_WEIGHT_MEDIUM;
- if (face->style_flags & FT_STYLE_FLAG_BOLD)
- weight = FC_WEIGHT_BOLD;
- }
-
- if (width == -1)
- width = FC_WIDTH_NORMAL;
-
- if (foundry == 0)
- foundry = (FcChar8 *) "unknown";
-
- if (!FcPatternAddInteger (pat, FC_SLANT, slant))
- goto bail1;
-
- if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
- goto bail1;
-
- if (!FcPatternAddInteger (pat, FC_WIDTH, width))
- goto bail1;
-
- if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
- goto bail1;
-
- if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
- goto bail1;
-
- /*
- * Compute the unicode coverage for the font
- */
- cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
- if (!cs)
- goto bail1;
-
-#if HAVE_FT_GET_BDF_PROPERTY
- /* For PCF fonts, override the computed spacing with the one from
- the property */
- if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
- prop.type == BDF_PROPERTY_TYPE_ATOM) {
- if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
- spacing = FC_CHARCELL;
- else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
- spacing = FC_MONO;
- else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
- spacing = FC_PROPORTIONAL;
- }
-#endif
-
- /*
- * Skip over PCF fonts that have no encoded characters; they're
- * usually just Unicode fonts transcoded to some legacy encoding
- * FT forces us to approximate whether a font is a PCF font
- * or not by whether it has any BDF properties. Try PIXEL_SIZE;
- * I don't know how to get a list of BDF properties on the font. -PL
- */
- if (FcCharSetCount (cs) == 0)
- {
-#if HAVE_FT_GET_BDF_PROPERTY
- if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
- goto bail2;
-#endif
- }
-
- if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
- goto bail2;
-
- ls = FcFreeTypeLangSet (cs, exclusiveLang);
- if (!ls)
- goto bail2;
-
- if (!FcPatternAddLangSet (pat, FC_LANG, ls))
- {
- FcLangSetDestroy (ls);
- goto bail2;
- }
-
- FcLangSetDestroy (ls);
-
- if (spacing != FC_PROPORTIONAL)
- if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
- goto bail2;
-
- if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
- {
- for (i = 0; i < face->num_fixed_sizes; i++)
- if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
- FcGetPixelSize (face, i)))
- goto bail2;
- if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
- goto bail2;
- }
-#if HAVE_FT_GET_X11_FONT_FORMAT
- /*
- * Use the (not well documented or supported) X-specific function
- * from FreeType to figure out the font format
- */
- {
- const char *font_format = FT_Get_X11_Font_Format (face);
- if (font_format)
- FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
- }
-#endif
-
- /*
- * Drop our reference to the charset
- */
- FcCharSetDestroy (cs);
-
- return pat;
-
-bail2:
- FcCharSetDestroy (cs);
-bail1:
- FcPatternDestroy (pat);
-bail0:
- return NULL;
-}
-
-FcPattern *
-FcFreeTypeQuery(const FcChar8 *file,
- int id,
- FcBlanks *blanks,
- int *count)
-{
- FT_Face face;
- FT_Library ftLibrary;
- FcPattern *pat = NULL;
-
- if (FT_Init_FreeType (&ftLibrary))
- return NULL;
-
- if (FT_New_Face (ftLibrary, (char *) file, id, &face))
- goto bail;
-
- *count = face->num_faces;
-
- pat = FcFreeTypeQueryFace (face, file, id, blanks);
-
- FT_Done_Face (face);
-bail:
- FT_Done_FreeType (ftLibrary);
- return pat;
-}
-
-/*
- * For our purposes, this approximation is sufficient
- */
-#if !HAVE_FT_GET_NEXT_CHAR
-#define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
- (*(gi) = 0), 0 : \
- (*(gi) = 1), (ucs4) + 1)
-#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
-#endif
-
-typedef struct _FcCharEnt {
- FcChar16 bmp;
- unsigned char encode;
-} FcCharEnt;
-
-struct _FcCharMap {
- const FcCharEnt *ent;
- int nent;
-};
-
-typedef struct _FcFontDecode {
- FT_Encoding encoding;
- const FcCharMap *map;
- FcChar32 max;
-} FcFontDecode;
-
-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]),
-};
-
-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 (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
-
-static const FcChar32 prefer_unicode[] = {
- 0x20ac, /* EURO SIGN */
-};
-
-#define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
-
-FcChar32
-FcFreeTypeUcs4ToPrivate (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 (low <= high)
- {
- mid = (high + low) >> 1;
- bmp = map->ent[mid].bmp;
- if (ucs4 == bmp)
- return (FT_ULong) map->ent[mid].encode;
- if (ucs4 < bmp)
- high = mid - 1;
- else
- low = mid + 1;
- }
- return ~0;
-}
-
-FcChar32
-FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
-{
- int i;
-
- for (i = 0; i < map->nent; i++)
- if (map->ent[i].encode == private)
- return (FcChar32) map->ent[i].bmp;
- return ~0;
-}
-
-const FcCharMap *
-FcFreeTypeGetPrivateMap (FT_Encoding encoding)
-{
- int i;
-
- for (i = 0; i < NUM_DECODE; i++)
- if (fcFontDecoders[i].encoding == encoding)
- return fcFontDecoders[i].map;
- return 0;
-}
-
-#include "../fc-glyphname/fcglyphname.h"
-
-static FcChar32
-FcHashGlyphName (const FcChar8 *name)
-{
- FcChar32 h = 0;
- FcChar8 c;
-
- while ((c = *name++))
- {
- h = ((h << 1) | (h >> 31)) ^ c;
- }
- return h;
-}
-
-#if HAVE_FT_HAS_PS_GLYPH_NAMES
-/*
- * Use Type1 glyph names for fonts which have reliable names
- * and which export an Adobe Custom mapping
- */
-static FcBool
-FcFreeTypeUseNames (FT_Face face)
-{
- FT_Int map;
-
- if (!FT_Has_PS_Glyph_Names (face))
- return FcFalse;
- for (map = 0; map < face->num_charmaps; map++)
- if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
- return FcTrue;
- return FcFalse;
-}
-
-static const FcChar8 *
-FcUcs4ToGlyphName (FcChar32 ucs4)
-{
- int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
- int r = 0;
- FcGlyphId gn;
-
- while ((gn = _fc_ucs_to_name[i]) != -1)
- {
- if (_fc_glyph_names[gn].ucs == ucs4)
- return _fc_glyph_names[gn].name;
- if (!r)
- {
- r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
- if (!r)
- r = 1;
- }
- i += r;
- if (i >= FC_GLYPHNAME_HASH)
- i -= FC_GLYPHNAME_HASH;
- }
- return 0;
-}
-
-static FcChar32
-FcGlyphNameToUcs4 (FcChar8 *name)
-{
- FcChar32 h = FcHashGlyphName (name);
- int i = (int) (h % FC_GLYPHNAME_HASH);
- int r = 0;
- FcGlyphId gn;
-
- while ((gn = _fc_name_to_ucs[i]) != -1)
- {
- if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name))
- return _fc_glyph_names[gn].ucs;
- if (!r)
- {
- r = (int) (h % FC_GLYPHNAME_REHASH);
- if (!r)
- r = 1;
- }
- i += r;
- if (i >= FC_GLYPHNAME_HASH)
- i -= FC_GLYPHNAME_HASH;
- }
- return 0xffff;
-}
-
-/*
- * Work around a bug in some FreeType versions which fail
- * to correctly bounds check glyph name buffers and overwrite
- * the stack. As Postscript names have a limit of 127 characters,
- * this should be sufficient.
- */
-
-#if FC_GLYPHNAME_MAXLEN < 127
-# define FC_GLYPHNAME_BUFLEN 127
-#else
-# define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
-#endif
-
-/*
- * Search through a font for a glyph by name. This is
- * currently a linear search as there doesn't appear to be
- * any defined order within the font
- */
-static FT_UInt
-FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
-{
- FT_UInt gindex;
- FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
-
- for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
- {
- if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
- if (!strcmp ((char *) name, (char *) name_buf))
- return gindex;
- }
- return 0;
-}
-#endif
-
-/*
- * 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;
- FcChar32 charcode;
- int p;
-
- initial = 0;
-
- if (!face)
- return 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;
- }
- for (p = 0; p < NUM_PREFER_UNICODE; p++)
- if (ucs4 == prefer_unicode[p])
- {
- initial = 0;
- break;
- }
- /*
- * 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 = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
- if (charcode == ~0U)
- continue;
- }
- else
- charcode = ucs4;
- glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
- if (glyphindex)
- return glyphindex;
- }
-#if HAVE_FT_HAS_PS_GLYPH_NAMES
- /*
- * Check postscript name table if present
- */
- if (FcFreeTypeUseNames (face))
- {
- const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
- if (name)
- {
- glyphindex = FcFreeTypeGlyphNameIndex (face, name);
- if (glyphindex)
- return glyphindex;
- }
- }
-#endif
- return 0;
-}
-
-static FcBool
-FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
- FT_UInt glyph, FcBlanks *blanks,
- FT_Pos *advance,
- FcBool using_strike)
-{
- FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
- FT_GlyphSlot slot;
-
- if (using_strike)
- load_flags &= ~FT_LOAD_NO_SCALE;
-
- /*
- * 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;
-
- *advance = slot->metrics.horiAdvance;
-
- 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:
- break;
- }
- return FcFalse;
-}
-
-#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
-
-static FcCharSet *
-FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index)
-{
- FcChar32 page, off, ucs4;
-#ifdef CHECK
- FcChar32 font_max = 0;
-#endif
- FcCharSet *fcs;
- FcCharLeaf *leaf;
- const FcCharMap *map;
- int o;
- int i;
- FT_UInt glyph;
- FT_Pos advance, advance_one = 0, advance_two = 0;
- FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
- FcBool using_strike = FcFalse;
-
- fcs = FcCharSetCreate ();
- if (!fcs)
- goto bail0;
-
-#if HAVE_FT_SELECT_SIZE
- if (strike_index >= 0) {
- if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
- goto bail1;
- using_strike = FcTrue;
- }
-#endif
-
-#ifdef CHECK
- printf ("Family %s style %s\n", face->family_name, face->style_name);
-#endif
- 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, &advance, using_strike))
- {
- /*
- * ignore glyphs with zero advance. They’re
- * combining characters, and while their behaviour
- * isn’t well defined for monospaced applications in
- * Unicode, there are many fonts which include
- * zero-width combining characters in otherwise
- * monospaced fonts.
- */
- if (advance)
- {
- if (!has_advance)
- {
- has_advance = FcTrue;
- advance_one = advance;
- }
- else if (!APPROXIMATELY_EQUAL (advance, advance_one))
- {
- if (fixed_advance)
- {
- dual_advance = FcTrue;
- fixed_advance = FcFalse;
- advance_two = advance;
- }
- else if (!APPROXIMATELY_EQUAL (advance, advance_two))
- dual_advance = FcFalse;
- }
- }
-
- 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
- {
- page = ~0;
- leaf = NULL;
- ucs4 = FT_Get_First_Char (face, &glyph);
- while (glyph != 0)
- {
- if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
- {
- if (advance)
- {
- if (!has_advance)
- {
- has_advance = FcTrue;
- advance_one = advance;
- }
- else if (!APPROXIMATELY_EQUAL (advance, advance_one))
- {
- if (fixed_advance)
- {
- dual_advance = FcTrue;
- fixed_advance = FcFalse;
- advance_two = advance;
- }
- else if (!APPROXIMATELY_EQUAL (advance, advance_two))
- dual_advance = FcFalse;
- }
- }
-
- if ((ucs4 >> 8) != page)
- {
- page = (ucs4 >> 8);
- 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 = FT_Get_Next_Char (face, ucs4, &glyph);
- }
-#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
- }
- }
-#if HAVE_FT_HAS_PS_GLYPH_NAMES
- /*
- * Add mapping from PS glyph names if available
- */
- if (FcFreeTypeUseNames (face))
- {
- FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
-
- for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
- {
- if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
- {
- ucs4 = FcGlyphNameToUcs4 (name_buf);
- if (ucs4 != 0xffff &&
- FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
- {
- if (advance)
- {
- if (!has_advance)
- {
- has_advance = FcTrue;
- advance_one = advance;
- }
- else if (!APPROXIMATELY_EQUAL (advance, advance_one))
- {
- if (fixed_advance)
- {
- dual_advance = FcTrue;
- fixed_advance = FcFalse;
- advance_two = advance;
- }
- else if (!APPROXIMATELY_EQUAL (advance, advance_two))
- dual_advance = FcFalse;
- }
- }
- 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
- }
- }
- }
- }
-#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 = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
- FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
-
- if (has_char && !has_bit)
- {
- if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
- printf ("Bitmap missing broken char 0x%x\n", ucs4);
- else
- printf ("Bitmap missing char 0x%x\n", ucs4);
- }
- else if (!has_char && has_bit)
- printf ("Bitmap extra char 0x%x\n", ucs4);
- }
-#endif
- if (fixed_advance)
- *spacing = FC_MONO;
- else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
- *spacing = FC_DUAL;
- else
- *spacing = FC_PROPORTIONAL;
- return fcs;
-bail1:
- FcCharSetDestroy (fcs);
-bail0:
- return 0;
-}
-
-FcCharSet *
-FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
-{
- FcCharSet *cs;
-
- cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1);
- /*
- * Check for bitmap-only ttf fonts that are missing the glyf table.
- * In that case, pick a size and look for glyphs in that size instead
- */
- if (FcCharSetCount (cs) == 0)
- {
- /* Check for non-scalable TT fonts */
- if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
- face->num_fixed_sizes > 0 &&
- FT_Get_Sfnt_Table (face, ft_sfnt_head))
- {
- FT_Int strike_index = 0;
- int i;
-
- /* Select the face closest to 16 pixels tall */
- for (i = 1; i < face->num_fixed_sizes; i++) {
- if (abs (face->available_sizes[i].height - 16) <
- abs (face->available_sizes[strike_index].height - 16))
- strike_index = i;
- }
- FcCharSetDestroy (cs);
- cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index);
- }
- }
- return cs;
-}
-
-FcCharSet *
-FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
-{
- int spacing;
-
- return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
-}
-
-
-#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
-#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
-#define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
-
-#define OTLAYOUT_HEAD "otlayout:"
-#define OTLAYOUT_HEAD_LEN 9
-#define OTLAYOUT_ID_LEN 4
-/* space + head + id */
-#define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
-
-/*
- * This is a bit generous; the registry has only lower case and space
- * except for 'DFLT'.
- */
-#define FcIsSpace(x) (040 == (x))
-#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
-
-static void
-addtag(FcChar8 *complex_, FT_ULong tag)
-{
- FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
-
- tagstring[0] = (FcChar8)(tag >> 24),
- tagstring[1] = (FcChar8)(tag >> 16),
- tagstring[2] = (FcChar8)(tag >> 8),
- tagstring[3] = (FcChar8)(tag);
- tagstring[4] = '\0';
-
- /* skip tags which aren't alphabetic, under the assumption that
- * they're probably broken
- */
- if (!FcIsValidScript(tagstring[0]) ||
- !FcIsValidScript(tagstring[1]) ||
- !FcIsValidScript(tagstring[2]) ||
- !FcIsValidScript(tagstring[3]))
- return;
-
- if (*complex_ != '\0')
- strcat ((char *) complex_, " ");
- strcat ((char *) complex_, "otlayout:");
- strcat ((char *) complex_, (char *) tagstring);
-}
-
-static int
-compareulong (const void *a, const void *b)
-{
- const FT_ULong *ua = (const FT_ULong *) a;
- const FT_ULong *ub = (const FT_ULong *) b;
- return *ua - *ub;
-}
-
-
-static int
-GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
-{
- FT_ULong cur_offset, new_offset, base_offset;
- FT_Stream stream = face->stream;
- FT_Error error;
- FT_UShort n, p;
- FT_Memory memory;
- int script_count;
-
- if (!stream)
- return 0;
-
- memory = stream->memory;
-
- if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
- return 0;
-
- base_offset = ftglue_stream_pos ( stream );
-
- /* skip version */
-
- if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
- return 0;
-
- new_offset = GET_UShort() + base_offset;
-
- ftglue_stream_frame_exit( stream );
-
- cur_offset = ftglue_stream_pos( stream );
-
- if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
- return 0;
-
- base_offset = ftglue_stream_pos( stream );
-
- if ( ftglue_stream_frame_enter( stream, 2L ) )
- return 0;
-
- script_count = GET_UShort ();
-
- ftglue_stream_frame_exit( stream );
-
- *stags = malloc(script_count * sizeof (FT_ULong));
- if (!stags)
- return 0;
-
- p = 0;
- for ( n = 0; n < script_count; n++ )
- {
- if ( ftglue_stream_frame_enter( stream, 6L ) )
- goto Fail;
-
- (*stags)[p] = GET_ULong ();
- new_offset = GET_UShort () + base_offset;
-
- ftglue_stream_frame_exit( stream );
-
- cur_offset = ftglue_stream_pos( stream );
-
- error = ftglue_stream_seek( stream, new_offset );
-
- if ( error == FT_Err_Ok )
- p++;
-
- (void)ftglue_stream_seek( stream, cur_offset );
- }
-
- if (!p)
- goto Fail;
-
- /* sort the tag list before returning it */
- qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
-
- return script_count;
-
-Fail:
- free(*stags);
- *stags = NULL;
- return 0;
-}
-
-static FcChar8 *
-FcFontCapabilities(FT_Face face)
-{
- FcBool issilgraphitefont = 0;
- FT_Error err;
- FT_ULong len = 0;
- FT_ULong *gsubtags=NULL, *gpostags=NULL;
- FT_UShort gsub_count=0, gpos_count=0;
- FT_ULong maxsize;
- FcChar8 *complex_ = NULL;
- int indx1 = 0, indx2 = 0;
-
- err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
- issilgraphitefont = ( err == FT_Err_Ok);
-
- gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
- gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
-
- if (!issilgraphitefont && !gsub_count && !gpos_count)
- goto bail;
-
- maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
- (issilgraphitefont ? 13 : 0));
- complex_ = malloc (sizeof (FcChar8) * maxsize);
- if (!complex_)
- goto bail;
-
- complex_[0] = '\0';
- if (issilgraphitefont)
- strcpy((char *) complex_, "ttable:Silf ");
-
- while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
- if (indx1 == gsub_count) {
- addtag(complex_, gpostags[indx2]);
- indx2++;
- } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
- addtag(complex_, gsubtags[indx1]);
- indx1++;
- } else if (gsubtags[indx1] == gpostags[indx2]) {
- addtag(complex_, gsubtags[indx1]);
- indx1++;
- indx2++;
- } else {
- addtag(complex_, gpostags[indx2]);
- indx2++;
- }
- }
- if (FcDebug () & FC_DBG_SCANV)
- printf("complex_ features in this font: %s\n", complex_);
-bail:
- free(gsubtags);
- free(gpostags);
- return complex_;
-}
-
-#define __fcfreetype__
-#include "fcaliastail.h"
-#include "fcftaliastail.h"
-#undef __fcfreetype__
+/* + * fontconfig/src/fcfreetype.c + * + * Copyright © 2001 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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. + */ + +/* + Copyright © 2002-2003 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "fcint.h" +#include "fcftint.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H +#include FT_SFNT_NAMES_H +#include FT_TRUETYPE_IDS_H +#include FT_TYPE1_TABLES_H +#if HAVE_FT_GET_X11_FONT_FORMAT +#include FT_XFREE86_H +#endif +#if HAVE_FT_GET_BDF_PROPERTY +#include FT_BDF_H +#include FT_MODULE_H +#endif + +#include "ftglue.h" + +#if HAVE_WARNING_CPP_DIRECTIVE +#if !HAVE_FT_GET_BDF_PROPERTY +#warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later" +#endif + +#if !HAVE_FT_GET_PS_FONT_INFO +#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later" +#endif +#endif + +/* + * Keep Han languages separated by eliminating languages + * that the codePageRange bits says aren't supported + */ + +static const struct { + char bit; + const FcChar8 lang[6]; +} FcCodePageRange[] = { + { 17, "ja" }, + { 18, "zh-cn" }, + { 19, "ko" }, + { 20, "zh-tw" }, +}; + +#define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0]) + +FcBool +FcFreeTypeIsExclusiveLang (const FcChar8 *lang) +{ + int i; + + for (i = 0; i < NUM_CODE_PAGE_RANGE; i++) + { + if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual) + return FcTrue; + } + return FcFalse; +} + +typedef struct { + const FT_UShort platform_id; + const FT_UShort encoding_id; + const char fromcode[12]; +} FcFtEncoding; + +#define TT_ENCODING_DONT_CARE 0xffff +#define FC_ENCODING_MAC_ROMAN "MACINTOSH" + +static const FcFtEncoding fcFtEncoding[] = { + { TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UTF-16BE" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, "UTF-16BE" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB2312" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UTF-16BE" }, + { TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" }, + { TT_PLATFORM_ISO, TT_ISO_ID_10646, "UTF-16BE" }, + { TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" }, +}; + +#define NUM_FC_FT_ENCODING (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0])) + +typedef struct { + const FT_UShort platform_id; + const FT_UShort language_id; + const char lang[8]; +} FcFtLanguage; + +#define TT_LANGUAGE_DONT_CARE 0xffff + +static const FcFtLanguage fcFtLanguage[] = { + { TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" }, +/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */ + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" }, + +#if 0 /* these seem to be errors that have been dropped */ + + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC }, + +#endif + + /* The following codes are new as of 2000-03-10 */ + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" }, + +#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND + /* this seems to be an error that have been dropped */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" }, +#endif + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" }, + + /* new as of 2001-01-01 */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" }, + + /* the following seems to be inconsistent; + here is the current "official" way: */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" }, + /* and here is what is used by Passport SDK */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" }, + /* end of inconsistency */ + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" }, + /* the following one is only encountered in Microsoft RTF specification */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" }, + /* the following one is not in the Passport list, looks like an omission */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" }, + + /* new as of 2001-03-01 (from Office Xp) */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" }, +#if 0 + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN }, +#endif + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" }, + + /* New additions from Windows Xp/Passport SDK 2001-11-10. */ + + /* don't ask what this one means... It is commented out currently. */ +#if 0 + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 }, +#endif + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" }, + /* The following two IDs blatantly violate MS specs by using a */ + /* sublanguage >,. */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" }, +#if 0 + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA }, +#endif + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" }, + /* language codes from, to, are (still) unknown. */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" }, +#if 0 + /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ + /* not written (but OTOH the peculiar writing system is worth */ + /* studying). */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA }, +#endif + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" }, +}; + +#define NUM_FC_FT_LANGUAGE (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0])) + +typedef struct { + FT_UShort language_id; + char fromcode[12]; +} FcMacRomanFake; + +static const FcMacRomanFake fcMacRomanFake[] = { + { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" }, + { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" }, +}; + +static FcChar8 * +FcFontCapabilities(FT_Face face); + +#define NUM_FC_MAC_ROMAN_FAKE (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0])) + +#if USE_ICONV +#include <iconv.h> +#endif + +/* + * A shift-JIS will have many high bits turned on + */ +static FcBool +FcLooksLikeSJIS (FcChar8 *string, int len) +{ + int nhigh = 0, nlow = 0; + + while (len-- > 0) + { + if (*string++ & 0x80) nhigh++; + else nlow++; + } + /* + * Heuristic -- if more than 1/3 of the bytes have the high-bit set, + * this is likely to be SJIS and not ROMAN + */ + if (nhigh * 2 > nlow) + return FcTrue; + return FcFalse; +} + +static FcChar8 * +FcSfntNameTranscode (FT_SfntName *sname) +{ + int i; + const char *fromcode; +#if USE_ICONV + iconv_t cd; +#endif + FcChar8 *utf8; + + for (i = 0; i < NUM_FC_FT_ENCODING; i++) + if (fcFtEncoding[i].platform_id == sname->platform_id && + (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE || + fcFtEncoding[i].encoding_id == sname->encoding_id)) + break; + if (i == NUM_FC_FT_ENCODING) + return 0; + fromcode = fcFtEncoding[i].fromcode; + + /* + * Many names encoded for TT_PLATFORM_MACINTOSH are broken + * in various ways. Kludge around them. + */ + if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN)) + { + if (sname->language_id == TT_MAC_LANGID_ENGLISH && + FcLooksLikeSJIS (sname->string, sname->string_len)) + { + fromcode = "SJIS"; + } + else if (sname->language_id >= 0x100) + { + /* + * "real" Mac language IDs are all less than 150. + * Names using one of the MS language IDs are assumed + * to use an associated encoding (Yes, this is a kludge) + */ + int f; + + fromcode = NULL; + for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++) + if (fcMacRomanFake[f].language_id == sname->language_id) + { + fromcode = fcMacRomanFake[f].fromcode; + break; + } + if (!fromcode) + return 0; + } + } + if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE")) + { + FcChar8 *src = sname->string; + int src_len = sname->string_len; + int len; + int wchar; + int ilen, olen; + FcChar8 *u8; + FcChar32 ucs4; + + /* + * Convert Utf16 to Utf8 + */ + + if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar)) + return 0; + + /* + * Allocate plenty of space. Freed below + */ + utf8 = malloc (len * FC_UTF8_MAX_LEN + 1); + if (!utf8) + return 0; + + u8 = utf8; + + while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0) + { + src_len -= ilen; + src += ilen; + olen = FcUcs4ToUtf8 (ucs4, u8); + u8 += olen; + } + *u8 = '\0'; + goto done; + } + if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1")) + { + FcChar8 *src = sname->string; + int src_len = sname->string_len; + int olen; + FcChar8 *u8; + FcChar32 ucs4; + + /* + * Convert Latin1 to Utf8. Freed below + */ + utf8 = malloc (src_len * 2 + 1); + if (!utf8) + return 0; + + u8 = utf8; + while (src_len > 0) + { + ucs4 = *src++; + src_len--; + olen = FcUcs4ToUtf8 (ucs4, u8); + u8 += olen; + } + *u8 = '\0'; + goto done; + } + if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN)) + { + FcChar8 *u8; + const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman); + FcChar8 *src = (FcChar8 *) sname->string; + int src_len = sname->string_len; + + /* + * Convert AppleRoman to Utf8 + */ + if (!map) + return 0; + + utf8 = malloc (sname->string_len * 3 + 1); + if (!utf8) + return 0; + + u8 = utf8; + while (src_len > 0) + { + FcChar32 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map); + int olen = FcUcs4ToUtf8 (ucs4, u8); + src_len--; + u8 += olen; + } + *u8 = '\0'; + goto done; + } +#if USE_ICONV + cd = iconv_open ("UTF-8", fromcode); + if (cd && cd != (iconv_t) (-1)) + { + size_t in_bytes_left = sname->string_len; + size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN; + char *inbuf, *outbuf; + + utf8 = malloc (out_bytes_left + 1); + if (!utf8) + { + iconv_close (cd); + return 0; + } + + outbuf = (char *) utf8; + inbuf = (char *) sname->string; + + while (in_bytes_left) + { + size_t did = iconv (cd, + &inbuf, &in_bytes_left, + &outbuf, &out_bytes_left); + if (did == (size_t) (-1)) + { + iconv_close (cd); + free (utf8); + return 0; + } + } + iconv_close (cd); + *outbuf = '\0'; + goto done; + } +#endif + return 0; +done: + if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0) + { + free (utf8); + return 0; + } + return utf8; +} + +static const FcChar8 * +FcSfntNameLanguage (FT_SfntName *sname) +{ + int i; + FT_UShort platform_id = sname->platform_id; + FT_UShort language_id = sname->language_id; + + /* + * Many names encoded for TT_PLATFORM_MACINTOSH are broken + * in various ways. Kludge around them. + */ + if (platform_id == TT_PLATFORM_MACINTOSH && + sname->encoding_id == TT_MAC_ID_ROMAN && + FcLooksLikeSJIS (sname->string, sname->string_len)) + { + language_id = TT_MAC_LANGID_JAPANESE; + } + + for (i = 0; i < NUM_FC_FT_LANGUAGE; i++) + if (fcFtLanguage[i].platform_id == platform_id && + (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE || + fcFtLanguage[i].language_id == language_id)) + { + if (fcFtLanguage[i].lang[0] == '\0') + return NULL; + else + return (FcChar8 *) fcFtLanguage[i].lang; + } + return 0; +} + +/* Order is significant. For example, some B&H fonts are hinted by + URW++, and both strings appear in the notice. */ + +static const char notice_foundry_data[] = + "Bigelow\0b&h\0" + "Adobe\0adobe\0" + "Bitstream\0bitstream\0" + "Monotype\0monotype\0" + "Linotype\0linotype\0" + "LINOTYPE-HELL\0linotype\0" + "IBM\0ibm\0" + "URW\0urw\0" + "International Typeface Corporation\0itc\0" + "Tiro Typeworks\0tiro\0" + "XFree86\0xfree86\0" + "Microsoft\0microsoft\0" + "Omega\0omega\0" + "Font21\0hwan\0" + "HanYang System\0hanyang"; + +struct _notice_foundry { + /* these are the offsets into the + * notice_foundry_data array. + */ + unsigned char notice_offset; + unsigned char foundry_offset; +}; + +static const struct _notice_foundry FcNoticeFoundries[] = { + { 0, 8 }, + { 12, 18 }, + { 24, 34 }, + { 44, 53 }, + { 62, 71 }, + { 80, 94 }, + { 103, 107 }, + { 111, 115 }, + { 119, 154 }, + { 158, 173 }, + { 178, 186 }, + { 194, 204 }, + { 214, 220 }, + { 226, 233 }, + { 238, 253 } +}; + +#define NUM_NOTICE_FOUNDRIES (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0])) + +static const FcChar8 * +FcNoticeFoundry(const FT_String *notice) +{ + int i; + + if (notice) + for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++) + { + const struct _notice_foundry *nf = &FcNoticeFoundries[i]; + const char *n = notice_foundry_data + nf->notice_offset; + const char *f = notice_foundry_data + nf->foundry_offset; + + if (strstr ((const char *) notice, n)) + return (const FcChar8 *) f; + } + return 0; +} + +static FcBool +FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string) +{ + /* vendor is not necessarily NUL-terminated. */ + int i, len; + + len = strlen((char *) vendor_string); + if (memcmp(vendor, vendor_string, len) != 0) + return FcFalse; + for (i = len; i < 4; i++) + if (vendor[i] != ' ' && vendor[i] != '\0') + return FcFalse; + return FcTrue; +} + +/* This table is partly taken from ttmkfdir by Joerg Pommnitz. */ + +/* It should not contain useless entries (such as UNKN) nor duplicate + entries for padding both with spaces and NULs. */ + +static const struct { + const FT_Char vendor[5]; + const FcChar8 foundry[13]; +} FcVendorFoundries[] = { + { "ADBE", "adobe"}, + { "AGFA", "agfa"}, + { "ALTS", "altsys"}, + { "APPL", "apple"}, + { "ARPH", "arphic"}, + { "ATEC", "alltype"}, + { "B&H", "b&h"}, + { "BITS", "bitstream"}, + { "CANO", "cannon"}, + { "DYNA", "dynalab"}, + { "EPSN", "epson"}, + { "FJ", "fujitsu"}, + { "IBM", "ibm"}, + { "ITC", "itc"}, + { "IMPR", "impress"}, + { "LARA", "larabiefonts"}, + { "LEAF", "interleaf"}, + { "LETR", "letraset"}, + { "LINO", "linotype"}, + { "MACR", "macromedia"}, + { "MONO", "monotype"}, + { "MS", "microsoft"}, + { "MT", "monotype"}, + { "NEC", "nec"}, + { "PARA", "paratype"}, + { "QMSI", "qms"}, + { "RICO", "ricoh"}, + { "URW", "urw"}, + { "Y&Y", "y&y"} +}; + +#define NUM_VENDOR_FOUNDRIES (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0])) + +static const FcChar8 * +FcVendorFoundry(const FT_Char vendor[4]) +{ + int i; + + if (vendor) + for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++) + if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor)) + return FcVendorFoundries[i].foundry; + return 0; +} + +typedef struct _FcStringConst { + const FcChar8 *name; + int value; +} FcStringConst; + +static int +FcStringIsConst (const FcChar8 *string, + const FcStringConst *c, + int nc) +{ + int i; + + for (i = 0; i < nc; i++) + if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0) + return c[i].value; + return -1; +} + +static int +FcStringContainsConst (const FcChar8 *string, + const FcStringConst *c, + int nc) +{ + int i; + + for (i = 0; i < nc; i++) + { + if (c[i].name[0] == '<') + { + if (FcStrContainsWord (string, c[i].name + 1)) + return c[i].value; + } + else + { + if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name)) + return c[i].value; + } + } + return -1; +} + +typedef FcChar8 *FC8; + +static const FcStringConst weightConsts[] = { + { (FC8) "thin", FC_WEIGHT_THIN }, + { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT }, + { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT }, + { (FC8) "light", FC_WEIGHT_LIGHT }, + { (FC8) "book", FC_WEIGHT_BOOK }, + { (FC8) "regular", FC_WEIGHT_REGULAR }, + { (FC8) "normal", FC_WEIGHT_NORMAL }, + { (FC8) "medium", FC_WEIGHT_MEDIUM }, + { (FC8) "demibold", FC_WEIGHT_DEMIBOLD }, + { (FC8) "demi", FC_WEIGHT_DEMIBOLD }, + { (FC8) "semibold", FC_WEIGHT_SEMIBOLD }, + { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD }, + { (FC8) "superbold", FC_WEIGHT_EXTRABOLD }, + { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD }, + { (FC8) "bold", FC_WEIGHT_BOLD }, + { (FC8) "ultrablack", FC_WEIGHT_ULTRABLACK }, + { (FC8) "superblack", FC_WEIGHT_EXTRABLACK }, + { (FC8) "extrablack", FC_WEIGHT_EXTRABLACK }, + { (FC8) "<ultra", FC_WEIGHT_ULTRABOLD }, /* only if a word */ + { (FC8) "black", FC_WEIGHT_BLACK }, + { (FC8) "heavy", FC_WEIGHT_HEAVY }, +}; + +#define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0])) + +#define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS) +#define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS) + +static const FcStringConst widthConsts[] = { + { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED }, + { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED }, + { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED }, + { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */ + { (FC8) "normal", FC_WIDTH_NORMAL }, + { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED }, + { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED }, + { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED }, + { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */ + { (FC8) "extended", FC_WIDTH_EXPANDED }, +}; + +#define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0])) + +#define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS) +#define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS) + +static const FcStringConst slantConsts[] = { + { (FC8) "italic", FC_SLANT_ITALIC }, + { (FC8) "kursiv", FC_SLANT_ITALIC }, + { (FC8) "oblique", FC_SLANT_OBLIQUE }, +}; + +#define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0])) + +#define FcIsSlant(s) FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS) +#define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS) + +static const FcStringConst decorativeConsts[] = { + { (FC8) "shadow", FcTrue }, + { (FC8) "caps", FcTrue }, + { (FC8) "antiqua", FcTrue }, + { (FC8) "romansc", FcTrue }, + { (FC8) "embosed", FcTrue }, + { (FC8) "dunhill", FcTrue }, +}; + +#define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0])) + +#define FcIsDecorative(s) FcStringIsConst(s,decorativeConsts,NUM_DECORATIVE_CONSTS) +#define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS) + +static double +FcGetPixelSize (FT_Face face, int i) +{ +#if HAVE_FT_GET_BDF_PROPERTY + if (face->num_fixed_sizes == 1) + { + BDF_PropertyRec prop; + int rc; + + rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop); + if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) + return (double) prop.u.integer; + } +#endif +#if HAVE_FT_BITMAP_SIZE_Y_PPEM + return (double) face->available_sizes[i].y_ppem / 64.0; +#else + return (double) face->available_sizes[i].height; +#endif +} + +static FcBool +FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string) +{ + int e; + FcChar8 *old; + for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++) + if (!FcStrCmpIgnoreBlanksAndCase (old, string)) + { + return FcTrue; + } + return FcFalse; +} + +static const FT_UShort platform_order[] = { + TT_PLATFORM_MICROSOFT, + TT_PLATFORM_APPLE_UNICODE, + TT_PLATFORM_MACINTOSH, +}; +#define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0])) + +static const FT_UShort nameid_order[] = { +#ifdef TT_NAME_ID_WWS_FAMILY + TT_NAME_ID_WWS_FAMILY, +#endif + TT_NAME_ID_PREFERRED_FAMILY, + TT_NAME_ID_FONT_FAMILY, + TT_NAME_ID_MAC_FULL_NAME, + TT_NAME_ID_FULL_NAME, +#ifdef TT_NAME_ID_WWS_SUBFAMILY + TT_NAME_ID_WWS_SUBFAMILY, +#endif + TT_NAME_ID_PREFERRED_SUBFAMILY, + TT_NAME_ID_FONT_SUBFAMILY, + TT_NAME_ID_TRADEMARK, + TT_NAME_ID_MANUFACTURER, +}; + +#define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0])) +FcPattern * +FcFreeTypeQueryFace (const FT_Face face, + const FcChar8 *file, + int id, + FcBlanks *blanks) +{ + FcPattern *pat; + int slant = -1; + int weight = -1; + int width = -1; + FcBool decorative = FcFalse; + int i; + FcCharSet *cs; + FcLangSet *ls; +#if 0 + FcChar8 *family = 0; +#endif + FcChar8 *complex_; + const FcChar8 *foundry = 0; + int spacing; + TT_OS2 *os2; +#if HAVE_FT_GET_PS_FONT_INFO + PS_FontInfoRec psfontinfo; +#endif +#if HAVE_FT_GET_BDF_PROPERTY + BDF_PropertyRec prop; +#endif + TT_Header *head; + const FcChar8 *exclusiveLang = 0; + FT_SfntName sname; + FT_UInt snamei, snamec; + + int nfamily = 0; + int nfamily_lang = 0; + int nstyle = 0; + int nstyle_lang = 0; + int nfullname = 0; + int nfullname_lang = 0; + int p, platform; + int n, nameid; + + FcChar8 *style = 0; + int st; + + 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; + + + /* + * Get the OS/2 table + */ + os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2); + + /* + * Look first in the OS/2 table for the foundry, if + * not found here, the various notices will be searched for + * that information, either from the sfnt name tables or + * the Postscript FontInfo dictionary. Finally, the + * BDF properties will queried. + */ + + if (os2 && os2->version >= 0x0001 && os2->version != 0xffff) + foundry = FcVendorFoundry(os2->achVendID); + + if (FcDebug () & FC_DBG_SCANV) + printf ("\n"); + /* + * Grub through the name table looking for family + * and style names. FreeType makes quite a hash + * of them + */ + snamec = FT_Get_Sfnt_Name_Count (face); + for (p = 0; p <= NUM_PLATFORM_ORDER; p++) + { + if (p < NUM_PLATFORM_ORDER) + platform = platform_order[p]; + else + platform = 0xffff; + + /* + * Order nameids so preferred names appear first + * in the resulting list + */ + for (n = 0; n < NUM_NAMEID_ORDER; n++) + { + nameid = nameid_order[n]; + + for (snamei = 0; snamei < snamec; snamei++) + { + FcChar8 *utf8; + const FcChar8 *lang; + const char *elt = 0, *eltlang = 0; + int *np = 0, *nlangp = 0; + + if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0) + continue; + if (sname.name_id != nameid) + continue; + + /* + * Sort platforms in preference order, accepting + * all other platforms last + */ + if (p < NUM_PLATFORM_ORDER) + { + if (sname.platform_id != platform) + continue; + } + else + { + int sp; + + for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++) + if (sname.platform_id == platform_order[sp]) + break; + if (sp != NUM_PLATFORM_ORDER) + continue; + } + utf8 = FcSfntNameTranscode (&sname); + lang = FcSfntNameLanguage (&sname); + + if (!utf8) + continue; + + switch (sname.name_id) { +#ifdef TT_NAME_ID_WWS_FAMILY + case TT_NAME_ID_WWS_FAMILY: +#endif + case TT_NAME_ID_PREFERRED_FAMILY: + case TT_NAME_ID_FONT_FAMILY: +#if 0 + case TT_NAME_ID_PS_NAME: + case TT_NAME_ID_UNIQUE_ID: +#endif + if (FcDebug () & FC_DBG_SCANV) + printf ("found family (n %2d p %d e %d l 0x%04x) %s\n", + sname.name_id, sname.platform_id, + sname.encoding_id, sname.language_id, + utf8); + + elt = FC_FAMILY; + eltlang = FC_FAMILYLANG; + np = &nfamily; + nlangp = &nfamily_lang; + break; + case TT_NAME_ID_MAC_FULL_NAME: + case TT_NAME_ID_FULL_NAME: + if (FcDebug () & FC_DBG_SCANV) + printf ("found full (n %2d p %d e %d l 0x%04x) %s\n", + sname.name_id, sname.platform_id, + sname.encoding_id, sname.language_id, + utf8); + + elt = FC_FULLNAME; + eltlang = FC_FULLNAMELANG; + np = &nfullname; + nlangp = &nfullname_lang; + break; +#ifdef TT_NAME_ID_WWS_SUBFAMILY + case TT_NAME_ID_WWS_SUBFAMILY: +#endif + case TT_NAME_ID_PREFERRED_SUBFAMILY: + case TT_NAME_ID_FONT_SUBFAMILY: + if (FcDebug () & FC_DBG_SCANV) + printf ("found style (n %2d p %d e %d l 0x%04x) %s\n", + sname.name_id, sname.platform_id, + sname.encoding_id, sname.language_id, + utf8); + + elt = FC_STYLE; + eltlang = FC_STYLELANG; + np = &nstyle; + nlangp = &nstyle_lang; + break; + case TT_NAME_ID_TRADEMARK: + case TT_NAME_ID_MANUFACTURER: + /* If the foundry wasn't found in the OS/2 table, look here */ + if(!foundry) + foundry = FcNoticeFoundry((FT_String *) utf8); + break; + } + if (elt) + { + if (FcStringInPatternElement (pat, elt, utf8)) + { + free (utf8); + continue; + } + + /* add new element */ + if (!FcPatternAddString (pat, elt, utf8)) + { + free (utf8); + goto bail1; + } + free (utf8); + if (lang) + { + /* pad lang list with 'xx' to line up with elt */ + while (*nlangp < *np) + { + if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx")) + goto bail1; + ++*nlangp; + } + if (!FcPatternAddString (pat, eltlang, lang)) + goto bail1; + ++*nlangp; + } + ++*np; + } + else + free (utf8); + } + } + } + + if (!nfamily && face->family_name && + FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0) + { + if (FcDebug () & FC_DBG_SCANV) + printf ("using FreeType family \"%s\"\n", face->family_name); + if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name)) + goto bail1; + ++nfamily; + } + + if (!nstyle && face->style_name && + FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0) + { + if (FcDebug () & FC_DBG_SCANV) + printf ("using FreeType style \"%s\"\n", face->style_name); + if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name)) + goto bail1; + ++nstyle; + } + + if (!nfamily) + { + FcChar8 *start, *end; + FcChar8 *family; + + start = (FcChar8 *) strrchr ((char *) file, '/'); + if (start) + start++; + else + start = (FcChar8 *) file; + end = (FcChar8 *) strrchr ((char *) start, '.'); + if (!end) + end = start + strlen ((char *) start); + /* freed below */ + family = malloc (end - start + 1); + strncpy ((char *) family, (char *) start, end - start); + family[end - start] = '\0'; + if (FcDebug () & FC_DBG_SCANV) + printf ("using filename for family %s\n", family); + if (!FcPatternAddString (pat, FC_FAMILY, family)) + { + free (family); + goto bail1; + } + free (family); + ++nfamily; + } + + if (!FcPatternAddString (pat, FC_FILE, file)) + goto bail1; + + if (!FcPatternAddInteger (pat, FC_INDEX, id)) + goto bail1; + +#if 0 + /* + * don't even try this -- CJK 'monospace' fonts are really + * dual width, and most other fonts don't bother to set + * the attribute. Sigh. + */ + if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0) + if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO)) + goto bail1; +#endif + + /* + * Find the font revision (if available) + */ + head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head); + if (head) + { + if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision)) + goto bail1; + } + else + { + if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0)) + goto bail1; + } + + 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 the font advertises support for multiple + * "exclusive" languages, then include support + * for any language found to have coverage + */ + if (exclusiveLang) + { + exclusiveLang = 0; + break; + } + exclusiveLang = FcCodePageRange[i].lang; + } + } + } + + if (os2 && os2->version != 0xffff) + { + if (os2->usWeightClass == 0) + ; + else if (os2->usWeightClass < 150) + weight = FC_WEIGHT_THIN; + else if (os2->usWeightClass < 250) + weight = FC_WEIGHT_EXTRALIGHT; + else if (os2->usWeightClass < 350) + weight = FC_WEIGHT_LIGHT; + else if (os2->usWeightClass < 450) + weight = FC_WEIGHT_REGULAR; + else if (os2->usWeightClass < 550) + weight = FC_WEIGHT_MEDIUM; + else if (os2->usWeightClass < 650) + weight = FC_WEIGHT_SEMIBOLD; + else if (os2->usWeightClass < 750) + weight = FC_WEIGHT_BOLD; + else if (os2->usWeightClass < 850) + weight = FC_WEIGHT_EXTRABOLD; + else if (os2->usWeightClass < 925) + weight = FC_WEIGHT_BLACK; + else if (os2->usWeightClass < 1000) + weight = FC_WEIGHT_EXTRABLACK; + if ((FcDebug() & FC_DBG_SCANV) && weight != -1) + printf ("\tos2 weight class %d maps to weight %d\n", + os2->usWeightClass, weight); + + switch (os2->usWidthClass) { + case 1: width = FC_WIDTH_ULTRACONDENSED; break; + case 2: width = FC_WIDTH_EXTRACONDENSED; break; + case 3: width = FC_WIDTH_CONDENSED; break; + case 4: width = FC_WIDTH_SEMICONDENSED; break; + case 5: width = FC_WIDTH_NORMAL; break; + case 6: width = FC_WIDTH_SEMIEXPANDED; break; + case 7: width = FC_WIDTH_EXPANDED; break; + case 8: width = FC_WIDTH_EXTRAEXPANDED; break; + case 9: width = FC_WIDTH_ULTRAEXPANDED; break; + } + if ((FcDebug() & FC_DBG_SCANV) && width != -1) + printf ("\tos2 width class %d maps to width %d\n", + os2->usWidthClass, width); + } + if (os2 && (complex_ = FcFontCapabilities(face))) + { + if (!FcPatternAddString (pat, FC_CAPABILITY, complex_)) + { + free (complex_); + goto bail1; + } + free (complex_); + } + + /* + * Type 1: Check for FontInfo dictionary information + * Code from g2@magestudios.net (Gerard Escalante) + */ + +#if HAVE_FT_GET_PS_FONT_INFO + if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0) + { + if (weight == -1 && psfontinfo.weight) + { + weight = FcIsWeight ((FcChar8 *) psfontinfo.weight); + if (FcDebug() & FC_DBG_SCANV) + printf ("\tType1 weight %s maps to %d\n", + psfontinfo.weight, weight); + } + +#if 0 + /* + * Don't bother with italic_angle; FreeType already extracts that + * information for us and sticks it into style_flags + */ + if (psfontinfo.italic_angle) + slant = FC_SLANT_ITALIC; + else + slant = FC_SLANT_ROMAN; +#endif + + if(!foundry) + foundry = FcNoticeFoundry(psfontinfo.notice); + } +#endif /* HAVE_FT_GET_PS_FONT_INFO */ + +#if HAVE_FT_GET_BDF_PROPERTY + /* + * Finally, look for a FOUNDRY BDF property if no other + * mechanism has managed to locate a foundry + */ + + if (!foundry) + { + int rc; + rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop); + if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) + foundry = (FcChar8 *) prop.u.atom; + } + + if (width == -1) + { + if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 && + (prop.type == BDF_PROPERTY_TYPE_INTEGER || + prop.type == BDF_PROPERTY_TYPE_CARDINAL)) + { + FT_Int32 value; + + if (prop.type == BDF_PROPERTY_TYPE_INTEGER) + value = prop.u.integer; + else + value = (FT_Int32) prop.u.cardinal; + switch ((value + 5) / 10) { + case 1: width = FC_WIDTH_ULTRACONDENSED; break; + case 2: width = FC_WIDTH_EXTRACONDENSED; break; + case 3: width = FC_WIDTH_CONDENSED; break; + case 4: width = FC_WIDTH_SEMICONDENSED; break; + case 5: width = FC_WIDTH_NORMAL; break; + case 6: width = FC_WIDTH_SEMIEXPANDED; break; + case 7: width = FC_WIDTH_EXPANDED; break; + case 8: width = FC_WIDTH_EXTRAEXPANDED; break; + case 9: width = FC_WIDTH_ULTRAEXPANDED; break; + } + } + if (width == -1 && + FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 && + prop.type == BDF_PROPERTY_TYPE_ATOM) + { + width = FcIsWidth ((FcChar8 *) prop.u.atom); + if (FcDebug () & FC_DBG_SCANV) + printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width); + } + } +#endif + + /* + * Look for weight, width and slant names in the style value + */ + for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++) + { + if (weight == -1) + { + weight = FcContainsWeight (style); + if (FcDebug() & FC_DBG_SCANV) + printf ("\tStyle %s maps to weight %d\n", style, weight); + } + if (width == -1) + { + width = FcContainsWidth (style); + if (FcDebug() & FC_DBG_SCANV) + printf ("\tStyle %s maps to width %d\n", style, width); + } + if (slant == -1) + { + slant = FcContainsSlant (style); + if (FcDebug() & FC_DBG_SCANV) + printf ("\tStyle %s maps to slant %d\n", style, slant); + } + if (decorative == FcFalse) + { + decorative = FcContainsDecorative (style) > 0; + if (FcDebug() & FC_DBG_SCANV) + printf ("\tStyle %s maps to decorative %d\n", style, decorative); + } + } + /* + * Pull default values from the FreeType flags if more + * specific values not found above + */ + if (slant == -1) + { + slant = FC_SLANT_ROMAN; + if (face->style_flags & FT_STYLE_FLAG_ITALIC) + slant = FC_SLANT_ITALIC; + } + + if (weight == -1) + { + weight = FC_WEIGHT_MEDIUM; + if (face->style_flags & FT_STYLE_FLAG_BOLD) + weight = FC_WEIGHT_BOLD; + } + + if (width == -1) + width = FC_WIDTH_NORMAL; + + if (foundry == 0) + foundry = (FcChar8 *) "unknown"; + + if (!FcPatternAddInteger (pat, FC_SLANT, slant)) + goto bail1; + + if (!FcPatternAddInteger (pat, FC_WEIGHT, weight)) + goto bail1; + + if (!FcPatternAddInteger (pat, FC_WIDTH, width)) + goto bail1; + + if (!FcPatternAddString (pat, FC_FOUNDRY, foundry)) + goto bail1; + + if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative)) + goto bail1; + + /* + * Compute the unicode coverage for the font + */ + cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing); + if (!cs) + goto bail1; + +#if HAVE_FT_GET_BDF_PROPERTY + /* For PCF fonts, override the computed spacing with the one from + the property */ + if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 && + prop.type == BDF_PROPERTY_TYPE_ATOM) { + if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C")) + spacing = FC_CHARCELL; + else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M")) + spacing = FC_MONO; + else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P")) + spacing = FC_PROPORTIONAL; + } +#endif + + /* + * Skip over PCF fonts that have no encoded characters; they're + * usually just Unicode fonts transcoded to some legacy encoding + * FT forces us to approximate whether a font is a PCF font + * or not by whether it has any BDF properties. Try PIXEL_SIZE; + * I don't know how to get a list of BDF properties on the font. -PL + */ + if (FcCharSetCount (cs) == 0) + { +#if HAVE_FT_GET_BDF_PROPERTY + if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0) + goto bail2; +#endif + } + + if (!FcPatternAddCharSet (pat, FC_CHARSET, cs)) + goto bail2; + + ls = FcFreeTypeLangSet (cs, exclusiveLang); + if (!ls) + goto bail2; + + if (!FcPatternAddLangSet (pat, FC_LANG, ls)) + { + FcLangSetDestroy (ls); + goto bail2; + } + + FcLangSetDestroy (ls); + + if (spacing != FC_PROPORTIONAL) + if (!FcPatternAddInteger (pat, FC_SPACING, spacing)) + goto bail2; + + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) + { + for (i = 0; i < face->num_fixed_sizes; i++) + if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE, + FcGetPixelSize (face, i))) + goto bail2; + if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse)) + goto bail2; + } +#if HAVE_FT_GET_X11_FONT_FORMAT + /* + * Use the (not well documented or supported) X-specific function + * from FreeType to figure out the font format + */ + { + const char *font_format = FT_Get_X11_Font_Format (face); + if (font_format) + FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format); + } +#endif + + /* + * Drop our reference to the charset + */ + FcCharSetDestroy (cs); + + return pat; + +bail2: + FcCharSetDestroy (cs); +bail1: + FcPatternDestroy (pat); +bail0: + return NULL; +} + +FcPattern * +FcFreeTypeQuery(const FcChar8 *file, + int id, + FcBlanks *blanks, + int *count) +{ + FT_Face face; + FT_Library ftLibrary; + FcPattern *pat = NULL; + + if (FT_Init_FreeType (&ftLibrary)) + return NULL; + + if (FT_New_Face (ftLibrary, (char *) file, id, &face)) + goto bail; + + *count = face->num_faces; + + pat = FcFreeTypeQueryFace (face, file, id, blanks); + + FT_Done_Face (face); +bail: + FT_Done_FreeType (ftLibrary); + return pat; +} + +/* + * For our purposes, this approximation is sufficient + */ +#if !HAVE_FT_GET_NEXT_CHAR +#define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \ + (*(gi) = 0), 0 : \ + (*(gi) = 1), (ucs4) + 1) +#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer" +#endif + +typedef struct _FcCharEnt { + FcChar16 bmp; + unsigned char encode; +} FcCharEnt; + +struct _FcCharMap { + const FcCharEnt *ent; + int nent; +}; + +typedef struct _FcFontDecode { + FT_Encoding encoding; + const FcCharMap *map; + FcChar32 max; +} FcFontDecode; + +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]), +}; + +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 (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0])) + +static const FcChar32 prefer_unicode[] = { + 0x20ac, /* EURO SIGN */ +}; + +#define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0])) + +FcChar32 +FcFreeTypeUcs4ToPrivate (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 (low <= high) + { + mid = (high + low) >> 1; + bmp = map->ent[mid].bmp; + if (ucs4 == bmp) + return (FT_ULong) map->ent[mid].encode; + if (ucs4 < bmp) + high = mid - 1; + else + low = mid + 1; + } + return ~0; +} + +FcChar32 +FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map) +{ + int i; + + for (i = 0; i < map->nent; i++) + if (map->ent[i].encode == private) + return (FcChar32) map->ent[i].bmp; + return ~0; +} + +const FcCharMap * +FcFreeTypeGetPrivateMap (FT_Encoding encoding) +{ + int i; + + for (i = 0; i < NUM_DECODE; i++) + if (fcFontDecoders[i].encoding == encoding) + return fcFontDecoders[i].map; + return 0; +} + +#include "../fc-glyphname/fcglyphname.h" + +static FcChar32 +FcHashGlyphName (const FcChar8 *name) +{ + FcChar32 h = 0; + FcChar8 c; + + while ((c = *name++)) + { + h = ((h << 1) | (h >> 31)) ^ c; + } + return h; +} + +#if HAVE_FT_HAS_PS_GLYPH_NAMES +/* + * Use Type1 glyph names for fonts which have reliable names + * and which export an Adobe Custom mapping + */ +static FcBool +FcFreeTypeUseNames (FT_Face face) +{ + FT_Int map; + + if (!FT_Has_PS_Glyph_Names (face)) + return FcFalse; + for (map = 0; map < face->num_charmaps; map++) + if (face->charmaps[map]->encoding == ft_encoding_adobe_custom) + return FcTrue; + return FcFalse; +} + +static const FcChar8 * +FcUcs4ToGlyphName (FcChar32 ucs4) +{ + int i = (int) (ucs4 % FC_GLYPHNAME_HASH); + int r = 0; + FcGlyphId gn; + + while ((gn = _fc_ucs_to_name[i]) != -1) + { + if (_fc_glyph_names[gn].ucs == ucs4) + return _fc_glyph_names[gn].name; + if (!r) + { + r = (int) (ucs4 % FC_GLYPHNAME_REHASH); + if (!r) + r = 1; + } + i += r; + if (i >= FC_GLYPHNAME_HASH) + i -= FC_GLYPHNAME_HASH; + } + return 0; +} + +static FcChar32 +FcGlyphNameToUcs4 (FcChar8 *name) +{ + FcChar32 h = FcHashGlyphName (name); + int i = (int) (h % FC_GLYPHNAME_HASH); + int r = 0; + FcGlyphId gn; + + while ((gn = _fc_name_to_ucs[i]) != -1) + { + if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name)) + return _fc_glyph_names[gn].ucs; + if (!r) + { + r = (int) (h % FC_GLYPHNAME_REHASH); + if (!r) + r = 1; + } + i += r; + if (i >= FC_GLYPHNAME_HASH) + i -= FC_GLYPHNAME_HASH; + } + return 0xffff; +} + +/* + * Work around a bug in some FreeType versions which fail + * to correctly bounds check glyph name buffers and overwrite + * the stack. As Postscript names have a limit of 127 characters, + * this should be sufficient. + */ + +#if FC_GLYPHNAME_MAXLEN < 127 +# define FC_GLYPHNAME_BUFLEN 127 +#else +# define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN +#endif + +/* + * Search through a font for a glyph by name. This is + * currently a linear search as there doesn't appear to be + * any defined order within the font + */ +static FT_UInt +FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name) +{ + FT_UInt gindex; + FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2]; + + for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++) + { + if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0) + if (!strcmp ((char *) name, (char *) name_buf)) + return gindex; + } + return 0; +} +#endif + +/* + * 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; + FcChar32 charcode; + int p; + + initial = 0; + + if (!face) + return 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; + } + for (p = 0; p < NUM_PREFER_UNICODE; p++) + if (ucs4 == prefer_unicode[p]) + { + initial = 0; + break; + } + /* + * 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 = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map); + if (charcode == ~0U) + continue; + } + else + charcode = ucs4; + glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode); + if (glyphindex) + return glyphindex; + } +#if HAVE_FT_HAS_PS_GLYPH_NAMES + /* + * Check postscript name table if present + */ + if (FcFreeTypeUseNames (face)) + { + const FcChar8 *name = FcUcs4ToGlyphName (ucs4); + if (name) + { + glyphindex = FcFreeTypeGlyphNameIndex (face, name); + if (glyphindex) + return glyphindex; + } + } +#endif + return 0; +} + +static FcBool +FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, + FT_UInt glyph, FcBlanks *blanks, + FT_Pos *advance, + FcBool using_strike) +{ + FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + FT_GlyphSlot slot; + + if (using_strike) + load_flags &= ~FT_LOAD_NO_SCALE; + + /* + * 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; + + *advance = slot->metrics.horiAdvance; + + 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: + break; + } + return FcFalse; +} + +#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33) + +static FcCharSet * +FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index) +{ + FcChar32 page, off, ucs4; +#ifdef CHECK + FcChar32 font_max = 0; +#endif + FcCharSet *fcs; + FcCharLeaf *leaf; + const FcCharMap *map; + int o; + int i; + FT_UInt glyph; + FT_Pos advance, advance_one = 0, advance_two = 0; + FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse; + FcBool using_strike = FcFalse; + + fcs = FcCharSetCreate (); + if (!fcs) + goto bail0; + +#if HAVE_FT_SELECT_SIZE + if (strike_index >= 0) { + if (FT_Select_Size (face, strike_index) != FT_Err_Ok) + goto bail1; + using_strike = FcTrue; + } +#endif + +#ifdef CHECK + printf ("Family %s style %s\n", face->family_name, face->style_name); +#endif + 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, &advance, using_strike)) + { + /* + * ignore glyphs with zero advance. They’re + * combining characters, and while their behaviour + * isn’t well defined for monospaced applications in + * Unicode, there are many fonts which include + * zero-width combining characters in otherwise + * monospaced fonts. + */ + if (advance) + { + if (!has_advance) + { + has_advance = FcTrue; + advance_one = advance; + } + else if (!APPROXIMATELY_EQUAL (advance, advance_one)) + { + if (fixed_advance) + { + dual_advance = FcTrue; + fixed_advance = FcFalse; + advance_two = advance; + } + else if (!APPROXIMATELY_EQUAL (advance, advance_two)) + dual_advance = FcFalse; + } + } + + 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 + { + page = ~0; + leaf = NULL; + ucs4 = FT_Get_First_Char (face, &glyph); + while (glyph != 0) + { + if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + { + if (advance) + { + if (!has_advance) + { + has_advance = FcTrue; + advance_one = advance; + } + else if (!APPROXIMATELY_EQUAL (advance, advance_one)) + { + if (fixed_advance) + { + dual_advance = FcTrue; + fixed_advance = FcFalse; + advance_two = advance; + } + else if (!APPROXIMATELY_EQUAL (advance, advance_two)) + dual_advance = FcFalse; + } + } + + if ((ucs4 >> 8) != page) + { + page = (ucs4 >> 8); + 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 = FT_Get_Next_Char (face, ucs4, &glyph); + } +#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 + } + } +#if HAVE_FT_HAS_PS_GLYPH_NAMES + /* + * Add mapping from PS glyph names if available + */ + if (FcFreeTypeUseNames (face)) + { + FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2]; + + for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++) + { + if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0) + { + ucs4 = FcGlyphNameToUcs4 (name_buf); + if (ucs4 != 0xffff && + FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + { + if (advance) + { + if (!has_advance) + { + has_advance = FcTrue; + advance_one = advance; + } + else if (!APPROXIMATELY_EQUAL (advance, advance_one)) + { + if (fixed_advance) + { + dual_advance = FcTrue; + fixed_advance = FcFalse; + advance_two = advance; + } + else if (!APPROXIMATELY_EQUAL (advance, advance_two)) + dual_advance = FcFalse; + } + } + 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 + } + } + } + } +#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 = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0; + FcBool has_bit = FcCharSetHasChar (fcs, ucs4); + + if (has_char && !has_bit) + { + if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) + printf ("Bitmap missing broken char 0x%x\n", ucs4); + else + printf ("Bitmap missing char 0x%x\n", ucs4); + } + else if (!has_char && has_bit) + printf ("Bitmap extra char 0x%x\n", ucs4); + } +#endif + if (fixed_advance) + *spacing = FC_MONO; + else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two))) + *spacing = FC_DUAL; + else + *spacing = FC_PROPORTIONAL; + return fcs; +bail1: + FcCharSetDestroy (fcs); +bail0: + return 0; +} + +FcCharSet * +FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing) +{ + FcCharSet *cs; + + cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1); + /* + * Check for bitmap-only ttf fonts that are missing the glyf table. + * In that case, pick a size and look for glyphs in that size instead + */ + if (FcCharSetCount (cs) == 0) + { + /* Check for non-scalable TT fonts */ + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && + face->num_fixed_sizes > 0 && + FT_Get_Sfnt_Table (face, ft_sfnt_head)) + { + FT_Int strike_index = 0; + int i; + + /* Select the face closest to 16 pixels tall */ + for (i = 1; i < face->num_fixed_sizes; i++) { + if (abs (face->available_sizes[i].height - 16) < + abs (face->available_sizes[strike_index].height - 16)) + strike_index = i; + } + FcCharSetDestroy (cs); + cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index); + } + } + return cs; +} + +FcCharSet * +FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks) +{ + int spacing; + + return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing); +} + + +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f') + +#define OTLAYOUT_HEAD "otlayout:" +#define OTLAYOUT_HEAD_LEN 9 +#define OTLAYOUT_ID_LEN 4 +/* space + head + id */ +#define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN) + +/* + * This is a bit generous; the registry has only lower case and space + * except for 'DFLT'. + */ +#define FcIsSpace(x) (040 == (x)) +#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x)) + +static void +addtag(FcChar8 *complex_, FT_ULong tag) +{ + FcChar8 tagstring[OTLAYOUT_ID_LEN + 1]; + + tagstring[0] = (FcChar8)(tag >> 24), + tagstring[1] = (FcChar8)(tag >> 16), + tagstring[2] = (FcChar8)(tag >> 8), + tagstring[3] = (FcChar8)(tag); + tagstring[4] = '\0'; + + /* skip tags which aren't alphabetic, under the assumption that + * they're probably broken + */ + if (!FcIsValidScript(tagstring[0]) || + !FcIsValidScript(tagstring[1]) || + !FcIsValidScript(tagstring[2]) || + !FcIsValidScript(tagstring[3])) + return; + + if (*complex_ != '\0') + strcat ((char *) complex_, " "); + strcat ((char *) complex_, "otlayout:"); + strcat ((char *) complex_, (char *) tagstring); +} + +static int +compareulong (const void *a, const void *b) +{ + const FT_ULong *ua = (const FT_ULong *) a; + const FT_ULong *ub = (const FT_ULong *) b; + return *ua - *ub; +} + + +static int +GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags) +{ + FT_ULong cur_offset, new_offset, base_offset; + FT_Stream stream = face->stream; + FT_Error error; + FT_UShort n, p; + FT_Memory memory; + int script_count; + + if (!stream) + return 0; + + memory = stream->memory; + + if (( error = ftglue_face_goto_table( face, tabletag, stream ) )) + return 0; + + base_offset = ftglue_stream_pos ( stream ); + + /* skip version */ + + if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) ) + return 0; + + new_offset = GET_UShort() + base_offset; + + ftglue_stream_frame_exit( stream ); + + cur_offset = ftglue_stream_pos( stream ); + + if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok ) + return 0; + + base_offset = ftglue_stream_pos( stream ); + + if ( ftglue_stream_frame_enter( stream, 2L ) ) + return 0; + + script_count = GET_UShort (); + + ftglue_stream_frame_exit( stream ); + + *stags = malloc(script_count * sizeof (FT_ULong)); + if (!stags) + return 0; + + p = 0; + for ( n = 0; n < script_count; n++ ) + { + if ( ftglue_stream_frame_enter( stream, 6L ) ) + goto Fail; + + (*stags)[p] = GET_ULong (); + new_offset = GET_UShort () + base_offset; + + ftglue_stream_frame_exit( stream ); + + cur_offset = ftglue_stream_pos( stream ); + + error = ftglue_stream_seek( stream, new_offset ); + + if ( error == FT_Err_Ok ) + p++; + + (void)ftglue_stream_seek( stream, cur_offset ); + } + + if (!p) + goto Fail; + + /* sort the tag list before returning it */ + qsort(*stags, script_count, sizeof(FT_ULong), compareulong); + + return script_count; + +Fail: + free(*stags); + *stags = NULL; + return 0; +} + +static FcChar8 * +FcFontCapabilities(FT_Face face) +{ + FcBool issilgraphitefont = 0; + FT_Error err; + FT_ULong len = 0; + FT_ULong *gsubtags=NULL, *gpostags=NULL; + FT_UShort gsub_count=0, gpos_count=0; + FT_ULong maxsize; + FcChar8 *complex_ = NULL; + int indx1 = 0, indx2 = 0; + + err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len); + issilgraphitefont = ( err == FT_Err_Ok); + + gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags); + gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags); + + if (!issilgraphitefont && !gsub_count && !gpos_count) + goto bail; + + maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN + + (issilgraphitefont ? 13 : 0)); + complex_ = malloc (sizeof (FcChar8) * maxsize); + if (!complex_) + goto bail; + + complex_[0] = '\0'; + if (issilgraphitefont) + strcpy((char *) complex_, "ttable:Silf "); + + while ((indx1 < gsub_count) || (indx2 < gpos_count)) { + if (indx1 == gsub_count) { + addtag(complex_, gpostags[indx2]); + indx2++; + } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) { + addtag(complex_, gsubtags[indx1]); + indx1++; + } else if (gsubtags[indx1] == gpostags[indx2]) { + addtag(complex_, gsubtags[indx1]); + indx1++; + indx2++; + } else { + addtag(complex_, gpostags[indx2]); + indx2++; + } + } + if (FcDebug () & FC_DBG_SCANV) + printf("complex_ features in this font: %s\n", complex_); +bail: + free(gsubtags); + free(gpostags); + return complex_; +} + +#define __fcfreetype__ +#include "fcaliastail.h" +#include "fcftaliastail.h" +#undef __fcfreetype__ diff --git a/fontconfig/src/fcfs.c b/fontconfig/src/fcfs.c index e2ff0fafe..6625687c1 100644 --- a/fontconfig/src/fcfs.c +++ b/fontconfig/src/fcfs.c @@ -1,135 +1,135 @@ -/*
- * fontconfig/src/fcfs.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdlib.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;
-}
-
-FcBool
-FcFontSetSerializeAlloc (FcSerialize *serialize, const FcFontSet *s)
-{
- int i;
-
- if (!FcSerializeAlloc (serialize, s, sizeof (FcFontSet)))
- return FcFalse;
- if (!FcSerializeAlloc (serialize, s->fonts, s->nfont * sizeof (FcPattern *)))
- return FcFalse;
- for (i = 0; i < s->nfont; i++)
- {
- if (!FcPatternSerializeAlloc (serialize, s->fonts[i]))
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcFontSet *
-FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s)
-{
- int i;
- FcFontSet *s_serialize;
- FcPattern **fonts_serialize;
- FcPattern *p_serialize;
-
- s_serialize = FcSerializePtr (serialize, s);
- if (!s_serialize)
- return NULL;
- *s_serialize = *s;
- s_serialize->sfont = s_serialize->nfont;
-
- fonts_serialize = FcSerializePtr (serialize, s->fonts);
- if (!fonts_serialize)
- return NULL;
- s_serialize->fonts = FcPtrToEncodedOffset (s_serialize,
- fonts_serialize, FcPattern *);
-
- for (i = 0; i < s->nfont; i++)
- {
- p_serialize = FcPatternSerialize (serialize, s->fonts[i]);
- if (!p_serialize)
- return NULL;
- fonts_serialize[i] = FcPtrToEncodedOffset (s_serialize,
- p_serialize,
- FcPattern);
- }
-
- return s_serialize;
-}
-#define __fcfs__
-#include "fcaliastail.h"
-#undef __fcfs__
+/* + * fontconfig/src/fcfs.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdlib.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; +} + +FcBool +FcFontSetSerializeAlloc (FcSerialize *serialize, const FcFontSet *s) +{ + int i; + + if (!FcSerializeAlloc (serialize, s, sizeof (FcFontSet))) + return FcFalse; + if (!FcSerializeAlloc (serialize, s->fonts, s->nfont * sizeof (FcPattern *))) + return FcFalse; + for (i = 0; i < s->nfont; i++) + { + if (!FcPatternSerializeAlloc (serialize, s->fonts[i])) + return FcFalse; + } + return FcTrue; +} + +FcFontSet * +FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s) +{ + int i; + FcFontSet *s_serialize; + FcPattern **fonts_serialize; + FcPattern *p_serialize; + + s_serialize = FcSerializePtr (serialize, s); + if (!s_serialize) + return NULL; + *s_serialize = *s; + s_serialize->sfont = s_serialize->nfont; + + fonts_serialize = FcSerializePtr (serialize, s->fonts); + if (!fonts_serialize) + return NULL; + s_serialize->fonts = FcPtrToEncodedOffset (s_serialize, + fonts_serialize, FcPattern *); + + for (i = 0; i < s->nfont; i++) + { + p_serialize = FcPatternSerialize (serialize, s->fonts[i]); + if (!p_serialize) + return NULL; + fonts_serialize[i] = FcPtrToEncodedOffset (s_serialize, + p_serialize, + FcPattern); + } + + return s_serialize; +} +#define __fcfs__ +#include "fcaliastail.h" +#undef __fcfs__ diff --git a/fontconfig/src/fcftint.h b/fontconfig/src/fcftint.h index b0f9ff960..a317370e1 100644 --- a/fontconfig/src/fcftint.h +++ b/fontconfig/src/fcftint.h @@ -1,54 +1,54 @@ -/*
- * Copyright © 2007 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. The copyright holders make no representations
- * about the suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS 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 _FCFTINT_H_
-#define _FCFTINT_H_
-
-#include <fontconfig/fcfreetype.h>
-
-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
-#define FcPrivate __attribute__((__visibility__("hidden")))
-#define HAVE_GNUC_ATTRIBUTE 1
-#include "fcftalias.h"
-#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-#define FcPrivate __hidden
-#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
-#define FcPrivate
-#endif
-
-/* fcfreetype.c */
-FcPrivate FcBool
-FcFreeTypeIsExclusiveLang (const FcChar8 *lang);
-
-FcPrivate FcBool
-FcFreeTypeHasLang (FcPattern *pattern, const FcChar8 *lang);
-
-FcPrivate FcChar32
-FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map);
-
-FcPrivate FcChar32
-FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map);
-
-FcPrivate const FcCharMap *
-FcFreeTypeGetPrivateMap (FT_Encoding encoding);
-
-#endif /* _FCFTINT_H_ */
+/* + * Copyright © 2007 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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 _FCFTINT_H_ +#define _FCFTINT_H_ + +#include <fontconfig/fcfreetype.h> + +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) +#define FcPrivate __attribute__((__visibility__("hidden"))) +#define HAVE_GNUC_ATTRIBUTE 1 +#include "fcftalias.h" +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +#define FcPrivate __hidden +#else /* not gcc >= 3.3 and not Sun Studio >= 8 */ +#define FcPrivate +#endif + +/* fcfreetype.c */ +FcPrivate FcBool +FcFreeTypeIsExclusiveLang (const FcChar8 *lang); + +FcPrivate FcBool +FcFreeTypeHasLang (FcPattern *pattern, const FcChar8 *lang); + +FcPrivate FcChar32 +FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map); + +FcPrivate FcChar32 +FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map); + +FcPrivate const FcCharMap * +FcFreeTypeGetPrivateMap (FT_Encoding encoding); + +#endif /* _FCFTINT_H_ */ diff --git a/fontconfig/src/fcinit.c b/fontconfig/src/fcinit.c index 45f0cd4a3..b7966b6db 100644 --- a/fontconfig/src/fcinit.c +++ b/fontconfig/src/fcinit.c @@ -1,289 +1,289 @@ -/*
- * fontconfig/src/fcinit.c
- *
- * Copyright © 2001 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdlib.h>
-
-static FcConfig *
-FcInitFallbackConfig (void)
-{
- FcConfig *config;
-
- config = FcConfigCreate ();
- if (!config)
- goto bail0;
- if (!FcConfigAddDir (config, (FcChar8 *) FC_DEFAULT_FONTS))
- goto bail1;
- if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR))
- goto bail1;
- return config;
-
-bail1:
- FcConfigDestroy (config);
-bail0:
- return 0;
-}
-
-int
-FcGetVersion (void)
-{
- return FC_VERSION;
-}
-
-/*
- * Load the configuration files
- */
-FcConfig *
-FcInitLoadConfig (void)
-{
- FcConfig *config;
-
- FcInitDebug ();
- config = FcConfigCreate ();
- if (!config)
- return NULL;
-
- if (!FcConfigParseAndLoad (config, 0, FcTrue))
- {
- FcConfigDestroy (config);
- return FcInitFallbackConfig ();
- }
-
- if (config->cacheDirs && config->cacheDirs->num == 0)
- {
- fprintf (stderr,
- "Fontconfig warning: no <cachedir> elements found. Check configuration.\n");
- fprintf (stderr,
- "Fontconfig warning: adding <cachedir>%s</cachedir>\n",
- FC_CACHEDIR);
- fprintf (stderr,
- "Fontconfig warning: adding <cachedir>~/.fontconfig</cachedir>\n");
- if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR) ||
- !FcConfigAddCacheDir (config, (FcChar8 *) "~/.fontconfig"))
- {
- fprintf (stderr,
- "Fontconfig error: out of memory");
- FcConfigDestroy (config);
- return FcInitFallbackConfig ();
- }
- }
-
- return config;
-}
-
-/*
- * Load the configuration files and scan for available fonts
- */
-FcConfig *
-FcInitLoadConfigAndFonts (void)
-{
- FcConfig *config = FcInitLoadConfig ();
-
- FcInitDebug ();
- if (!config)
- return 0;
- if (!FcConfigBuildFonts (config))
- {
- FcConfigDestroy (config);
- return 0;
- }
- return config;
-}
-
-/*
- * Initialize the default library configuration
- */
-FcBool
-FcInit (void)
-{
- FcConfig *config;
-
- if (_fcConfig)
- return FcTrue;
- config = FcInitLoadConfigAndFonts ();
- if (!config)
- return FcFalse;
- FcConfigSetCurrent (config);
- if (FcDebug() & FC_DBG_MEMORY)
- FcMemReport ();
- return FcTrue;
-}
-
-/*
- * Free all library-allocated data structures.
- */
-void
-FcFini (void)
-{
- if (_fcConfig)
- FcConfigDestroy (_fcConfig);
-
- FcPatternFini ();
- FcCacheFini ();
- if (FcDebug() & FC_DBG_MEMORY)
- FcMemReport ();
-}
-
-/*
- * Reread the configuration and available font lists
- */
-FcBool
-FcInitReinitialize (void)
-{
- FcConfig *config;
-
- config = FcInitLoadConfigAndFonts ();
- if (!config)
- return FcFalse;
- FcConfigSetCurrent (config);
- return FcTrue;
-}
-
-FcBool
-FcInitBringUptoDate (void)
-{
- FcConfig *config = FcConfigGetCurrent ();
- time_t now;
-
- /*
- * rescanInterval == 0 disables automatic up to date
- */
- if (config->rescanInterval == 0)
- return FcTrue;
- /*
- * Check no more often than rescanInterval seconds
- */
- now = time (0);
- if (config->rescanTime + config->rescanInterval - now > 0)
- return FcTrue;
- /*
- * If up to date, don't reload configuration
- */
- if (FcConfigUptoDate (0))
- return FcTrue;
- return FcInitReinitialize ();
-}
-
-static struct {
- char name[16];
- int alloc_count;
- int alloc_mem;
- int free_count;
- int free_mem;
-} FcInUse[FC_MEM_NUM] = {
- { "charset" },
- { "charleaf" },
- { "fontset" },
- { "fontptr" },
- { "objectset" },
- { "objectptr" },
- { "matrix" },
- { "pattern" },
- { "patelt" },
- { "vallist" },
- { "substate" },
- { "string" },
- { "listbuck" },
- { "strset" },
- { "strlist" },
- { "config" },
- { "langset" },
- { "atomic" },
- { "blanks" },
- { "cache" },
- { "strbuf" },
- { "subst" },
- { "objecttype" },
- { "constant" },
- { "test" },
- { "expr" },
- { "vstack" },
- { "attr" },
- { "pstack" },
- { "staticstr" },
-};
-
-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 ("%16.16s%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 ("%16.16s%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 ();
- }
-}
-#define __fcinit__
-#include "fcaliastail.h"
-#undef __fcinit__
+/* + * fontconfig/src/fcinit.c + * + * Copyright © 2001 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdlib.h> + +static FcConfig * +FcInitFallbackConfig (void) +{ + FcConfig *config; + + config = FcConfigCreate (); + if (!config) + goto bail0; + if (!FcConfigAddDir (config, (FcChar8 *) FC_DEFAULT_FONTS)) + goto bail1; + if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR)) + goto bail1; + return config; + +bail1: + FcConfigDestroy (config); +bail0: + return 0; +} + +int +FcGetVersion (void) +{ + return FC_VERSION; +} + +/* + * Load the configuration files + */ +FcConfig * +FcInitLoadConfig (void) +{ + FcConfig *config; + + FcInitDebug (); + config = FcConfigCreate (); + if (!config) + return NULL; + + if (!FcConfigParseAndLoad (config, 0, FcTrue)) + { + FcConfigDestroy (config); + return FcInitFallbackConfig (); + } + + if (config->cacheDirs && config->cacheDirs->num == 0) + { + fprintf (stderr, + "Fontconfig warning: no <cachedir> elements found. Check configuration.\n"); + fprintf (stderr, + "Fontconfig warning: adding <cachedir>%s</cachedir>\n", + FC_CACHEDIR); + fprintf (stderr, + "Fontconfig warning: adding <cachedir>~/.fontconfig</cachedir>\n"); + if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR) || + !FcConfigAddCacheDir (config, (FcChar8 *) "~/.fontconfig")) + { + fprintf (stderr, + "Fontconfig error: out of memory"); + FcConfigDestroy (config); + return FcInitFallbackConfig (); + } + } + + return config; +} + +/* + * Load the configuration files and scan for available fonts + */ +FcConfig * +FcInitLoadConfigAndFonts (void) +{ + FcConfig *config = FcInitLoadConfig (); + + FcInitDebug (); + if (!config) + return 0; + if (!FcConfigBuildFonts (config)) + { + FcConfigDestroy (config); + return 0; + } + return config; +} + +/* + * Initialize the default library configuration + */ +FcBool +FcInit (void) +{ + FcConfig *config; + + if (_fcConfig) + return FcTrue; + config = FcInitLoadConfigAndFonts (); + if (!config) + return FcFalse; + FcConfigSetCurrent (config); + if (FcDebug() & FC_DBG_MEMORY) + FcMemReport (); + return FcTrue; +} + +/* + * Free all library-allocated data structures. + */ +void +FcFini (void) +{ + if (_fcConfig) + FcConfigDestroy (_fcConfig); + + FcPatternFini (); + FcCacheFini (); + if (FcDebug() & FC_DBG_MEMORY) + FcMemReport (); +} + +/* + * Reread the configuration and available font lists + */ +FcBool +FcInitReinitialize (void) +{ + FcConfig *config; + + config = FcInitLoadConfigAndFonts (); + if (!config) + return FcFalse; + FcConfigSetCurrent (config); + return FcTrue; +} + +FcBool +FcInitBringUptoDate (void) +{ + FcConfig *config = FcConfigGetCurrent (); + time_t now; + + /* + * rescanInterval == 0 disables automatic up to date + */ + if (config->rescanInterval == 0) + return FcTrue; + /* + * Check no more often than rescanInterval seconds + */ + now = time (0); + if (config->rescanTime + config->rescanInterval - now > 0) + return FcTrue; + /* + * If up to date, don't reload configuration + */ + if (FcConfigUptoDate (0)) + return FcTrue; + return FcInitReinitialize (); +} + +static struct { + char name[16]; + int alloc_count; + int alloc_mem; + int free_count; + int free_mem; +} FcInUse[FC_MEM_NUM] = { + { "charset" }, + { "charleaf" }, + { "fontset" }, + { "fontptr" }, + { "objectset" }, + { "objectptr" }, + { "matrix" }, + { "pattern" }, + { "patelt" }, + { "vallist" }, + { "substate" }, + { "string" }, + { "listbuck" }, + { "strset" }, + { "strlist" }, + { "config" }, + { "langset" }, + { "atomic" }, + { "blanks" }, + { "cache" }, + { "strbuf" }, + { "subst" }, + { "objecttype" }, + { "constant" }, + { "test" }, + { "expr" }, + { "vstack" }, + { "attr" }, + { "pstack" }, + { "staticstr" }, +}; + +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 ("%16.16s%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 ("%16.16s%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 (); + } +} +#define __fcinit__ +#include "fcaliastail.h" +#undef __fcinit__ diff --git a/fontconfig/src/fcint.h b/fontconfig/src/fcint.h index 46be99eb8..83a7a435b 100644 --- a/fontconfig/src/fcint.h +++ b/fontconfig/src/fcint.h @@ -1,1039 +1,1039 @@ -/*
- * fontconfig/src/fcint.h
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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_
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#elif defined(HAVE_STDINT_H)
-#include <stdint.h>
-#else
-#error missing C99 integer data types
-#endif
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcprivate.h>
-#include "fcdeprecate.h"
-
-#ifndef FC_CONFIG_PATH
-#define FC_CONFIG_PATH "fonts.conf"
-#endif
-
-#ifdef _WIN32
-#define FC_SEARCH_PATH_SEPARATOR ';'
-#else
-#define FC_SEARCH_PATH_SEPARATOR ':'
-#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_SCANV 256
-#define FC_DBG_MEMORY 512
-#define FC_DBG_CONFIG 1024
-#define FC_DBG_LANGSET 2048
-#define FC_DBG_OBJTYPES 4096
-
-#define FC_MEM_CHARSET 0
-#define FC_MEM_CHARLEAF 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_STRSET 13
-#define FC_MEM_STRLIST 14
-#define FC_MEM_CONFIG 15
-#define FC_MEM_LANGSET 16
-#define FC_MEM_ATOMIC 17
-#define FC_MEM_BLANKS 18
-#define FC_MEM_CACHE 19
-#define FC_MEM_STRBUF 20
-#define FC_MEM_SUBST 21
-#define FC_MEM_OBJECTTYPE 22
-#define FC_MEM_CONSTANT 23
-#define FC_MEM_TEST 24
-#define FC_MEM_EXPR 25
-#define FC_MEM_VSTACK 26
-#define FC_MEM_ATTR 27
-#define FC_MEM_PSTACK 28
-#define FC_MEM_STATICSTR 29
-
-#define FC_MEM_NUM 30
-
-#define _FC_ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
-#define _FC_ASSERT_STATIC0(_line, _cond) _FC_ASSERT_STATIC1 (_line, (_cond))
-#define FC_ASSERT_STATIC(_cond) _FC_ASSERT_STATIC0 (__LINE__, (_cond))
-
-#define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
-#define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
-#define FC_ABS(a) ((a) < 0 ? -(a) : (a))
-
-/* slim_internal.h */
-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
-#define FcPrivate __attribute__((__visibility__("hidden")))
-#define HAVE_GNUC_ATTRIBUTE 1
-#include "fcalias.h"
-#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-#define FcPrivate __hidden
-#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
-#define FcPrivate
-#endif
-
-typedef enum _FcValueBinding {
- FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame
-} FcValueBinding;
-
-/*
- * Serialized data structures use only offsets instead of pointers
- * A low bit of 1 indicates an offset.
- */
-
-/* Is the provided pointer actually an offset? */
-#define FcIsEncodedOffset(p) ((((intptr_t) (p)) & 1) != 0)
-
-/* Encode offset in a pointer of type t */
-#define FcOffsetEncode(o,t) ((t *) ((o) | 1))
-
-/* Decode a pointer into an offset */
-#define FcOffsetDecode(p) (((intptr_t) (p)) & ~1)
-
-/* Compute pointer offset */
-#define FcPtrToOffset(b,p) ((intptr_t) (p) - (intptr_t) (b))
-
-/* Given base address, offset and type, return a pointer */
-#define FcOffsetToPtr(b,o,t) ((t *) ((intptr_t) (b) + (o)))
-
-/* Given base address, encoded offset and type, return a pointer */
-#define FcEncodedOffsetToPtr(b,p,t) FcOffsetToPtr(b,FcOffsetDecode(p),t)
-
-/* Given base address, pointer and type, return an encoded offset */
-#define FcPtrToEncodedOffset(b,p,t) FcOffsetEncode(FcPtrToOffset(b,p),t)
-
-/* Given a structure, offset member and type, return pointer */
-#define FcOffsetMember(s,m,t) FcOffsetToPtr(s,(s)->m,t)
-
-/* Given a structure, encoded offset member and type, return pointer to member */
-#define FcEncodedOffsetMember(s,m,t) FcOffsetToPtr(s,FcOffsetDecode((s)->m), t)
-
-/* Given a structure, member and type, convert the member to a pointer */
-#define FcPointerMember(s,m,t) (FcIsEncodedOffset((s)->m) ? \
- FcEncodedOffsetMember (s,m,t) : \
- (s)->m)
-
-/*
- * Serialized values may hold strings, charsets and langsets as pointers,
- * unfortunately FcValue is an exposed type so we can't just always use
- * offsets
- */
-#define FcValueString(v) FcPointerMember(v,u.s,FcChar8)
-#define FcValueCharSet(v) FcPointerMember(v,u.c,const FcCharSet)
-#define FcValueLangSet(v) FcPointerMember(v,u.l,const FcLangSet)
-
-typedef struct _FcValueList *FcValueListPtr;
-
-typedef struct _FcValueList {
- struct _FcValueList *next;
- FcValue value;
- FcValueBinding binding;
-} FcValueList;
-
-#define FcValueListNext(vl) FcPointerMember(vl,next,FcValueList)
-
-typedef int FcObject;
-
-typedef struct _FcPatternElt *FcPatternEltPtr;
-
-/*
- * Pattern elts are stuck in a structure connected to the pattern,
- * so they get moved around when the pattern is resized. Hence, the
- * values field must be a pointer/offset instead of just an offset
- */
-typedef struct _FcPatternElt {
- FcObject object;
- FcValueList *values;
-} FcPatternElt;
-
-#define FcPatternEltValues(pe) FcPointerMember(pe,values,FcValueList)
-
-struct _FcPattern {
- int num;
- int size;
- intptr_t elts_offset;
- int ref;
-};
-
-#define FcPatternElts(p) FcOffsetMember(p,elts_offset,FcPatternElt)
-
-#define FcFontSetFonts(fs) FcPointerMember(fs,fonts,FcPattern *)
-
-#define FcFontSetFont(fs,i) (FcIsEncodedOffset((fs)->fonts) ? \
- FcEncodedOffsetToPtr(fs, \
- FcFontSetFonts(fs)[i], \
- FcPattern) : \
- fs->fonts[i])
-
-typedef enum _FcOp {
- FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpRange, FcOpBool, FcOpCharSet, FcOpLangSet,
- FcOpNil,
- FcOpField, FcOpConst,
- FcOpAssign, FcOpAssignReplace,
- FcOpPrependFirst, FcOpPrepend, FcOpAppend, FcOpAppendLast,
- FcOpQuest,
- FcOpOr, FcOpAnd, FcOpEqual, FcOpNotEqual,
- FcOpContains, FcOpListing, FcOpNotContains,
- FcOpLess, FcOpLessEqual, FcOpMore, FcOpMoreEqual,
- FcOpPlus, FcOpMinus, FcOpTimes, FcOpDivide,
- FcOpNot, FcOpComma, FcOpFloor, FcOpCeil, FcOpRound, FcOpTrunc,
- FcOpInvalid
-} FcOp;
-
-typedef struct _FcExpr {
- FcOp op;
- union {
- int ival;
- double dval;
- const FcChar8 *sval;
- FcMatrix *mval;
- FcBool bval;
- FcCharSet *cval;
- FcLangSet *lval;
- FcObject object;
- const FcChar8 *constant;
- struct {
- struct _FcExpr *left, *right;
- } tree;
- } u;
-} FcExpr;
-
-typedef struct _FcExprPage FcExprPage;
-
-struct _FcExprPage {
- FcExprPage *next_page;
- FcExpr *next;
- FcExpr exprs[(1024 - 2/* two pointers */ - 2/* malloc overhead */) * sizeof (void *) / sizeof (FcExpr)];
- FcExpr end[];
-};
-
-typedef enum _FcQual {
- FcQualAny, FcQualAll, FcQualFirst, FcQualNotFirst
-} FcQual;
-
-#define FcMatchDefault ((FcMatchKind) -1)
-
-typedef struct _FcTest {
- struct _FcTest *next;
- FcMatchKind kind;
- FcQual qual;
- FcObject object;
- FcOp op;
- FcExpr *expr;
-} FcTest;
-
-typedef struct _FcEdit {
- struct _FcEdit *next;
- FcObject object;
- FcOp op;
- FcExpr *expr;
- FcValueBinding binding;
-} FcEdit;
-
-typedef struct _FcSubst {
- struct _FcSubst *next;
- FcTest *test;
- FcEdit *edit;
-} FcSubst;
-
-typedef struct _FcCharLeaf {
- FcChar32 map[256/32];
-} FcCharLeaf;
-
-#define FC_REF_CONSTANT -1
-
-struct _FcCharSet {
- int ref; /* reference count */
- int num; /* size of leaves and numbers arrays */
- intptr_t leaves_offset;
- intptr_t numbers_offset;
-};
-
-#define FcCharSetLeaves(c) FcOffsetMember(c,leaves_offset,intptr_t)
-#define FcCharSetLeaf(c,i) (FcOffsetToPtr(FcCharSetLeaves(c), \
- FcCharSetLeaves(c)[i], \
- FcCharLeaf))
-#define FcCharSetNumbers(c) FcOffsetMember(c,numbers_offset,FcChar16)
-
-struct _FcStrSet {
- int ref; /* reference count */
- int num;
- int size;
- FcChar8 **strs;
-};
-
-struct _FcStrList {
- FcStrSet *set;
- int n;
-};
-
-typedef struct _FcStrBuf {
- FcChar8 *buf;
- FcBool allocated;
- FcBool failed;
- int len;
- int size;
- FcChar8 buf_static[16 * sizeof (void *)];
-} FcStrBuf;
-
-struct _FcCache {
- int magic; /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */
- int version; /* FC_CACHE_CONTENT_VERSION */
- intptr_t size; /* size of file */
- intptr_t dir; /* offset to dir name */
- intptr_t dirs; /* offset to subdirs */
- int dirs_count; /* number of subdir strings */
- intptr_t set; /* offset to font set */
- int mtime; /* low bits of directory mtime */
-};
-
-#undef FcCacheDir
-#undef FcCacheSubdir
-#define FcCacheDir(c) FcOffsetMember(c,dir,FcChar8)
-#define FcCacheDirs(c) FcOffsetMember(c,dirs,intptr_t)
-#define FcCacheSet(c) FcOffsetMember(c,set,FcFontSet)
-#define FcCacheSubdir(c,i) FcOffsetToPtr (FcCacheDirs(c),\
- FcCacheDirs(c)[i], \
- FcChar8)
-
-/*
- * Used while constructing a directory cache object
- */
-
-#define FC_SERIALIZE_HASH_SIZE 8191
-
-typedef union _FcAlign {
- double d;
- int i;
- intptr_t ip;
- FcBool b;
- void *p;
-} FcAlign;
-
-typedef struct _FcSerializeBucket {
- struct _FcSerializeBucket *next;
- const void *object;
- intptr_t offset;
-} FcSerializeBucket;
-
-typedef struct _FcCharSetFreezer FcCharSetFreezer;
-
-typedef struct _FcSerialize {
- intptr_t size;
- FcCharSetFreezer *cs_freezer;
- void *linear;
- FcSerializeBucket *buckets[FC_SERIALIZE_HASH_SIZE];
-} FcSerialize;
-
-/*
- * To map adobe glyph names to unicode values, a precomputed hash
- * table is used
- */
-
-typedef struct _FcGlyphName {
- FcChar32 ucs; /* unicode value */
- FcChar8 name[1]; /* name extends beyond struct */
-} FcGlyphName;
-
-/*
- * To perform case-insensitive string comparisons, a table
- * is used which holds three different kinds of folding data.
- *
- * The first is a range of upper case values mapping to a range
- * of their lower case equivalents. Within each range, the offset
- * between upper and lower case is constant.
- *
- * The second is a range of upper case values which are interleaved
- * with their lower case equivalents.
- *
- * The third is a set of raw unicode values mapping to a list
- * of unicode values for comparison purposes. This allows conversion
- * of ß to "ss" so that SS, ss and ß all match. A separate array
- * holds the list of unicode values for each entry.
- *
- * These are packed into a single table. Using a binary search,
- * the appropriate entry can be located.
- */
-
-#define FC_CASE_FOLD_RANGE 0
-#define FC_CASE_FOLD_EVEN_ODD 1
-#define FC_CASE_FOLD_FULL 2
-
-typedef struct _FcCaseFold {
- FcChar32 upper;
- FcChar16 method : 2;
- FcChar16 count : 14;
- short offset; /* lower - upper for RANGE, table id for FULL */
-} FcCaseFold;
-
-#define FC_MAX_FILE_LEN 4096
-
-#define FC_CACHE_MAGIC_MMAP 0xFC02FC04
-#define FC_CACHE_MAGIC_ALLOC 0xFC02FC05
-#define FC_CACHE_CONTENT_VERSION 3 /* also check FC_CACHE_VERSION */
-
-struct _FcAtomic {
- FcChar8 *file; /* original file name */
- FcChar8 *new; /* temp file name -- write data here */
- FcChar8 *lck; /* lockfile name (used for locking) */
- FcChar8 *tmp; /* tmpfile name (used for locking) */
-};
-
-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
- */
- FcStrSet *configDirs; /* directories to scan for fonts */
- /*
- * Set of allowed blank chars -- used to
- * trim fonts of bogus glyphs
- */
- FcBlanks *blanks;
- /*
- * List of directories containing fonts,
- * built by recursively scanning the set
- * of configured directories
- */
- FcStrSet *fontDirs;
- /*
- * List of directories containing cache files.
- */
- FcStrSet *cacheDirs;
- /*
- * Names of all of the configuration files used
- * to create this configuration
- */
- FcStrSet *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 */
- FcSubst *substScan; /* substitutions for scanned fonts */
- int maxObjects; /* maximum number of tests in all substs */
- /*
- * List of patterns used to control font file selection
- */
- FcStrSet *acceptGlobs;
- FcStrSet *rejectGlobs;
- FcFontSet *acceptPatterns;
- FcFontSet *rejectPatterns;
- /*
- * 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];
- /*
- * Fontconfig can periodically rescan the system configuration
- * and font directories. This rescanning occurs when font
- * listing requests are made, but no more often than rescanInterval
- * seconds apart.
- */
- time_t rescanTime; /* last time information was scanned */
- int rescanInterval; /* interval between scans */
-
- int ref; /* reference count */
-
- FcExprPage *expr_pool; /* pool of FcExpr's */
-};
-
-extern FcPrivate FcConfig *_fcConfig;
-
-typedef struct _FcFileTime {
- time_t time;
- FcBool set;
-} FcFileTime;
-
-typedef struct _FcCharMap FcCharMap;
-
-typedef struct _FcRange FcRange;
-
-struct _FcRange {
- FcChar32 begin;
- FcChar32 end;
-};
-
-/* fcblanks.c */
-
-/* fccache.c */
-
-FcPrivate FcCache *
-FcDirCacheScan (const FcChar8 *dir, FcConfig *config);
-
-FcPrivate FcCache *
-FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs);
-
-FcPrivate FcBool
-FcDirCacheWrite (FcCache *cache, FcConfig *config);
-
-FcPrivate void
-FcCacheObjectReference (void *object);
-
-FcPrivate void
-FcCacheObjectDereference (void *object);
-
-FcPrivate void
-FcCacheFini (void);
-
-FcPrivate void
-FcDirCacheReference (FcCache *cache, int nref);
-
-FcPrivate int
-FcStat (const char *file, struct stat *statb);
-
-/* fccfg.c */
-
-FcPrivate FcExpr *
-FcConfigAllocExpr (FcConfig *config);
-
-FcPrivate FcBool
-FcConfigAddConfigDir (FcConfig *config,
- const FcChar8 *d);
-
-FcPrivate FcBool
-FcConfigAddFontDir (FcConfig *config,
- const FcChar8 *d);
-
-FcPrivate FcBool
-FcConfigAddDir (FcConfig *config,
- const FcChar8 *d);
-
-FcPrivate FcBool
-FcConfigAddCacheDir (FcConfig *config,
- const FcChar8 *d);
-
-FcPrivate FcBool
-FcConfigAddConfigFile (FcConfig *config,
- const FcChar8 *f);
-
-FcPrivate FcBool
-FcConfigAddBlank (FcConfig *config,
- FcChar32 blank);
-
-FcPrivate FcBool
-FcConfigAddEdit (FcConfig *config,
- FcTest *test,
- FcEdit *edit,
- FcMatchKind kind);
-
-FcPrivate void
-FcConfigSetFonts (FcConfig *config,
- FcFontSet *fonts,
- FcSetName set);
-
-FcPrivate FcBool
-FcConfigCompareValue (const FcValue *m,
- FcOp op,
- const FcValue *v);
-
-FcPrivate FcBool
-FcConfigGlobAdd (FcConfig *config,
- const FcChar8 *glob,
- FcBool accept);
-
-FcPrivate FcBool
-FcConfigAcceptFilename (FcConfig *config,
- const FcChar8 *filename);
-
-FcPrivate FcBool
-FcConfigPatternsAdd (FcConfig *config,
- FcPattern *pattern,
- FcBool accept);
-
-FcPrivate FcBool
-FcConfigAcceptFont (FcConfig *config,
- const FcPattern *font);
-
-FcPrivate FcFileTime
-FcConfigModifiedTime (FcConfig *config);
-
-FcPrivate FcBool
-FcConfigAddCache (FcConfig *config, FcCache *cache,
- FcSetName set, FcStrSet *dirSet);
-
-/* fcserialize.c */
-FcPrivate intptr_t
-FcAlignSize (intptr_t size);
-
-FcPrivate FcSerialize *
-FcSerializeCreate (void);
-
-FcPrivate void
-FcSerializeDestroy (FcSerialize *serialize);
-
-FcPrivate FcBool
-FcSerializeAlloc (FcSerialize *serialize, const void *object, int size);
-
-FcPrivate intptr_t
-FcSerializeReserve (FcSerialize *serialize, int size);
-
-FcPrivate intptr_t
-FcSerializeOffset (FcSerialize *serialize, const void *object);
-
-FcPrivate void *
-FcSerializePtr (FcSerialize *serialize, const void *object);
-
-FcPrivate FcBool
-FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l);
-
-FcPrivate FcLangSet *
-FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l);
-
-/* fccharset.c */
-FcPrivate void
-FcLangCharSetPopulate (void);
-
-FcPrivate FcCharSetFreezer *
-FcCharSetFreezerCreate (void);
-
-FcPrivate const FcCharSet *
-FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs);
-
-FcPrivate void
-FcCharSetFreezerDestroy (FcCharSetFreezer *freezer);
-
-FcPrivate FcBool
-FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c);
-
-FcPrivate FcCharSet *
-FcNameParseCharSet (FcChar8 *string);
-
-FcPrivate FcBool
-FcNameUnparseValue (FcStrBuf *buf,
- FcValue *v0,
- FcChar8 *escape);
-
-FcPrivate FcBool
-FcNameUnparseValueList (FcStrBuf *buf,
- FcValueListPtr v,
- FcChar8 *escape);
-
-FcPrivate FcCharLeaf *
-FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4);
-
-FcPrivate FcBool
-FcCharSetSerializeAlloc(FcSerialize *serialize, const FcCharSet *cs);
-
-FcPrivate FcCharSet *
-FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs);
-
-FcPrivate FcChar16 *
-FcCharSetGetNumbers(const FcCharSet *c);
-
-/* fcdbg.c */
-FcPrivate void
-FcValueListPrint (const FcValueListPtr l);
-
-FcPrivate void
-FcLangSetPrint (const FcLangSet *ls);
-
-FcPrivate void
-FcOpPrint (FcOp op);
-
-FcPrivate void
-FcTestPrint (const FcTest *test);
-
-FcPrivate void
-FcExprPrint (const FcExpr *expr);
-
-FcPrivate void
-FcEditPrint (const FcEdit *edit);
-
-FcPrivate void
-FcSubstPrint (const FcSubst *subst);
-
-FcPrivate void
-FcCharSetPrint (const FcCharSet *c);
-
-extern FcPrivate int FcDebugVal;
-
-#define FcDebug() (FcDebugVal)
-
-FcPrivate void
-FcInitDebug (void);
-
-/* fcdefault.c */
-FcPrivate FcChar8 *
-FcGetDefaultLang (void);
-
-/* fcdir.c */
-
-FcPrivate FcBool
-FcFileScanConfig (FcFontSet *set,
- FcStrSet *dirs,
- FcBlanks *blanks,
- const FcChar8 *file,
- FcConfig *config);
-
-FcPrivate FcBool
-FcDirScanConfig (FcFontSet *set,
- FcStrSet *dirs,
- FcBlanks *blanks,
- const FcChar8 *dir,
- FcBool force,
- FcConfig *config);
-
-/* fcfont.c */
-FcPrivate int
-FcFontDebug (void);
-
-/* fcfs.c */
-
-FcPrivate FcBool
-FcFontSetSerializeAlloc (FcSerialize *serialize, const FcFontSet *s);
-
-FcPrivate FcFontSet *
-FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s);
-
-/* fcxml.c */
-FcPrivate void
-FcTestDestroy (FcTest *test);
-
-FcPrivate void
-FcEditDestroy (FcEdit *e);
-
-/* fcinit.c */
-
-FcPrivate void
-FcMemReport (void);
-
-FcPrivate void
-FcMemAlloc (int kind, int size);
-
-FcPrivate void
-FcMemFree (int kind, int size);
-
-/* fclang.c */
-FcPrivate FcLangSet *
-FcFreeTypeLangSet (const FcCharSet *charset,
- const FcChar8 *exclusiveLang);
-
-FcPrivate FcLangResult
-FcLangCompare (const FcChar8 *s1, const FcChar8 *s2);
-
-FcPrivate FcLangSet *
-FcLangSetPromote (const FcChar8 *lang);
-
-FcPrivate FcLangSet *
-FcNameParseLangSet (const FcChar8 *string);
-
-FcPrivate FcBool
-FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls);
-
-FcPrivate FcChar8 *
-FcNameUnparseEscaped (FcPattern *pat, FcBool escape);
-
-/* fclist.c */
-
-FcPrivate FcBool
-FcListPatternMatchAny (const FcPattern *p,
- const FcPattern *font);
-
-/* fcmatch.c */
-
-/* fcname.c */
-
-/*
- * NOTE -- this ordering is part of the cache file format.
- * It must also match the ordering in fcname.c
- */
-
-#define FC_FAMILY_OBJECT 1
-#define FC_FAMILYLANG_OBJECT 2
-#define FC_STYLE_OBJECT 3
-#define FC_STYLELANG_OBJECT 4
-#define FC_FULLNAME_OBJECT 5
-#define FC_FULLNAMELANG_OBJECT 6
-#define FC_SLANT_OBJECT 7
-#define FC_WEIGHT_OBJECT 8
-#define FC_WIDTH_OBJECT 9
-#define FC_SIZE_OBJECT 10
-#define FC_ASPECT_OBJECT 11
-#define FC_PIXEL_SIZE_OBJECT 12
-#define FC_SPACING_OBJECT 13
-#define FC_FOUNDRY_OBJECT 14
-#define FC_ANTIALIAS_OBJECT 15
-#define FC_HINT_STYLE_OBJECT 16
-#define FC_HINTING_OBJECT 17
-#define FC_VERTICAL_LAYOUT_OBJECT 18
-#define FC_AUTOHINT_OBJECT 19
-#define FC_GLOBAL_ADVANCE_OBJECT 20
-#define FC_FILE_OBJECT 21
-#define FC_INDEX_OBJECT 22
-#define FC_RASTERIZER_OBJECT 23
-#define FC_OUTLINE_OBJECT 24
-#define FC_SCALABLE_OBJECT 25
-#define FC_DPI_OBJECT 26
-#define FC_RGBA_OBJECT 27
-#define FC_SCALE_OBJECT 28
-#define FC_MINSPACE_OBJECT 29
-#define FC_CHAR_WIDTH_OBJECT 30
-#define FC_CHAR_HEIGHT_OBJECT 31
-#define FC_MATRIX_OBJECT 32
-#define FC_CHARSET_OBJECT 33
-#define FC_LANG_OBJECT 34
-#define FC_FONTVERSION_OBJECT 35
-#define FC_CAPABILITY_OBJECT 36
-#define FC_FONTFORMAT_OBJECT 37
-#define FC_EMBOLDEN_OBJECT 38
-#define FC_EMBEDDED_BITMAP_OBJECT 39
-#define FC_DECORATIVE_OBJECT 40
-#define FC_LCD_FILTER_OBJECT 41
-#define FC_MAX_BASE_OBJECT FC_LCD_FILTER_OBJECT
-
-FcPrivate FcBool
-FcNameBool (const FcChar8 *v, FcBool *result);
-
-FcPrivate FcBool
-FcObjectValidType (FcObject object, FcType type);
-
-FcPrivate FcObject
-FcObjectFromName (const char * name);
-
-FcPrivate const char *
-FcObjectName (FcObject object);
-
-FcPrivate FcObjectSet *
-FcObjectGetSet (void);
-
-FcPrivate FcBool
-FcObjectInit (void);
-
-FcPrivate void
-FcObjectFini (void);
-
-#define FcObjectCompare(a, b) ((int) a - (int) b)
-
-/* fcpat.c */
-
-FcPrivate FcValue
-FcValueCanonicalize (const FcValue *v);
-
-FcPrivate void
-FcValueListDestroy (FcValueListPtr l);
-
-FcPrivate FcPatternElt *
-FcPatternObjectFindElt (const FcPattern *p, FcObject object);
-
-FcPrivate FcPatternElt *
-FcPatternObjectInsertElt (FcPattern *p, FcObject object);
-
-FcPrivate FcBool
-FcPatternObjectAddWithBinding (FcPattern *p,
- FcObject object,
- FcValue value,
- FcValueBinding binding,
- FcBool append);
-
-FcPrivate FcBool
-FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append);
-
-FcPrivate FcBool
-FcPatternObjectAddWeak (FcPattern *p, FcObject object, FcValue value, FcBool append);
-
-FcPrivate FcResult
-FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v);
-
-FcPrivate FcBool
-FcPatternObjectDel (FcPattern *p, FcObject object);
-
-FcPrivate FcBool
-FcPatternObjectRemove (FcPattern *p, FcObject object, int id);
-
-FcPrivate FcBool
-FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i);
-
-FcPrivate FcBool
-FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d);
-
-FcPrivate FcBool
-FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s);
-
-FcPrivate FcBool
-FcPatternObjectAddMatrix (FcPattern *p, FcObject object, const FcMatrix *s);
-
-FcPrivate FcBool
-FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c);
-
-FcPrivate FcBool
-FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b);
-
-FcPrivate FcBool
-FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls);
-
-FcPrivate FcResult
-FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int n, int *i);
-
-FcPrivate FcResult
-FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int n, double *d);
-
-FcPrivate FcResult
-FcPatternObjectGetString (const FcPattern *p, FcObject object, int n, FcChar8 ** s);
-
-FcPrivate FcResult
-FcPatternObjectGetMatrix (const FcPattern *p, FcObject object, int n, FcMatrix **s);
-
-FcPrivate FcResult
-FcPatternObjectGetCharSet (const FcPattern *p, FcObject object, int n, FcCharSet **c);
-
-FcPrivate FcResult
-FcPatternObjectGetBool (const FcPattern *p, FcObject object, int n, FcBool *b);
-
-FcPrivate FcResult
-FcPatternObjectGetLangSet (const FcPattern *p, FcObject object, int n, FcLangSet **ls);
-
-FcPrivate void
-FcPatternFini (void);
-
-FcPrivate FcBool
-FcPatternAppend (FcPattern *p, FcPattern *s);
-
-FcPrivate const FcChar8 *
-FcStrStaticName (const FcChar8 *name);
-
-FcPrivate FcChar32
-FcStringHash (const FcChar8 *s);
-
-FcPrivate FcBool
-FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat);
-
-FcPrivate FcPattern *
-FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat);
-
-FcPrivate FcBool
-FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *pat);
-
-FcPrivate FcValueList *
-FcValueListSerialize (FcSerialize *serialize, const FcValueList *pat);
-
-/* fcrender.c */
-
-/* fcmatrix.c */
-
-extern FcPrivate const FcMatrix FcIdentityMatrix;
-
-FcPrivate void
-FcMatrixFree (FcMatrix *mat);
-
-/* fcstr.c */
-FcPrivate void
-FcStrSetSort (FcStrSet * set);
-
-FcPrivate void
-FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size);
-
-FcPrivate void
-FcStrBufDestroy (FcStrBuf *buf);
-
-FcPrivate FcChar8 *
-FcStrBufDone (FcStrBuf *buf);
-
-FcPrivate FcChar8 *
-FcStrBufDoneStatic (FcStrBuf *buf);
-
-FcPrivate FcBool
-FcStrBufChar (FcStrBuf *buf, FcChar8 c);
-
-FcPrivate FcBool
-FcStrBufString (FcStrBuf *buf, const FcChar8 *s);
-
-FcPrivate FcBool
-FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len);
-
-FcPrivate int
-FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2);
-
-FcPrivate const FcChar8 *
-FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2);
-
-FcPrivate const FcChar8 *
-FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2);
-
-FcPrivate const FcChar8 *
-FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2);
-
-FcPrivate FcBool
-FcStrUsesHome (const FcChar8 *s);
-
-FcPrivate FcChar8 *
-FcStrLastSlash (const FcChar8 *path);
-
-FcPrivate FcChar32
-FcStrHashIgnoreCase (const FcChar8 *s);
-
-FcPrivate FcChar8 *
-FcStrCanonFilename (const FcChar8 *s);
-
-FcPrivate FcBool
-FcStrSerializeAlloc (FcSerialize *serialize, const FcChar8 *str);
-
-FcPrivate FcChar8 *
-FcStrSerialize (FcSerialize *serialize, const FcChar8 *str);
-
-#endif /* _FC_INT_H_ */
+/* + * fontconfig/src/fcint.h + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#elif defined(HAVE_STDINT_H) +#include <stdint.h> +#else +#error missing C99 integer data types +#endif +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <fontconfig/fontconfig.h> +#include <fontconfig/fcprivate.h> +#include "fcdeprecate.h" + +#ifndef FC_CONFIG_PATH +#define FC_CONFIG_PATH "fonts.conf" +#endif + +#ifdef _WIN32 +#define FC_SEARCH_PATH_SEPARATOR ';' +#else +#define FC_SEARCH_PATH_SEPARATOR ':' +#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_SCANV 256 +#define FC_DBG_MEMORY 512 +#define FC_DBG_CONFIG 1024 +#define FC_DBG_LANGSET 2048 +#define FC_DBG_OBJTYPES 4096 + +#define FC_MEM_CHARSET 0 +#define FC_MEM_CHARLEAF 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_STRSET 13 +#define FC_MEM_STRLIST 14 +#define FC_MEM_CONFIG 15 +#define FC_MEM_LANGSET 16 +#define FC_MEM_ATOMIC 17 +#define FC_MEM_BLANKS 18 +#define FC_MEM_CACHE 19 +#define FC_MEM_STRBUF 20 +#define FC_MEM_SUBST 21 +#define FC_MEM_OBJECTTYPE 22 +#define FC_MEM_CONSTANT 23 +#define FC_MEM_TEST 24 +#define FC_MEM_EXPR 25 +#define FC_MEM_VSTACK 26 +#define FC_MEM_ATTR 27 +#define FC_MEM_PSTACK 28 +#define FC_MEM_STATICSTR 29 + +#define FC_MEM_NUM 30 + +#define _FC_ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] +#define _FC_ASSERT_STATIC0(_line, _cond) _FC_ASSERT_STATIC1 (_line, (_cond)) +#define FC_ASSERT_STATIC(_cond) _FC_ASSERT_STATIC0 (__LINE__, (_cond)) + +#define FC_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define FC_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define FC_ABS(a) ((a) < 0 ? -(a) : (a)) + +/* slim_internal.h */ +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) +#define FcPrivate __attribute__((__visibility__("hidden"))) +#define HAVE_GNUC_ATTRIBUTE 1 +#include "fcalias.h" +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +#define FcPrivate __hidden +#else /* not gcc >= 3.3 and not Sun Studio >= 8 */ +#define FcPrivate +#endif + +typedef enum _FcValueBinding { + FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame +} FcValueBinding; + +/* + * Serialized data structures use only offsets instead of pointers + * A low bit of 1 indicates an offset. + */ + +/* Is the provided pointer actually an offset? */ +#define FcIsEncodedOffset(p) ((((intptr_t) (p)) & 1) != 0) + +/* Encode offset in a pointer of type t */ +#define FcOffsetEncode(o,t) ((t *) ((o) | 1)) + +/* Decode a pointer into an offset */ +#define FcOffsetDecode(p) (((intptr_t) (p)) & ~1) + +/* Compute pointer offset */ +#define FcPtrToOffset(b,p) ((intptr_t) (p) - (intptr_t) (b)) + +/* Given base address, offset and type, return a pointer */ +#define FcOffsetToPtr(b,o,t) ((t *) ((intptr_t) (b) + (o))) + +/* Given base address, encoded offset and type, return a pointer */ +#define FcEncodedOffsetToPtr(b,p,t) FcOffsetToPtr(b,FcOffsetDecode(p),t) + +/* Given base address, pointer and type, return an encoded offset */ +#define FcPtrToEncodedOffset(b,p,t) FcOffsetEncode(FcPtrToOffset(b,p),t) + +/* Given a structure, offset member and type, return pointer */ +#define FcOffsetMember(s,m,t) FcOffsetToPtr(s,(s)->m,t) + +/* Given a structure, encoded offset member and type, return pointer to member */ +#define FcEncodedOffsetMember(s,m,t) FcOffsetToPtr(s,FcOffsetDecode((s)->m), t) + +/* Given a structure, member and type, convert the member to a pointer */ +#define FcPointerMember(s,m,t) (FcIsEncodedOffset((s)->m) ? \ + FcEncodedOffsetMember (s,m,t) : \ + (s)->m) + +/* + * Serialized values may hold strings, charsets and langsets as pointers, + * unfortunately FcValue is an exposed type so we can't just always use + * offsets + */ +#define FcValueString(v) FcPointerMember(v,u.s,FcChar8) +#define FcValueCharSet(v) FcPointerMember(v,u.c,const FcCharSet) +#define FcValueLangSet(v) FcPointerMember(v,u.l,const FcLangSet) + +typedef struct _FcValueList *FcValueListPtr; + +typedef struct _FcValueList { + struct _FcValueList *next; + FcValue value; + FcValueBinding binding; +} FcValueList; + +#define FcValueListNext(vl) FcPointerMember(vl,next,FcValueList) + +typedef int FcObject; + +typedef struct _FcPatternElt *FcPatternEltPtr; + +/* + * Pattern elts are stuck in a structure connected to the pattern, + * so they get moved around when the pattern is resized. Hence, the + * values field must be a pointer/offset instead of just an offset + */ +typedef struct _FcPatternElt { + FcObject object; + FcValueList *values; +} FcPatternElt; + +#define FcPatternEltValues(pe) FcPointerMember(pe,values,FcValueList) + +struct _FcPattern { + int num; + int size; + intptr_t elts_offset; + int ref; +}; + +#define FcPatternElts(p) FcOffsetMember(p,elts_offset,FcPatternElt) + +#define FcFontSetFonts(fs) FcPointerMember(fs,fonts,FcPattern *) + +#define FcFontSetFont(fs,i) (FcIsEncodedOffset((fs)->fonts) ? \ + FcEncodedOffsetToPtr(fs, \ + FcFontSetFonts(fs)[i], \ + FcPattern) : \ + fs->fonts[i]) + +typedef enum _FcOp { + FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpRange, FcOpBool, FcOpCharSet, FcOpLangSet, + FcOpNil, + FcOpField, FcOpConst, + FcOpAssign, FcOpAssignReplace, + FcOpPrependFirst, FcOpPrepend, FcOpAppend, FcOpAppendLast, + FcOpQuest, + FcOpOr, FcOpAnd, FcOpEqual, FcOpNotEqual, + FcOpContains, FcOpListing, FcOpNotContains, + FcOpLess, FcOpLessEqual, FcOpMore, FcOpMoreEqual, + FcOpPlus, FcOpMinus, FcOpTimes, FcOpDivide, + FcOpNot, FcOpComma, FcOpFloor, FcOpCeil, FcOpRound, FcOpTrunc, + FcOpInvalid +} FcOp; + +typedef struct _FcExpr { + FcOp op; + union { + int ival; + double dval; + const FcChar8 *sval; + FcMatrix *mval; + FcBool bval; + FcCharSet *cval; + FcLangSet *lval; + FcObject object; + const FcChar8 *constant; + struct { + struct _FcExpr *left, *right; + } tree; + } u; +} FcExpr; + +typedef struct _FcExprPage FcExprPage; + +struct _FcExprPage { + FcExprPage *next_page; + FcExpr *next; + FcExpr exprs[(1024 - 2/* two pointers */ - 2/* malloc overhead */) * sizeof (void *) / sizeof (FcExpr)]; + FcExpr end[]; +}; + +typedef enum _FcQual { + FcQualAny, FcQualAll, FcQualFirst, FcQualNotFirst +} FcQual; + +#define FcMatchDefault ((FcMatchKind) -1) + +typedef struct _FcTest { + struct _FcTest *next; + FcMatchKind kind; + FcQual qual; + FcObject object; + FcOp op; + FcExpr *expr; +} FcTest; + +typedef struct _FcEdit { + struct _FcEdit *next; + FcObject object; + FcOp op; + FcExpr *expr; + FcValueBinding binding; +} FcEdit; + +typedef struct _FcSubst { + struct _FcSubst *next; + FcTest *test; + FcEdit *edit; +} FcSubst; + +typedef struct _FcCharLeaf { + FcChar32 map[256/32]; +} FcCharLeaf; + +#define FC_REF_CONSTANT -1 + +struct _FcCharSet { + int ref; /* reference count */ + int num; /* size of leaves and numbers arrays */ + intptr_t leaves_offset; + intptr_t numbers_offset; +}; + +#define FcCharSetLeaves(c) FcOffsetMember(c,leaves_offset,intptr_t) +#define FcCharSetLeaf(c,i) (FcOffsetToPtr(FcCharSetLeaves(c), \ + FcCharSetLeaves(c)[i], \ + FcCharLeaf)) +#define FcCharSetNumbers(c) FcOffsetMember(c,numbers_offset,FcChar16) + +struct _FcStrSet { + int ref; /* reference count */ + int num; + int size; + FcChar8 **strs; +}; + +struct _FcStrList { + FcStrSet *set; + int n; +}; + +typedef struct _FcStrBuf { + FcChar8 *buf; + FcBool allocated; + FcBool failed; + int len; + int size; + FcChar8 buf_static[16 * sizeof (void *)]; +} FcStrBuf; + +struct _FcCache { + int magic; /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */ + int version; /* FC_CACHE_CONTENT_VERSION */ + intptr_t size; /* size of file */ + intptr_t dir; /* offset to dir name */ + intptr_t dirs; /* offset to subdirs */ + int dirs_count; /* number of subdir strings */ + intptr_t set; /* offset to font set */ + int mtime; /* low bits of directory mtime */ +}; + +#undef FcCacheDir +#undef FcCacheSubdir +#define FcCacheDir(c) FcOffsetMember(c,dir,FcChar8) +#define FcCacheDirs(c) FcOffsetMember(c,dirs,intptr_t) +#define FcCacheSet(c) FcOffsetMember(c,set,FcFontSet) +#define FcCacheSubdir(c,i) FcOffsetToPtr (FcCacheDirs(c),\ + FcCacheDirs(c)[i], \ + FcChar8) + +/* + * Used while constructing a directory cache object + */ + +#define FC_SERIALIZE_HASH_SIZE 8191 + +typedef union _FcAlign { + double d; + int i; + intptr_t ip; + FcBool b; + void *p; +} FcAlign; + +typedef struct _FcSerializeBucket { + struct _FcSerializeBucket *next; + const void *object; + intptr_t offset; +} FcSerializeBucket; + +typedef struct _FcCharSetFreezer FcCharSetFreezer; + +typedef struct _FcSerialize { + intptr_t size; + FcCharSetFreezer *cs_freezer; + void *linear; + FcSerializeBucket *buckets[FC_SERIALIZE_HASH_SIZE]; +} FcSerialize; + +/* + * To map adobe glyph names to unicode values, a precomputed hash + * table is used + */ + +typedef struct _FcGlyphName { + FcChar32 ucs; /* unicode value */ + FcChar8 name[1]; /* name extends beyond struct */ +} FcGlyphName; + +/* + * To perform case-insensitive string comparisons, a table + * is used which holds three different kinds of folding data. + * + * The first is a range of upper case values mapping to a range + * of their lower case equivalents. Within each range, the offset + * between upper and lower case is constant. + * + * The second is a range of upper case values which are interleaved + * with their lower case equivalents. + * + * The third is a set of raw unicode values mapping to a list + * of unicode values for comparison purposes. This allows conversion + * of ß to "ss" so that SS, ss and ß all match. A separate array + * holds the list of unicode values for each entry. + * + * These are packed into a single table. Using a binary search, + * the appropriate entry can be located. + */ + +#define FC_CASE_FOLD_RANGE 0 +#define FC_CASE_FOLD_EVEN_ODD 1 +#define FC_CASE_FOLD_FULL 2 + +typedef struct _FcCaseFold { + FcChar32 upper; + FcChar16 method : 2; + FcChar16 count : 14; + short offset; /* lower - upper for RANGE, table id for FULL */ +} FcCaseFold; + +#define FC_MAX_FILE_LEN 4096 + +#define FC_CACHE_MAGIC_MMAP 0xFC02FC04 +#define FC_CACHE_MAGIC_ALLOC 0xFC02FC05 +#define FC_CACHE_CONTENT_VERSION 3 /* also check FC_CACHE_VERSION */ + +struct _FcAtomic { + FcChar8 *file; /* original file name */ + FcChar8 *new; /* temp file name -- write data here */ + FcChar8 *lck; /* lockfile name (used for locking) */ + FcChar8 *tmp; /* tmpfile name (used for locking) */ +}; + +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 + */ + FcStrSet *configDirs; /* directories to scan for fonts */ + /* + * Set of allowed blank chars -- used to + * trim fonts of bogus glyphs + */ + FcBlanks *blanks; + /* + * List of directories containing fonts, + * built by recursively scanning the set + * of configured directories + */ + FcStrSet *fontDirs; + /* + * List of directories containing cache files. + */ + FcStrSet *cacheDirs; + /* + * Names of all of the configuration files used + * to create this configuration + */ + FcStrSet *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 */ + FcSubst *substScan; /* substitutions for scanned fonts */ + int maxObjects; /* maximum number of tests in all substs */ + /* + * List of patterns used to control font file selection + */ + FcStrSet *acceptGlobs; + FcStrSet *rejectGlobs; + FcFontSet *acceptPatterns; + FcFontSet *rejectPatterns; + /* + * 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]; + /* + * Fontconfig can periodically rescan the system configuration + * and font directories. This rescanning occurs when font + * listing requests are made, but no more often than rescanInterval + * seconds apart. + */ + time_t rescanTime; /* last time information was scanned */ + int rescanInterval; /* interval between scans */ + + int ref; /* reference count */ + + FcExprPage *expr_pool; /* pool of FcExpr's */ +}; + +extern FcPrivate FcConfig *_fcConfig; + +typedef struct _FcFileTime { + time_t time; + FcBool set; +} FcFileTime; + +typedef struct _FcCharMap FcCharMap; + +typedef struct _FcRange FcRange; + +struct _FcRange { + FcChar32 begin; + FcChar32 end; +}; + +/* fcblanks.c */ + +/* fccache.c */ + +FcPrivate FcCache * +FcDirCacheScan (const FcChar8 *dir, FcConfig *config); + +FcPrivate FcCache * +FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs); + +FcPrivate FcBool +FcDirCacheWrite (FcCache *cache, FcConfig *config); + +FcPrivate void +FcCacheObjectReference (void *object); + +FcPrivate void +FcCacheObjectDereference (void *object); + +FcPrivate void +FcCacheFini (void); + +FcPrivate void +FcDirCacheReference (FcCache *cache, int nref); + +FcPrivate int +FcStat (const char *file, struct stat *statb); + +/* fccfg.c */ + +FcPrivate FcExpr * +FcConfigAllocExpr (FcConfig *config); + +FcPrivate FcBool +FcConfigAddConfigDir (FcConfig *config, + const FcChar8 *d); + +FcPrivate FcBool +FcConfigAddFontDir (FcConfig *config, + const FcChar8 *d); + +FcPrivate FcBool +FcConfigAddDir (FcConfig *config, + const FcChar8 *d); + +FcPrivate FcBool +FcConfigAddCacheDir (FcConfig *config, + const FcChar8 *d); + +FcPrivate FcBool +FcConfigAddConfigFile (FcConfig *config, + const FcChar8 *f); + +FcPrivate FcBool +FcConfigAddBlank (FcConfig *config, + FcChar32 blank); + +FcPrivate FcBool +FcConfigAddEdit (FcConfig *config, + FcTest *test, + FcEdit *edit, + FcMatchKind kind); + +FcPrivate void +FcConfigSetFonts (FcConfig *config, + FcFontSet *fonts, + FcSetName set); + +FcPrivate FcBool +FcConfigCompareValue (const FcValue *m, + FcOp op, + const FcValue *v); + +FcPrivate FcBool +FcConfigGlobAdd (FcConfig *config, + const FcChar8 *glob, + FcBool accept); + +FcPrivate FcBool +FcConfigAcceptFilename (FcConfig *config, + const FcChar8 *filename); + +FcPrivate FcBool +FcConfigPatternsAdd (FcConfig *config, + FcPattern *pattern, + FcBool accept); + +FcPrivate FcBool +FcConfigAcceptFont (FcConfig *config, + const FcPattern *font); + +FcPrivate FcFileTime +FcConfigModifiedTime (FcConfig *config); + +FcPrivate FcBool +FcConfigAddCache (FcConfig *config, FcCache *cache, + FcSetName set, FcStrSet *dirSet); + +/* fcserialize.c */ +FcPrivate intptr_t +FcAlignSize (intptr_t size); + +FcPrivate FcSerialize * +FcSerializeCreate (void); + +FcPrivate void +FcSerializeDestroy (FcSerialize *serialize); + +FcPrivate FcBool +FcSerializeAlloc (FcSerialize *serialize, const void *object, int size); + +FcPrivate intptr_t +FcSerializeReserve (FcSerialize *serialize, int size); + +FcPrivate intptr_t +FcSerializeOffset (FcSerialize *serialize, const void *object); + +FcPrivate void * +FcSerializePtr (FcSerialize *serialize, const void *object); + +FcPrivate FcBool +FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l); + +FcPrivate FcLangSet * +FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l); + +/* fccharset.c */ +FcPrivate void +FcLangCharSetPopulate (void); + +FcPrivate FcCharSetFreezer * +FcCharSetFreezerCreate (void); + +FcPrivate const FcCharSet * +FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs); + +FcPrivate void +FcCharSetFreezerDestroy (FcCharSetFreezer *freezer); + +FcPrivate FcBool +FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c); + +FcPrivate FcCharSet * +FcNameParseCharSet (FcChar8 *string); + +FcPrivate FcBool +FcNameUnparseValue (FcStrBuf *buf, + FcValue *v0, + FcChar8 *escape); + +FcPrivate FcBool +FcNameUnparseValueList (FcStrBuf *buf, + FcValueListPtr v, + FcChar8 *escape); + +FcPrivate FcCharLeaf * +FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4); + +FcPrivate FcBool +FcCharSetSerializeAlloc(FcSerialize *serialize, const FcCharSet *cs); + +FcPrivate FcCharSet * +FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs); + +FcPrivate FcChar16 * +FcCharSetGetNumbers(const FcCharSet *c); + +/* fcdbg.c */ +FcPrivate void +FcValueListPrint (const FcValueListPtr l); + +FcPrivate void +FcLangSetPrint (const FcLangSet *ls); + +FcPrivate void +FcOpPrint (FcOp op); + +FcPrivate void +FcTestPrint (const FcTest *test); + +FcPrivate void +FcExprPrint (const FcExpr *expr); + +FcPrivate void +FcEditPrint (const FcEdit *edit); + +FcPrivate void +FcSubstPrint (const FcSubst *subst); + +FcPrivate void +FcCharSetPrint (const FcCharSet *c); + +extern FcPrivate int FcDebugVal; + +#define FcDebug() (FcDebugVal) + +FcPrivate void +FcInitDebug (void); + +/* fcdefault.c */ +FcPrivate FcChar8 * +FcGetDefaultLang (void); + +/* fcdir.c */ + +FcPrivate FcBool +FcFileScanConfig (FcFontSet *set, + FcStrSet *dirs, + FcBlanks *blanks, + const FcChar8 *file, + FcConfig *config); + +FcPrivate FcBool +FcDirScanConfig (FcFontSet *set, + FcStrSet *dirs, + FcBlanks *blanks, + const FcChar8 *dir, + FcBool force, + FcConfig *config); + +/* fcfont.c */ +FcPrivate int +FcFontDebug (void); + +/* fcfs.c */ + +FcPrivate FcBool +FcFontSetSerializeAlloc (FcSerialize *serialize, const FcFontSet *s); + +FcPrivate FcFontSet * +FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s); + +/* fcxml.c */ +FcPrivate void +FcTestDestroy (FcTest *test); + +FcPrivate void +FcEditDestroy (FcEdit *e); + +/* fcinit.c */ + +FcPrivate void +FcMemReport (void); + +FcPrivate void +FcMemAlloc (int kind, int size); + +FcPrivate void +FcMemFree (int kind, int size); + +/* fclang.c */ +FcPrivate FcLangSet * +FcFreeTypeLangSet (const FcCharSet *charset, + const FcChar8 *exclusiveLang); + +FcPrivate FcLangResult +FcLangCompare (const FcChar8 *s1, const FcChar8 *s2); + +FcPrivate FcLangSet * +FcLangSetPromote (const FcChar8 *lang); + +FcPrivate FcLangSet * +FcNameParseLangSet (const FcChar8 *string); + +FcPrivate FcBool +FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls); + +FcPrivate FcChar8 * +FcNameUnparseEscaped (FcPattern *pat, FcBool escape); + +/* fclist.c */ + +FcPrivate FcBool +FcListPatternMatchAny (const FcPattern *p, + const FcPattern *font); + +/* fcmatch.c */ + +/* fcname.c */ + +/* + * NOTE -- this ordering is part of the cache file format. + * It must also match the ordering in fcname.c + */ + +#define FC_FAMILY_OBJECT 1 +#define FC_FAMILYLANG_OBJECT 2 +#define FC_STYLE_OBJECT 3 +#define FC_STYLELANG_OBJECT 4 +#define FC_FULLNAME_OBJECT 5 +#define FC_FULLNAMELANG_OBJECT 6 +#define FC_SLANT_OBJECT 7 +#define FC_WEIGHT_OBJECT 8 +#define FC_WIDTH_OBJECT 9 +#define FC_SIZE_OBJECT 10 +#define FC_ASPECT_OBJECT 11 +#define FC_PIXEL_SIZE_OBJECT 12 +#define FC_SPACING_OBJECT 13 +#define FC_FOUNDRY_OBJECT 14 +#define FC_ANTIALIAS_OBJECT 15 +#define FC_HINT_STYLE_OBJECT 16 +#define FC_HINTING_OBJECT 17 +#define FC_VERTICAL_LAYOUT_OBJECT 18 +#define FC_AUTOHINT_OBJECT 19 +#define FC_GLOBAL_ADVANCE_OBJECT 20 +#define FC_FILE_OBJECT 21 +#define FC_INDEX_OBJECT 22 +#define FC_RASTERIZER_OBJECT 23 +#define FC_OUTLINE_OBJECT 24 +#define FC_SCALABLE_OBJECT 25 +#define FC_DPI_OBJECT 26 +#define FC_RGBA_OBJECT 27 +#define FC_SCALE_OBJECT 28 +#define FC_MINSPACE_OBJECT 29 +#define FC_CHAR_WIDTH_OBJECT 30 +#define FC_CHAR_HEIGHT_OBJECT 31 +#define FC_MATRIX_OBJECT 32 +#define FC_CHARSET_OBJECT 33 +#define FC_LANG_OBJECT 34 +#define FC_FONTVERSION_OBJECT 35 +#define FC_CAPABILITY_OBJECT 36 +#define FC_FONTFORMAT_OBJECT 37 +#define FC_EMBOLDEN_OBJECT 38 +#define FC_EMBEDDED_BITMAP_OBJECT 39 +#define FC_DECORATIVE_OBJECT 40 +#define FC_LCD_FILTER_OBJECT 41 +#define FC_MAX_BASE_OBJECT FC_LCD_FILTER_OBJECT + +FcPrivate FcBool +FcNameBool (const FcChar8 *v, FcBool *result); + +FcPrivate FcBool +FcObjectValidType (FcObject object, FcType type); + +FcPrivate FcObject +FcObjectFromName (const char * name); + +FcPrivate const char * +FcObjectName (FcObject object); + +FcPrivate FcObjectSet * +FcObjectGetSet (void); + +FcPrivate FcBool +FcObjectInit (void); + +FcPrivate void +FcObjectFini (void); + +#define FcObjectCompare(a, b) ((int) a - (int) b) + +/* fcpat.c */ + +FcPrivate FcValue +FcValueCanonicalize (const FcValue *v); + +FcPrivate void +FcValueListDestroy (FcValueListPtr l); + +FcPrivate FcPatternElt * +FcPatternObjectFindElt (const FcPattern *p, FcObject object); + +FcPrivate FcPatternElt * +FcPatternObjectInsertElt (FcPattern *p, FcObject object); + +FcPrivate FcBool +FcPatternObjectAddWithBinding (FcPattern *p, + FcObject object, + FcValue value, + FcValueBinding binding, + FcBool append); + +FcPrivate FcBool +FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append); + +FcPrivate FcBool +FcPatternObjectAddWeak (FcPattern *p, FcObject object, FcValue value, FcBool append); + +FcPrivate FcResult +FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v); + +FcPrivate FcBool +FcPatternObjectDel (FcPattern *p, FcObject object); + +FcPrivate FcBool +FcPatternObjectRemove (FcPattern *p, FcObject object, int id); + +FcPrivate FcBool +FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i); + +FcPrivate FcBool +FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d); + +FcPrivate FcBool +FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s); + +FcPrivate FcBool +FcPatternObjectAddMatrix (FcPattern *p, FcObject object, const FcMatrix *s); + +FcPrivate FcBool +FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c); + +FcPrivate FcBool +FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b); + +FcPrivate FcBool +FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls); + +FcPrivate FcResult +FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int n, int *i); + +FcPrivate FcResult +FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int n, double *d); + +FcPrivate FcResult +FcPatternObjectGetString (const FcPattern *p, FcObject object, int n, FcChar8 ** s); + +FcPrivate FcResult +FcPatternObjectGetMatrix (const FcPattern *p, FcObject object, int n, FcMatrix **s); + +FcPrivate FcResult +FcPatternObjectGetCharSet (const FcPattern *p, FcObject object, int n, FcCharSet **c); + +FcPrivate FcResult +FcPatternObjectGetBool (const FcPattern *p, FcObject object, int n, FcBool *b); + +FcPrivate FcResult +FcPatternObjectGetLangSet (const FcPattern *p, FcObject object, int n, FcLangSet **ls); + +FcPrivate void +FcPatternFini (void); + +FcPrivate FcBool +FcPatternAppend (FcPattern *p, FcPattern *s); + +FcPrivate const FcChar8 * +FcStrStaticName (const FcChar8 *name); + +FcPrivate FcChar32 +FcStringHash (const FcChar8 *s); + +FcPrivate FcBool +FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat); + +FcPrivate FcPattern * +FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat); + +FcPrivate FcBool +FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *pat); + +FcPrivate FcValueList * +FcValueListSerialize (FcSerialize *serialize, const FcValueList *pat); + +/* fcrender.c */ + +/* fcmatrix.c */ + +extern FcPrivate const FcMatrix FcIdentityMatrix; + +FcPrivate void +FcMatrixFree (FcMatrix *mat); + +/* fcstr.c */ +FcPrivate void +FcStrSetSort (FcStrSet * set); + +FcPrivate void +FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size); + +FcPrivate void +FcStrBufDestroy (FcStrBuf *buf); + +FcPrivate FcChar8 * +FcStrBufDone (FcStrBuf *buf); + +FcPrivate FcChar8 * +FcStrBufDoneStatic (FcStrBuf *buf); + +FcPrivate FcBool +FcStrBufChar (FcStrBuf *buf, FcChar8 c); + +FcPrivate FcBool +FcStrBufString (FcStrBuf *buf, const FcChar8 *s); + +FcPrivate FcBool +FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len); + +FcPrivate int +FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2); + +FcPrivate const FcChar8 * +FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2); + +FcPrivate const FcChar8 * +FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2); + +FcPrivate const FcChar8 * +FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2); + +FcPrivate FcBool +FcStrUsesHome (const FcChar8 *s); + +FcPrivate FcChar8 * +FcStrLastSlash (const FcChar8 *path); + +FcPrivate FcChar32 +FcStrHashIgnoreCase (const FcChar8 *s); + +FcPrivate FcChar8 * +FcStrCanonFilename (const FcChar8 *s); + +FcPrivate FcBool +FcStrSerializeAlloc (FcSerialize *serialize, const FcChar8 *str); + +FcPrivate FcChar8 * +FcStrSerialize (FcSerialize *serialize, const FcChar8 *str); + +#endif /* _FC_INT_H_ */ diff --git a/fontconfig/src/fclang.c b/fontconfig/src/fclang.c index 6a9cf01d6..be42b58c4 100644 --- a/fontconfig/src/fclang.c +++ b/fontconfig/src/fclang.c @@ -1,886 +1,886 @@ -/*
- * fontconfig/src/fclang.c
- *
- * Copyright © 2002 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include "fcftint.h"
-
-typedef struct {
- const FcChar8 lang[8];
- const FcCharSet charset;
-} FcLangCharSet;
-
-typedef struct {
- int begin;
- int end;
-} FcLangCharSetRange;
-
-#include "../fc-lang/fclang.h"
-
-struct _FcLangSet {
- FcStrSet *extra;
- FcChar32 map_size;
- FcChar32 map[NUM_LANG_SET_MAP];
-};
-
-static void
-FcLangSetBitSet (FcLangSet *ls,
- unsigned int id)
-{
- int bucket;
-
- id = fcLangCharSetIndices[id];
- bucket = id >> 5;
- if (bucket >= ls->map_size)
- return; /* shouldn't happen really */
-
- ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f));
-}
-
-static FcBool
-FcLangSetBitGet (const FcLangSet *ls,
- unsigned int id)
-{
- int bucket;
-
- id = fcLangCharSetIndices[id];
- bucket = id >> 5;
- if (bucket >= ls->map_size)
- return FcFalse;
-
- return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse;
-}
-
-static void
-FcLangSetBitReset (FcLangSet *ls,
- unsigned int id)
-{
- int bucket;
-
- id = fcLangCharSetIndices[id];
- bucket = id >> 5;
- if (bucket >= ls->map_size)
- return; /* shouldn't happen really */
-
- ls->map[bucket] &= ~((FcChar32) 1 << (id & 0x1f));
-}
-
-FcLangSet *
-FcFreeTypeLangSet (const FcCharSet *charset,
- const FcChar8 *exclusiveLang)
-{
- int i, j;
- FcChar32 missing;
- const FcCharSet *exclusiveCharset = 0;
- FcLangSet *ls;
-
- if (exclusiveLang)
- exclusiveCharset = FcLangGetCharSet (exclusiveLang);
- ls = FcLangSetCreate ();
- if (!ls)
- return 0;
- if (FcDebug() & FC_DBG_LANGSET)
- {
- printf ("font charset");
- FcCharSetPrint (charset);
- printf ("\n");
- }
- for (i = 0; i < NUM_LANG_CHAR_SET; i++)
- {
- if (FcDebug() & FC_DBG_LANGSET)
- {
- printf ("%s charset", fcLangCharSets[i].lang);
- FcCharSetPrint (&fcLangCharSets[i].charset);
- printf ("\n");
- }
-
- /*
- * Check for Han charsets to make fonts
- * which advertise support for a single language
- * not support other Han languages
- */
- if (exclusiveCharset &&
- FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
- {
- if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
- continue;
-
- for (j = 0; j < fcLangCharSets[i].charset.num; j++)
- if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
- FcCharSetLeaf(exclusiveCharset, j))
- continue;
- }
- missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
- if (FcDebug() & FC_DBG_SCANV)
- {
- if (missing && missing < 10)
- {
- FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
- charset);
- FcChar32 ucs4;
- FcChar32 map[FC_CHARSET_MAP_SIZE];
- FcChar32 next;
-
- printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
- printf ("{");
- for (ucs4 = FcCharSetFirstPage (missed, map, &next);
- ucs4 != FC_CHARSET_DONE;
- ucs4 = FcCharSetNextPage (missed, map, &next))
- {
- int i, j;
- for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
- if (map[i])
- {
- for (j = 0; j < 32; j++)
- if (map[i] & (1 << j))
- printf (" %04x", ucs4 + i * 32 + j);
- }
- }
- printf (" }\n\t");
- FcCharSetDestroy (missed);
- }
- else
- printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
- }
- if (!missing)
- FcLangSetBitSet (ls, i);
- }
-
- if (FcDebug() & FC_DBG_SCANV)
- printf ("\n");
-
-
- return ls;
-}
-
-#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
-
-FcLangResult
-FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcChar8 c1, c2;
- FcLangResult result = FcLangDifferentLang;
-
- for (;;)
- {
- c1 = *s1++;
- c2 = *s2++;
-
- c1 = FcToLower (c1);
- c2 = FcToLower (c2);
- if (c1 != c2)
- {
- if (FcLangEnd (c1) && FcLangEnd (c2))
- result = FcLangDifferentTerritory;
- return result;
- }
- else if (!c1)
- return FcLangEqual;
- else if (c1 == '-')
- result = FcLangDifferentTerritory;
- }
-}
-
-/*
- * Return FcTrue when super contains sub.
- *
- * super contains sub if super and sub have the same
- * language and either the same country or one
- * is missing the country
- */
-
-static FcBool
-FcLangContains (const FcChar8 *super, const FcChar8 *sub)
-{
- FcChar8 c1, c2;
-
- for (;;)
- {
- c1 = *super++;
- c2 = *sub++;
-
- c1 = FcToLower (c1);
- c2 = FcToLower (c2);
- if (c1 != c2)
- {
- /* see if super has a country while sub is mising one */
- if (c1 == '-' && c2 == '\0')
- return FcTrue;
- /* see if sub has a country while super is mising one */
- if (c1 == '\0' && c2 == '-')
- return FcTrue;
- return FcFalse;
- }
- else if (!c1)
- return FcTrue;
- }
-}
-
-const FcCharSet *
-FcLangGetCharSet (const FcChar8 *lang)
-{
- int i;
- int country = -1;
-
- for (i = 0; i < NUM_LANG_CHAR_SET; i++)
- {
- switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
- case FcLangEqual:
- return &fcLangCharSets[i].charset;
- case FcLangDifferentTerritory:
- if (country == -1)
- country = i;
- case FcLangDifferentLang:
- default:
- break;
- }
- }
- if (country == -1)
- return 0;
- return &fcLangCharSets[country].charset;
-}
-
-FcStrSet *
-FcGetLangs (void)
-{
- FcStrSet *langs;
- int i;
-
- langs = FcStrSetCreate();
- if (!langs)
- return 0;
-
- for (i = 0; i < NUM_LANG_CHAR_SET; i++)
- FcStrSetAdd (langs, fcLangCharSets[i].lang);
-
- return langs;
-}
-
-FcLangSet *
-FcLangSetCreate (void)
-{
- FcLangSet *ls;
-
- ls = malloc (sizeof (FcLangSet));
- if (!ls)
- return 0;
- FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
- memset (ls->map, '\0', sizeof (ls->map));
- ls->map_size = NUM_LANG_SET_MAP;
- ls->extra = 0;
- return ls;
-}
-
-void
-FcLangSetDestroy (FcLangSet *ls)
-{
- if (ls->extra)
- FcStrSetDestroy (ls->extra);
- FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
- free (ls);
-}
-
-FcLangSet *
-FcLangSetCopy (const FcLangSet *ls)
-{
- FcLangSet *new;
-
- new = FcLangSetCreate ();
- if (!new)
- goto bail0;
- memset (new->map, '\0', sizeof (new->map));
- memcpy (new->map, ls->map, FC_MIN (sizeof (new->map), ls->map_size * sizeof (ls->map[0])));
- if (ls->extra)
- {
- FcStrList *list;
- FcChar8 *extra;
-
- new->extra = FcStrSetCreate ();
- if (!new->extra)
- goto bail1;
-
- list = FcStrListCreate (ls->extra);
- if (!list)
- goto bail1;
-
- while ((extra = FcStrListNext (list)))
- if (!FcStrSetAdd (new->extra, extra))
- {
- FcStrListDone (list);
- goto bail1;
- }
- FcStrListDone (list);
- }
- return new;
-bail1:
- FcLangSetDestroy (new);
-bail0:
- return 0;
-}
-
-static int
-FcLangSetIndex (const FcChar8 *lang)
-{
- int low, high, mid = 0;
- int cmp = 0;
- FcChar8 firstChar = FcToLower(lang[0]);
- FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
-
- if (firstChar < 'a')
- {
- low = 0;
- high = fcLangCharSetRanges[0].begin;
- }
- else if(firstChar > 'z')
- {
- low = fcLangCharSetRanges[25].begin;
- high = NUM_LANG_CHAR_SET - 1;
- }
- else
- {
- low = fcLangCharSetRanges[firstChar - 'a'].begin;
- high = fcLangCharSetRanges[firstChar - 'a'].end;
- /* no matches */
- if (low > high)
- return -low; /* next entry after where it would be */
- }
-
- while (low <= high)
- {
- mid = (high + low) >> 1;
- if(fcLangCharSets[mid].lang[0] != firstChar)
- cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
- else
- { /* fast path for resolving 2-letter languages (by far the most common) after
- * finding the first char (probably already true because of the hash table) */
- cmp = fcLangCharSets[mid].lang[1] - secondChar;
- if (cmp == 0 &&
- (fcLangCharSets[mid].lang[2] != '\0' ||
- lang[2] != '\0'))
- {
- cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
- lang+2);
- }
- }
- if (cmp == 0)
- return mid;
- if (cmp < 0)
- low = mid + 1;
- else
- high = mid - 1;
- }
- if (cmp < 0)
- mid++;
- return -(mid + 1);
-}
-
-FcBool
-FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
-{
- int id;
-
- id = FcLangSetIndex (lang);
- if (id >= 0)
- {
- FcLangSetBitSet (ls, id);
- return FcTrue;
- }
- if (!ls->extra)
- {
- ls->extra = FcStrSetCreate ();
- if (!ls->extra)
- return FcFalse;
- }
- return FcStrSetAdd (ls->extra, lang);
-}
-
-FcBool
-FcLangSetDel (FcLangSet *ls, const FcChar8 *lang)
-{
- int id;
-
- id = FcLangSetIndex (lang);
- if (id >= 0)
- {
- FcLangSetBitReset (ls, id);
- }
- else if (ls->extra)
- {
- FcStrSetDel (ls->extra, lang);
- }
- return FcTrue;
-}
-
-FcLangResult
-FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
-{
- int id;
- FcLangResult best, r;
- int i;
-
- id = FcLangSetIndex (lang);
- if (id < 0)
- id = -id - 1;
- else if (FcLangSetBitGet (ls, id))
- return FcLangEqual;
- best = FcLangDifferentLang;
- for (i = id - 1; i >= 0; i--)
- {
- r = FcLangCompare (lang, fcLangCharSets[i].lang);
- if (r == FcLangDifferentLang)
- break;
- if (FcLangSetBitGet (ls, i) && r < best)
- best = r;
- }
- for (i = id; i < NUM_LANG_CHAR_SET; i++)
- {
- r = FcLangCompare (lang, fcLangCharSets[i].lang);
- if (r == FcLangDifferentLang)
- break;
- if (FcLangSetBitGet (ls, i) && r < best)
- best = r;
- }
- if (ls->extra)
- {
- FcStrList *list = FcStrListCreate (ls->extra);
- FcChar8 *extra;
-
- if (list)
- {
- while (best > FcLangEqual && (extra = FcStrListNext (list)))
- {
- r = FcLangCompare (lang, extra);
- if (r < best)
- best = r;
- }
- FcStrListDone (list);
- }
- }
- return best;
-}
-
-static FcLangResult
-FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
-{
- FcStrList *list = FcStrListCreate (set);
- FcLangResult r, best = FcLangDifferentLang;
- FcChar8 *extra;
-
- if (list)
- {
- while (best > FcLangEqual && (extra = FcStrListNext (list)))
- {
- r = FcLangSetHasLang (ls, extra);
- if (r < best)
- best = r;
- }
- FcStrListDone (list);
- }
- return best;
-}
-
-FcLangResult
-FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
-{
- int i, j, count;
- FcLangResult best, r;
-
- count = FC_MIN (lsa->map_size, lsb->map_size);
- count = FC_MIN (NUM_LANG_SET_MAP, count);
- for (i = 0; i < count; i++)
- if (lsa->map[i] & lsb->map[i])
- return FcLangEqual;
- best = FcLangDifferentLang;
- for (j = 0; j < NUM_COUNTRY_SET; j++)
- for (i = 0; i < count; i++)
- if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
- (lsb->map[i] & fcLangCountrySets[j][i]))
- {
- best = FcLangDifferentTerritory;
- break;
- }
- if (lsa->extra)
- {
- r = FcLangSetCompareStrSet (lsb, lsa->extra);
- if (r < best)
- best = r;
- }
- if (best > FcLangEqual && lsb->extra)
- {
- r = FcLangSetCompareStrSet (lsa, lsb->extra);
- if (r < best)
- best = r;
- }
- return best;
-}
-
-/*
- * Used in computing values -- mustn't allocate any storage
- * XXX Not thread-safe
- */
-FcLangSet *
-FcLangSetPromote (const FcChar8 *lang)
-{
- static FcLangSet ls;
- static FcStrSet strs;
- static FcChar8 *str;
- int id;
-
- memset (ls.map, '\0', sizeof (ls.map));
- ls.map_size = NUM_LANG_SET_MAP;
- ls.extra = 0;
- id = FcLangSetIndex (lang);
- if (id > 0)
- {
- FcLangSetBitSet (&ls, id);
- }
- else
- {
- ls.extra = &strs;
- strs.num = 1;
- strs.size = 1;
- strs.strs = &str;
- strs.ref = 1;
- str = (FcChar8 *) lang;
- }
- return &ls;
-}
-
-FcChar32
-FcLangSetHash (const FcLangSet *ls)
-{
- FcChar32 h = 0;
- int i, count;
-
- count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
- for (i = 0; i < count; i++)
- h ^= ls->map[i];
- if (ls->extra)
- h ^= ls->extra->num;
- return h;
-}
-
-FcLangSet *
-FcNameParseLangSet (const FcChar8 *string)
-{
- FcChar8 lang[32], c = 0;
- int i;
- FcLangSet *ls;
-
- ls = FcLangSetCreate ();
- if (!ls)
- goto bail0;
-
- for(;;)
- {
- for(i = 0; i < 31;i++)
- {
- c = *string++;
- if(c == '\0' || c == '|')
- break; /* end of this code */
- lang[i] = c;
- }
- lang[i] = '\0';
- if (!FcLangSetAdd (ls, lang))
- goto bail1;
- if(c == '\0')
- break;
- }
- return ls;
-bail1:
- FcLangSetDestroy (ls);
-bail0:
- return 0;
-}
-
-FcBool
-FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
-{
- int i, bit, count;
- FcChar32 bits;
- FcBool first = FcTrue;
-
- count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
- for (i = 0; i < count; i++)
- {
- if ((bits = ls->map[i]))
- {
- for (bit = 0; bit <= 31; bit++)
- if (bits & (1 << bit))
- {
- int id = (i << 5) | bit;
- if (!first)
- if (!FcStrBufChar (buf, '|'))
- return FcFalse;
- if (!FcStrBufString (buf, fcLangCharSets[fcLangCharSetIndicesInv[id]].lang))
- return FcFalse;
- first = FcFalse;
- }
- }
- }
- if (ls->extra)
- {
- FcStrList *list = FcStrListCreate (ls->extra);
- FcChar8 *extra;
-
- if (!list)
- return FcFalse;
- while ((extra = FcStrListNext (list)))
- {
- if (!first)
- if (!FcStrBufChar (buf, '|'))
- {
- FcStrListDone (list);
- return FcFalse;
- }
- if (!FcStrBufString (buf, extra))
- {
- FcStrListDone (list);
- return FcFalse;
- }
- first = FcFalse;
- }
- FcStrListDone (list);
- }
- return FcTrue;
-}
-
-FcBool
-FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
-{
- int i, count;
-
- count = FC_MIN (lsa->map_size, lsb->map_size);
- count = FC_MIN (NUM_LANG_SET_MAP, count);
- for (i = 0; i < count; i++)
- {
- if (lsa->map[i] != lsb->map[i])
- return FcFalse;
- }
- if (!lsa->extra && !lsb->extra)
- return FcTrue;
- if (lsa->extra && lsb->extra)
- return FcStrSetEqual (lsa->extra, lsb->extra);
- return FcFalse;
-}
-
-static FcBool
-FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
-{
- int id;
- int i;
-
- id = FcLangSetIndex (lang);
- if (id < 0)
- id = -id - 1;
- else if (FcLangSetBitGet (ls, id))
- return FcTrue;
- /*
- * search up and down among equal languages for a match
- */
- for (i = id - 1; i >= 0; i--)
- {
- if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
- break;
- if (FcLangSetBitGet (ls, i) &&
- FcLangContains (fcLangCharSets[i].lang, lang))
- return FcTrue;
- }
- for (i = id; i < NUM_LANG_CHAR_SET; i++)
- {
- if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
- break;
- if (FcLangSetBitGet (ls, i) &&
- FcLangContains (fcLangCharSets[i].lang, lang))
- return FcTrue;
- }
- if (ls->extra)
- {
- FcStrList *list = FcStrListCreate (ls->extra);
- FcChar8 *extra;
-
- if (list)
- {
- while ((extra = FcStrListNext (list)))
- {
- if (FcLangContains (extra, lang))
- break;
- }
- FcStrListDone (list);
- if (extra)
- return FcTrue;
- }
- }
- return FcFalse;
-}
-
-/*
- * return FcTrue if lsa contains every language in lsb
- */
-FcBool
-FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
-{
- int i, j, count;
- FcChar32 missing;
-
- if (FcDebug() & FC_DBG_MATCHV)
- {
- printf ("FcLangSet "); FcLangSetPrint (lsa);
- printf (" contains "); FcLangSetPrint (lsb);
- printf ("\n");
- }
- /*
- * check bitmaps for missing language support
- */
- count = FC_MIN (lsa->map_size, lsb->map_size);
- count = FC_MIN (NUM_LANG_SET_MAP, count);
- for (i = 0; i < count; i++)
- {
- missing = lsb->map[i] & ~lsa->map[i];
- if (missing)
- {
- for (j = 0; j < 32; j++)
- if (missing & (1 << j))
- {
- if (!FcLangSetContainsLang (lsa,
- fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang))
- {
- if (FcDebug() & FC_DBG_MATCHV)
- printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[i*32+j]].lang);
- return FcFalse;
- }
- }
- }
- }
- if (lsb->extra)
- {
- FcStrList *list = FcStrListCreate (lsb->extra);
- FcChar8 *extra;
-
- if (list)
- {
- while ((extra = FcStrListNext (list)))
- {
- if (!FcLangSetContainsLang (lsa, extra))
- {
- if (FcDebug() & FC_DBG_MATCHV)
- printf ("\tMissing string %s\n", extra);
- break;
- }
- }
- FcStrListDone (list);
- if (extra)
- return FcFalse;
- }
- }
- return FcTrue;
-}
-
-FcBool
-FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
-{
- if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
- return FcFalse;
- return FcTrue;
-}
-
-FcLangSet *
-FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
-{
- FcLangSet *l_serialize = FcSerializePtr (serialize, l);
-
- if (!l_serialize)
- return NULL;
- memset (l_serialize->map, '\0', sizeof (l_serialize->map));
- memcpy (l_serialize->map, l->map, FC_MIN (sizeof (l_serialize->map), l->map_size * sizeof (l->map[0])));
- l_serialize->map_size = NUM_LANG_SET_MAP;
- l_serialize->extra = NULL; /* We don't serialize ls->extra */
- return l_serialize;
-}
-
-FcStrSet *
-FcLangSetGetLangs (const FcLangSet *ls)
-{
- FcStrSet *langs;
- int i;
-
- langs = FcStrSetCreate();
- if (!langs)
- return 0;
-
- for (i = 0; i < NUM_LANG_CHAR_SET; i++)
- if (FcLangSetBitGet (ls, i))
- FcStrSetAdd (langs, fcLangCharSets[i].lang);
-
- if (ls->extra)
- {
- FcStrList *list = FcStrListCreate (ls->extra);
- FcChar8 *extra;
-
- if (list)
- {
- while ((extra = FcStrListNext (list)))
- FcStrSetAdd (langs, extra);
-
- FcStrListDone (list);
- }
- }
-
- return langs;
-}
-
-static FcLangSet *
-FcLangSetOperate(const FcLangSet *a,
- const FcLangSet *b,
- FcBool (*func) (FcLangSet *ls,
- const FcChar8 *s))
-{
- FcLangSet *langset = FcLangSetCopy (a);
- FcStrList *sl = FcStrListCreate (FcLangSetGetLangs (b));
- FcChar8 *str;
-
- while ((str = FcStrListNext (sl)))
- {
- func (langset, str);
- }
- FcStrListDone (sl);
-
- return langset;
-}
-
-FcLangSet *
-FcLangSetUnion (const FcLangSet *a, const FcLangSet *b)
-{
- return FcLangSetOperate(a, b, FcLangSetAdd);
-}
-
-FcLangSet *
-FcLangSetSubtract (const FcLangSet *a, const FcLangSet *b)
-{
- return FcLangSetOperate(a, b, FcLangSetDel);
-}
-
-#define __fclang__
-#include "fcaliastail.h"
-#include "fcftaliastail.h"
-#undef __fclang__
+/* + * fontconfig/src/fclang.c + * + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include "fcftint.h" + +typedef struct { + const FcChar8 lang[8]; + const FcCharSet charset; +} FcLangCharSet; + +typedef struct { + int begin; + int end; +} FcLangCharSetRange; + +#include "../fc-lang/fclang.h" + +struct _FcLangSet { + FcStrSet *extra; + FcChar32 map_size; + FcChar32 map[NUM_LANG_SET_MAP]; +}; + +static void +FcLangSetBitSet (FcLangSet *ls, + unsigned int id) +{ + int bucket; + + id = fcLangCharSetIndices[id]; + bucket = id >> 5; + if (bucket >= ls->map_size) + return; /* shouldn't happen really */ + + ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f)); +} + +static FcBool +FcLangSetBitGet (const FcLangSet *ls, + unsigned int id) +{ + int bucket; + + id = fcLangCharSetIndices[id]; + bucket = id >> 5; + if (bucket >= ls->map_size) + return FcFalse; + + return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse; +} + +static void +FcLangSetBitReset (FcLangSet *ls, + unsigned int id) +{ + int bucket; + + id = fcLangCharSetIndices[id]; + bucket = id >> 5; + if (bucket >= ls->map_size) + return; /* shouldn't happen really */ + + ls->map[bucket] &= ~((FcChar32) 1 << (id & 0x1f)); +} + +FcLangSet * +FcFreeTypeLangSet (const FcCharSet *charset, + const FcChar8 *exclusiveLang) +{ + int i, j; + FcChar32 missing; + const FcCharSet *exclusiveCharset = 0; + FcLangSet *ls; + + if (exclusiveLang) + exclusiveCharset = FcLangGetCharSet (exclusiveLang); + ls = FcLangSetCreate (); + if (!ls) + return 0; + if (FcDebug() & FC_DBG_LANGSET) + { + printf ("font charset"); + FcCharSetPrint (charset); + printf ("\n"); + } + for (i = 0; i < NUM_LANG_CHAR_SET; i++) + { + if (FcDebug() & FC_DBG_LANGSET) + { + printf ("%s charset", fcLangCharSets[i].lang); + FcCharSetPrint (&fcLangCharSets[i].charset); + printf ("\n"); + } + + /* + * Check for Han charsets to make fonts + * which advertise support for a single language + * not support other Han languages + */ + if (exclusiveCharset && + FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang)) + { + if (fcLangCharSets[i].charset.num != exclusiveCharset->num) + continue; + + for (j = 0; j < fcLangCharSets[i].charset.num; j++) + if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) != + FcCharSetLeaf(exclusiveCharset, j)) + continue; + } + missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset); + if (FcDebug() & FC_DBG_SCANV) + { + if (missing && missing < 10) + { + FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset, + charset); + FcChar32 ucs4; + FcChar32 map[FC_CHARSET_MAP_SIZE]; + FcChar32 next; + + printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing); + printf ("{"); + for (ucs4 = FcCharSetFirstPage (missed, map, &next); + ucs4 != FC_CHARSET_DONE; + ucs4 = FcCharSetNextPage (missed, map, &next)) + { + int i, j; + for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) + if (map[i]) + { + for (j = 0; j < 32; j++) + if (map[i] & (1 << j)) + printf (" %04x", ucs4 + i * 32 + j); + } + } + printf (" }\n\t"); + FcCharSetDestroy (missed); + } + else + printf ("%s(%u) ", fcLangCharSets[i].lang, missing); + } + if (!missing) + FcLangSetBitSet (ls, i); + } + + if (FcDebug() & FC_DBG_SCANV) + printf ("\n"); + + + return ls; +} + +#define FcLangEnd(c) ((c) == '-' || (c) == '\0') + +FcLangResult +FcLangCompare (const FcChar8 *s1, const FcChar8 *s2) +{ + FcChar8 c1, c2; + FcLangResult result = FcLangDifferentLang; + + for (;;) + { + c1 = *s1++; + c2 = *s2++; + + c1 = FcToLower (c1); + c2 = FcToLower (c2); + if (c1 != c2) + { + if (FcLangEnd (c1) && FcLangEnd (c2)) + result = FcLangDifferentTerritory; + return result; + } + else if (!c1) + return FcLangEqual; + else if (c1 == '-') + result = FcLangDifferentTerritory; + } +} + +/* + * Return FcTrue when super contains sub. + * + * super contains sub if super and sub have the same + * language and either the same country or one + * is missing the country + */ + +static FcBool +FcLangContains (const FcChar8 *super, const FcChar8 *sub) +{ + FcChar8 c1, c2; + + for (;;) + { + c1 = *super++; + c2 = *sub++; + + c1 = FcToLower (c1); + c2 = FcToLower (c2); + if (c1 != c2) + { + /* see if super has a country while sub is mising one */ + if (c1 == '-' && c2 == '\0') + return FcTrue; + /* see if sub has a country while super is mising one */ + if (c1 == '\0' && c2 == '-') + return FcTrue; + return FcFalse; + } + else if (!c1) + return FcTrue; + } +} + +const FcCharSet * +FcLangGetCharSet (const FcChar8 *lang) +{ + int i; + int country = -1; + + for (i = 0; i < NUM_LANG_CHAR_SET; i++) + { + switch (FcLangCompare (lang, fcLangCharSets[i].lang)) { + case FcLangEqual: + return &fcLangCharSets[i].charset; + case FcLangDifferentTerritory: + if (country == -1) + country = i; + case FcLangDifferentLang: + default: + break; + } + } + if (country == -1) + return 0; + return &fcLangCharSets[country].charset; +} + +FcStrSet * +FcGetLangs (void) +{ + FcStrSet *langs; + int i; + + langs = FcStrSetCreate(); + if (!langs) + return 0; + + for (i = 0; i < NUM_LANG_CHAR_SET; i++) + FcStrSetAdd (langs, fcLangCharSets[i].lang); + + return langs; +} + +FcLangSet * +FcLangSetCreate (void) +{ + FcLangSet *ls; + + ls = malloc (sizeof (FcLangSet)); + if (!ls) + return 0; + FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet)); + memset (ls->map, '\0', sizeof (ls->map)); + ls->map_size = NUM_LANG_SET_MAP; + ls->extra = 0; + return ls; +} + +void +FcLangSetDestroy (FcLangSet *ls) +{ + if (ls->extra) + FcStrSetDestroy (ls->extra); + FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet)); + free (ls); +} + +FcLangSet * +FcLangSetCopy (const FcLangSet *ls) +{ + FcLangSet *new; + + new = FcLangSetCreate (); + if (!new) + goto bail0; + memset (new->map, '\0', sizeof (new->map)); + memcpy (new->map, ls->map, FC_MIN (sizeof (new->map), ls->map_size * sizeof (ls->map[0]))); + if (ls->extra) + { + FcStrList *list; + FcChar8 *extra; + + new->extra = FcStrSetCreate (); + if (!new->extra) + goto bail1; + + list = FcStrListCreate (ls->extra); + if (!list) + goto bail1; + + while ((extra = FcStrListNext (list))) + if (!FcStrSetAdd (new->extra, extra)) + { + FcStrListDone (list); + goto bail1; + } + FcStrListDone (list); + } + return new; +bail1: + FcLangSetDestroy (new); +bail0: + return 0; +} + +static int +FcLangSetIndex (const FcChar8 *lang) +{ + int low, high, mid = 0; + int cmp = 0; + FcChar8 firstChar = FcToLower(lang[0]); + FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0'; + + if (firstChar < 'a') + { + low = 0; + high = fcLangCharSetRanges[0].begin; + } + else if(firstChar > 'z') + { + low = fcLangCharSetRanges[25].begin; + high = NUM_LANG_CHAR_SET - 1; + } + else + { + low = fcLangCharSetRanges[firstChar - 'a'].begin; + high = fcLangCharSetRanges[firstChar - 'a'].end; + /* no matches */ + if (low > high) + return -low; /* next entry after where it would be */ + } + + while (low <= high) + { + mid = (high + low) >> 1; + if(fcLangCharSets[mid].lang[0] != firstChar) + cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang); + else + { /* fast path for resolving 2-letter languages (by far the most common) after + * finding the first char (probably already true because of the hash table) */ + cmp = fcLangCharSets[mid].lang[1] - secondChar; + if (cmp == 0 && + (fcLangCharSets[mid].lang[2] != '\0' || + lang[2] != '\0')) + { + cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2, + lang+2); + } + } + if (cmp == 0) + return mid; + if (cmp < 0) + low = mid + 1; + else + high = mid - 1; + } + if (cmp < 0) + mid++; + return -(mid + 1); +} + +FcBool +FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang) +{ + int id; + + id = FcLangSetIndex (lang); + if (id >= 0) + { + FcLangSetBitSet (ls, id); + return FcTrue; + } + if (!ls->extra) + { + ls->extra = FcStrSetCreate (); + if (!ls->extra) + return FcFalse; + } + return FcStrSetAdd (ls->extra, lang); +} + +FcBool +FcLangSetDel (FcLangSet *ls, const FcChar8 *lang) +{ + int id; + + id = FcLangSetIndex (lang); + if (id >= 0) + { + FcLangSetBitReset (ls, id); + } + else if (ls->extra) + { + FcStrSetDel (ls->extra, lang); + } + return FcTrue; +} + +FcLangResult +FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang) +{ + int id; + FcLangResult best, r; + int i; + + id = FcLangSetIndex (lang); + if (id < 0) + id = -id - 1; + else if (FcLangSetBitGet (ls, id)) + return FcLangEqual; + best = FcLangDifferentLang; + for (i = id - 1; i >= 0; i--) + { + r = FcLangCompare (lang, fcLangCharSets[i].lang); + if (r == FcLangDifferentLang) + break; + if (FcLangSetBitGet (ls, i) && r < best) + best = r; + } + for (i = id; i < NUM_LANG_CHAR_SET; i++) + { + r = FcLangCompare (lang, fcLangCharSets[i].lang); + if (r == FcLangDifferentLang) + break; + if (FcLangSetBitGet (ls, i) && r < best) + best = r; + } + if (ls->extra) + { + FcStrList *list = FcStrListCreate (ls->extra); + FcChar8 *extra; + + if (list) + { + while (best > FcLangEqual && (extra = FcStrListNext (list))) + { + r = FcLangCompare (lang, extra); + if (r < best) + best = r; + } + FcStrListDone (list); + } + } + return best; +} + +static FcLangResult +FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set) +{ + FcStrList *list = FcStrListCreate (set); + FcLangResult r, best = FcLangDifferentLang; + FcChar8 *extra; + + if (list) + { + while (best > FcLangEqual && (extra = FcStrListNext (list))) + { + r = FcLangSetHasLang (ls, extra); + if (r < best) + best = r; + } + FcStrListDone (list); + } + return best; +} + +FcLangResult +FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb) +{ + int i, j, count; + FcLangResult best, r; + + count = FC_MIN (lsa->map_size, lsb->map_size); + count = FC_MIN (NUM_LANG_SET_MAP, count); + for (i = 0; i < count; i++) + if (lsa->map[i] & lsb->map[i]) + return FcLangEqual; + best = FcLangDifferentLang; + for (j = 0; j < NUM_COUNTRY_SET; j++) + for (i = 0; i < count; i++) + if ((lsa->map[i] & fcLangCountrySets[j][i]) && + (lsb->map[i] & fcLangCountrySets[j][i])) + { + best = FcLangDifferentTerritory; + break; + } + if (lsa->extra) + { + r = FcLangSetCompareStrSet (lsb, lsa->extra); + if (r < best) + best = r; + } + if (best > FcLangEqual && lsb->extra) + { + r = FcLangSetCompareStrSet (lsa, lsb->extra); + if (r < best) + best = r; + } + return best; +} + +/* + * Used in computing values -- mustn't allocate any storage + * XXX Not thread-safe + */ +FcLangSet * +FcLangSetPromote (const FcChar8 *lang) +{ + static FcLangSet ls; + static FcStrSet strs; + static FcChar8 *str; + int id; + + memset (ls.map, '\0', sizeof (ls.map)); + ls.map_size = NUM_LANG_SET_MAP; + ls.extra = 0; + id = FcLangSetIndex (lang); + if (id > 0) + { + FcLangSetBitSet (&ls, id); + } + else + { + ls.extra = &strs; + strs.num = 1; + strs.size = 1; + strs.strs = &str; + strs.ref = 1; + str = (FcChar8 *) lang; + } + return &ls; +} + +FcChar32 +FcLangSetHash (const FcLangSet *ls) +{ + FcChar32 h = 0; + int i, count; + + count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP); + for (i = 0; i < count; i++) + h ^= ls->map[i]; + if (ls->extra) + h ^= ls->extra->num; + return h; +} + +FcLangSet * +FcNameParseLangSet (const FcChar8 *string) +{ + FcChar8 lang[32], c = 0; + int i; + FcLangSet *ls; + + ls = FcLangSetCreate (); + if (!ls) + goto bail0; + + for(;;) + { + for(i = 0; i < 31;i++) + { + c = *string++; + if(c == '\0' || c == '|') + break; /* end of this code */ + lang[i] = c; + } + lang[i] = '\0'; + if (!FcLangSetAdd (ls, lang)) + goto bail1; + if(c == '\0') + break; + } + return ls; +bail1: + FcLangSetDestroy (ls); +bail0: + return 0; +} + +FcBool +FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls) +{ + int i, bit, count; + FcChar32 bits; + FcBool first = FcTrue; + + count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP); + for (i = 0; i < count; i++) + { + if ((bits = ls->map[i])) + { + for (bit = 0; bit <= 31; bit++) + if (bits & (1 << bit)) + { + int id = (i << 5) | bit; + if (!first) + if (!FcStrBufChar (buf, '|')) + return FcFalse; + if (!FcStrBufString (buf, fcLangCharSets[fcLangCharSetIndicesInv[id]].lang)) + return FcFalse; + first = FcFalse; + } + } + } + if (ls->extra) + { + FcStrList *list = FcStrListCreate (ls->extra); + FcChar8 *extra; + + if (!list) + return FcFalse; + while ((extra = FcStrListNext (list))) + { + if (!first) + if (!FcStrBufChar (buf, '|')) + { + FcStrListDone (list); + return FcFalse; + } + if (!FcStrBufString (buf, extra)) + { + FcStrListDone (list); + return FcFalse; + } + first = FcFalse; + } + FcStrListDone (list); + } + return FcTrue; +} + +FcBool +FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb) +{ + int i, count; + + count = FC_MIN (lsa->map_size, lsb->map_size); + count = FC_MIN (NUM_LANG_SET_MAP, count); + for (i = 0; i < count; i++) + { + if (lsa->map[i] != lsb->map[i]) + return FcFalse; + } + if (!lsa->extra && !lsb->extra) + return FcTrue; + if (lsa->extra && lsb->extra) + return FcStrSetEqual (lsa->extra, lsb->extra); + return FcFalse; +} + +static FcBool +FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang) +{ + int id; + int i; + + id = FcLangSetIndex (lang); + if (id < 0) + id = -id - 1; + else if (FcLangSetBitGet (ls, id)) + return FcTrue; + /* + * search up and down among equal languages for a match + */ + for (i = id - 1; i >= 0; i--) + { + if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang) + break; + if (FcLangSetBitGet (ls, i) && + FcLangContains (fcLangCharSets[i].lang, lang)) + return FcTrue; + } + for (i = id; i < NUM_LANG_CHAR_SET; i++) + { + if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang) + break; + if (FcLangSetBitGet (ls, i) && + FcLangContains (fcLangCharSets[i].lang, lang)) + return FcTrue; + } + if (ls->extra) + { + FcStrList *list = FcStrListCreate (ls->extra); + FcChar8 *extra; + + if (list) + { + while ((extra = FcStrListNext (list))) + { + if (FcLangContains (extra, lang)) + break; + } + FcStrListDone (list); + if (extra) + return FcTrue; + } + } + return FcFalse; +} + +/* + * return FcTrue if lsa contains every language in lsb + */ +FcBool +FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb) +{ + int i, j, count; + FcChar32 missing; + + if (FcDebug() & FC_DBG_MATCHV) + { + printf ("FcLangSet "); FcLangSetPrint (lsa); + printf (" contains "); FcLangSetPrint (lsb); + printf ("\n"); + } + /* + * check bitmaps for missing language support + */ + count = FC_MIN (lsa->map_size, lsb->map_size); + count = FC_MIN (NUM_LANG_SET_MAP, count); + for (i = 0; i < count; i++) + { + missing = lsb->map[i] & ~lsa->map[i]; + if (missing) + { + for (j = 0; j < 32; j++) + if (missing & (1 << j)) + { + if (!FcLangSetContainsLang (lsa, + fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang)) + { + if (FcDebug() & FC_DBG_MATCHV) + printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[i*32+j]].lang); + return FcFalse; + } + } + } + } + if (lsb->extra) + { + FcStrList *list = FcStrListCreate (lsb->extra); + FcChar8 *extra; + + if (list) + { + while ((extra = FcStrListNext (list))) + { + if (!FcLangSetContainsLang (lsa, extra)) + { + if (FcDebug() & FC_DBG_MATCHV) + printf ("\tMissing string %s\n", extra); + break; + } + } + FcStrListDone (list); + if (extra) + return FcFalse; + } + } + return FcTrue; +} + +FcBool +FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l) +{ + if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet))) + return FcFalse; + return FcTrue; +} + +FcLangSet * +FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l) +{ + FcLangSet *l_serialize = FcSerializePtr (serialize, l); + + if (!l_serialize) + return NULL; + memset (l_serialize->map, '\0', sizeof (l_serialize->map)); + memcpy (l_serialize->map, l->map, FC_MIN (sizeof (l_serialize->map), l->map_size * sizeof (l->map[0]))); + l_serialize->map_size = NUM_LANG_SET_MAP; + l_serialize->extra = NULL; /* We don't serialize ls->extra */ + return l_serialize; +} + +FcStrSet * +FcLangSetGetLangs (const FcLangSet *ls) +{ + FcStrSet *langs; + int i; + + langs = FcStrSetCreate(); + if (!langs) + return 0; + + for (i = 0; i < NUM_LANG_CHAR_SET; i++) + if (FcLangSetBitGet (ls, i)) + FcStrSetAdd (langs, fcLangCharSets[i].lang); + + if (ls->extra) + { + FcStrList *list = FcStrListCreate (ls->extra); + FcChar8 *extra; + + if (list) + { + while ((extra = FcStrListNext (list))) + FcStrSetAdd (langs, extra); + + FcStrListDone (list); + } + } + + return langs; +} + +static FcLangSet * +FcLangSetOperate(const FcLangSet *a, + const FcLangSet *b, + FcBool (*func) (FcLangSet *ls, + const FcChar8 *s)) +{ + FcLangSet *langset = FcLangSetCopy (a); + FcStrList *sl = FcStrListCreate (FcLangSetGetLangs (b)); + FcChar8 *str; + + while ((str = FcStrListNext (sl))) + { + func (langset, str); + } + FcStrListDone (sl); + + return langset; +} + +FcLangSet * +FcLangSetUnion (const FcLangSet *a, const FcLangSet *b) +{ + return FcLangSetOperate(a, b, FcLangSetAdd); +} + +FcLangSet * +FcLangSetSubtract (const FcLangSet *a, const FcLangSet *b) +{ + return FcLangSetOperate(a, b, FcLangSetDel); +} + +#define __fclang__ +#include "fcaliastail.h" +#include "fcftaliastail.h" +#undef __fclang__ diff --git a/fontconfig/src/fclist.c b/fontconfig/src/fclist.c index 0f9a1235c..9a84b5c7e 100644 --- a/fontconfig/src/fclist.c +++ b/fontconfig/src/fclist.c @@ -1,577 +1,577 @@ -/*
- * fontconfig/src/fclist.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdlib.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;
- int high, low, mid, c;
-
- 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;
- }
- high = os->nobject - 1;
- low = 0;
- mid = 0;
- c = 1;
- object = (char *)FcStrStaticName ((FcChar8 *)object);
- while (low <= high)
- {
- mid = (low + high) >> 1;
- c = os->objects[mid] - object;
- if (c == 0)
- return FcTrue;
- if (c < 0)
- low = mid + 1;
- else
- high = mid - 1;
- }
- if (c < 0)
- mid++;
- memmove (os->objects + mid + 1, os->objects + mid,
- (os->nobject - mid) * sizeof (const char *));
- os->objects[mid] = object;
- os->nobject++;
- 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;
-}
-
-/*
- * Font must have a containing value for every value in the pattern
- */
-static FcBool
-FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */
- FcValueListPtr fntOrig) /* font */
-{
- FcValueListPtr pat, fnt;
-
- for (pat = patOrig; pat != NULL; pat = FcValueListNext(pat))
- {
- for (fnt = fntOrig; fnt != NULL; fnt = FcValueListNext(fnt))
- {
- /*
- * make sure the font 'contains' the pattern.
- * (OpListing is OpContains except for strings
- * where it requires an exact match)
- */
- if (FcConfigCompareValue (&fnt->value,
- FcOpListing,
- &pat->value))
- break;
- }
- if (fnt == NULL)
- return FcFalse;
- }
- return FcTrue;
-}
-
-static FcBool
-FcListValueListEqual (FcValueListPtr v1orig,
- FcValueListPtr v2orig)
-{
- FcValueListPtr v1, v2;
-
- for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
- {
- for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
- if (FcValueEqual (FcValueCanonicalize(&(v1)->value),
- FcValueCanonicalize(&(v2)->value)))
- break;
- if (v2 == NULL)
- return FcFalse;
- }
- for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
- {
- for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
- if (FcValueEqual (FcValueCanonicalize(&v1->value),
- FcValueCanonicalize(&v2->value)))
- break;
- if (v1 == NULL)
- 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 = FcPatternObjectFindElt (p1, FcObjectFromName (os->objects[i]));
- e2 = FcPatternObjectFindElt (p2, FcObjectFromName (os->objects[i]));
- if (!e1 && !e2)
- continue;
- if (!e1 || !e2)
- return FcFalse;
- if (!FcListValueListEqual (FcPatternEltValues(e1),
- FcPatternEltValues(e2)))
- return FcFalse;
- }
- return FcTrue;
-}
-
-/*
- * FcTrue iff all objects in "p" match "font"
- */
-
-FcBool
-FcListPatternMatchAny (const FcPattern *p,
- const FcPattern *font)
-{
- int i;
-
- for (i = 0; i < p->num; i++)
- {
- FcPatternElt *pe = &FcPatternElts(p)[i];
- FcPatternElt *fe = FcPatternObjectFindElt (font, pe->object);
- if (!fe)
- return FcFalse;
- if (!FcListValueListMatchAny (FcPatternEltValues(pe), /* pat elts */
- FcPatternEltValues(fe))) /* font elts */
- return FcFalse;
- }
- return FcTrue;
-}
-
-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 *value)
-{
- FcValue v = FcValueCanonicalize(value);
- 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 FcStrHashIgnoreCase (v.u.s);
- case FcTypeBool:
- return (FcChar32) v.u.b;
- case FcTypeMatrix:
- return FcListMatrixHash (v.u.m);
- case FcTypeCharSet:
- return FcCharSetCount (v.u.c);
- case FcTypeFTFace:
- return (long) v.u.f;
- case FcTypeLangSet:
- return FcLangSetHash (v.u.l);
- }
- return 0;
-}
-
-static FcChar32
-FcListValueListHash (FcValueListPtr list)
-{
- FcChar32 h = 0;
-
- while (list != NULL)
- {
- h = h ^ FcListValueHash (&list->value);
- list = FcValueListNext(list);
- }
- return h;
-}
-
-static FcChar32
-FcListPatternHash (FcPattern *font,
- FcObjectSet *os)
-{
- int n;
- FcPatternElt *e;
- FcChar32 h = 0;
-
- for (n = 0; n < os->nobject; n++)
- {
- e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[n]));
- if (e)
- h = h ^ FcListValueListHash (FcPatternEltValues(e));
- }
- 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 int
-FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object)
-{
- FcChar8 *lang = FcGetDefaultLang ();
- FcPatternElt *e = FcPatternObjectFindElt (font, object);
- FcValueListPtr v;
- FcValue value;
- int idx = -1;
- int i;
-
- if (e)
- {
- for (v = FcPatternEltValues(e), i = 0; v; v = FcValueListNext(v), ++i)
- {
- value = FcValueCanonicalize (&v->value);
-
- if (value.type == FcTypeString)
- {
- FcLangResult res = FcLangCompare (value.u.s, lang);
- if (res == FcLangEqual)
- return i;
-
- if (res == FcLangDifferentCountry && idx < 0)
- idx = i;
- }
- }
- }
-
- return (idx > 0) ? idx : 0;
-}
-
-static FcBool
-FcListAppend (FcListHashTable *table,
- FcPattern *font,
- FcObjectSet *os)
-{
- int o;
- FcPatternElt *e;
- FcValueListPtr v;
- FcChar32 hash;
- FcListBucket **prev, *bucket;
- int familyidx = -1;
- int fullnameidx = -1;
- int styleidx = -1;
- int defidx = 0;
- int idx;
-
- 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++)
- {
- if (!strcmp (os->objects[o], FC_FAMILY) || !strcmp (os->objects[o], FC_FAMILYLANG))
- {
- if (familyidx < 0)
- familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT);
- defidx = familyidx;
- }
- else if (!strcmp (os->objects[o], FC_FULLNAME) || !strcmp (os->objects[o], FC_FULLNAMELANG))
- {
- if (fullnameidx < 0)
- fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT);
- defidx = fullnameidx;
- }
- else if (!strcmp (os->objects[o], FC_STYLE) || !strcmp (os->objects[o], FC_STYLELANG))
- {
- if (styleidx < 0)
- styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT);
- defidx = styleidx;
- }
- else
- defidx = 0;
-
- e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o]));
- if (e)
- {
- for (v = FcPatternEltValues(e), idx = 0; v;
- v = FcValueListNext(v), ++idx)
- {
- if (!FcPatternAdd (bucket->pattern,
- os->objects[o],
- FcValueCanonicalize(&v->value), defidx != idx))
- 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 *
-FcFontSetList (FcConfig *config,
- FcFontSet **sets,
- int nsets,
- FcPattern *p,
- FcObjectSet *os)
-{
- FcFontSet *ret;
- FcFontSet *s;
- int f;
- int set;
- FcListHashTable table;
- int i;
- FcListBucket *bucket;
- int destroy_os = 0;
-
- if (!config)
- {
- if (!FcInitBringUptoDate ())
- goto bail0;
-
- config = FcConfigGetCurrent ();
- if (!config)
- goto bail0;
- }
- FcListHashTableInit (&table);
-
- if (!os)
- {
- os = FcObjectGetSet ();
- destroy_os = 1;
- }
-
- /*
- * Walk all available fonts adding those that
- * match to the hash table
- */
- for (set = 0; set < nsets; set++)
- {
- s = sets[set];
- if (!s)
- continue;
- for (f = 0; f < s->nfont; f++)
- if (FcListPatternMatchAny (p, /* pattern */
- s->fonts[f])) /* font */
- 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:
- if (destroy_os)
- FcObjectSetDestroy (os);
- return 0;
-}
-
-FcFontSet *
-FcFontList (FcConfig *config,
- FcPattern *p,
- FcObjectSet *os)
-{
- FcFontSet *sets[2];
- int nsets;
-
- if (!config)
- {
- if (!FcInitBringUptoDate ())
- return 0;
-
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- nsets = 0;
- if (config->fonts[FcSetSystem])
- sets[nsets++] = config->fonts[FcSetSystem];
- if (config->fonts[FcSetApplication])
- sets[nsets++] = config->fonts[FcSetApplication];
- return FcFontSetList (config, sets, nsets, p, os);
-}
-#define __fclist__
-#include "fcaliastail.h"
-#undef __fclist__
+/* + * fontconfig/src/fclist.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdlib.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; + int high, low, mid, c; + + 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; + } + high = os->nobject - 1; + low = 0; + mid = 0; + c = 1; + object = (char *)FcStrStaticName ((FcChar8 *)object); + while (low <= high) + { + mid = (low + high) >> 1; + c = os->objects[mid] - object; + if (c == 0) + return FcTrue; + if (c < 0) + low = mid + 1; + else + high = mid - 1; + } + if (c < 0) + mid++; + memmove (os->objects + mid + 1, os->objects + mid, + (os->nobject - mid) * sizeof (const char *)); + os->objects[mid] = object; + os->nobject++; + 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; +} + +/* + * Font must have a containing value for every value in the pattern + */ +static FcBool +FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */ + FcValueListPtr fntOrig) /* font */ +{ + FcValueListPtr pat, fnt; + + for (pat = patOrig; pat != NULL; pat = FcValueListNext(pat)) + { + for (fnt = fntOrig; fnt != NULL; fnt = FcValueListNext(fnt)) + { + /* + * make sure the font 'contains' the pattern. + * (OpListing is OpContains except for strings + * where it requires an exact match) + */ + if (FcConfigCompareValue (&fnt->value, + FcOpListing, + &pat->value)) + break; + } + if (fnt == NULL) + return FcFalse; + } + return FcTrue; +} + +static FcBool +FcListValueListEqual (FcValueListPtr v1orig, + FcValueListPtr v2orig) +{ + FcValueListPtr v1, v2; + + for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1)) + { + for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2)) + if (FcValueEqual (FcValueCanonicalize(&(v1)->value), + FcValueCanonicalize(&(v2)->value))) + break; + if (v2 == NULL) + return FcFalse; + } + for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2)) + { + for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1)) + if (FcValueEqual (FcValueCanonicalize(&v1->value), + FcValueCanonicalize(&v2->value))) + break; + if (v1 == NULL) + 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 = FcPatternObjectFindElt (p1, FcObjectFromName (os->objects[i])); + e2 = FcPatternObjectFindElt (p2, FcObjectFromName (os->objects[i])); + if (!e1 && !e2) + continue; + if (!e1 || !e2) + return FcFalse; + if (!FcListValueListEqual (FcPatternEltValues(e1), + FcPatternEltValues(e2))) + return FcFalse; + } + return FcTrue; +} + +/* + * FcTrue iff all objects in "p" match "font" + */ + +FcBool +FcListPatternMatchAny (const FcPattern *p, + const FcPattern *font) +{ + int i; + + for (i = 0; i < p->num; i++) + { + FcPatternElt *pe = &FcPatternElts(p)[i]; + FcPatternElt *fe = FcPatternObjectFindElt (font, pe->object); + if (!fe) + return FcFalse; + if (!FcListValueListMatchAny (FcPatternEltValues(pe), /* pat elts */ + FcPatternEltValues(fe))) /* font elts */ + return FcFalse; + } + return FcTrue; +} + +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 *value) +{ + FcValue v = FcValueCanonicalize(value); + 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 FcStrHashIgnoreCase (v.u.s); + case FcTypeBool: + return (FcChar32) v.u.b; + case FcTypeMatrix: + return FcListMatrixHash (v.u.m); + case FcTypeCharSet: + return FcCharSetCount (v.u.c); + case FcTypeFTFace: + return (long) v.u.f; + case FcTypeLangSet: + return FcLangSetHash (v.u.l); + } + return 0; +} + +static FcChar32 +FcListValueListHash (FcValueListPtr list) +{ + FcChar32 h = 0; + + while (list != NULL) + { + h = h ^ FcListValueHash (&list->value); + list = FcValueListNext(list); + } + return h; +} + +static FcChar32 +FcListPatternHash (FcPattern *font, + FcObjectSet *os) +{ + int n; + FcPatternElt *e; + FcChar32 h = 0; + + for (n = 0; n < os->nobject; n++) + { + e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[n])); + if (e) + h = h ^ FcListValueListHash (FcPatternEltValues(e)); + } + 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 int +FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object) +{ + FcChar8 *lang = FcGetDefaultLang (); + FcPatternElt *e = FcPatternObjectFindElt (font, object); + FcValueListPtr v; + FcValue value; + int idx = -1; + int i; + + if (e) + { + for (v = FcPatternEltValues(e), i = 0; v; v = FcValueListNext(v), ++i) + { + value = FcValueCanonicalize (&v->value); + + if (value.type == FcTypeString) + { + FcLangResult res = FcLangCompare (value.u.s, lang); + if (res == FcLangEqual) + return i; + + if (res == FcLangDifferentCountry && idx < 0) + idx = i; + } + } + } + + return (idx > 0) ? idx : 0; +} + +static FcBool +FcListAppend (FcListHashTable *table, + FcPattern *font, + FcObjectSet *os) +{ + int o; + FcPatternElt *e; + FcValueListPtr v; + FcChar32 hash; + FcListBucket **prev, *bucket; + int familyidx = -1; + int fullnameidx = -1; + int styleidx = -1; + int defidx = 0; + int idx; + + 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++) + { + if (!strcmp (os->objects[o], FC_FAMILY) || !strcmp (os->objects[o], FC_FAMILYLANG)) + { + if (familyidx < 0) + familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT); + defidx = familyidx; + } + else if (!strcmp (os->objects[o], FC_FULLNAME) || !strcmp (os->objects[o], FC_FULLNAMELANG)) + { + if (fullnameidx < 0) + fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT); + defidx = fullnameidx; + } + else if (!strcmp (os->objects[o], FC_STYLE) || !strcmp (os->objects[o], FC_STYLELANG)) + { + if (styleidx < 0) + styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT); + defidx = styleidx; + } + else + defidx = 0; + + e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o])); + if (e) + { + for (v = FcPatternEltValues(e), idx = 0; v; + v = FcValueListNext(v), ++idx) + { + if (!FcPatternAdd (bucket->pattern, + os->objects[o], + FcValueCanonicalize(&v->value), defidx != idx)) + 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 * +FcFontSetList (FcConfig *config, + FcFontSet **sets, + int nsets, + FcPattern *p, + FcObjectSet *os) +{ + FcFontSet *ret; + FcFontSet *s; + int f; + int set; + FcListHashTable table; + int i; + FcListBucket *bucket; + int destroy_os = 0; + + if (!config) + { + if (!FcInitBringUptoDate ()) + goto bail0; + + config = FcConfigGetCurrent (); + if (!config) + goto bail0; + } + FcListHashTableInit (&table); + + if (!os) + { + os = FcObjectGetSet (); + destroy_os = 1; + } + + /* + * Walk all available fonts adding those that + * match to the hash table + */ + for (set = 0; set < nsets; set++) + { + s = sets[set]; + if (!s) + continue; + for (f = 0; f < s->nfont; f++) + if (FcListPatternMatchAny (p, /* pattern */ + s->fonts[f])) /* font */ + 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: + if (destroy_os) + FcObjectSetDestroy (os); + return 0; +} + +FcFontSet * +FcFontList (FcConfig *config, + FcPattern *p, + FcObjectSet *os) +{ + FcFontSet *sets[2]; + int nsets; + + if (!config) + { + if (!FcInitBringUptoDate ()) + return 0; + + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + nsets = 0; + if (config->fonts[FcSetSystem]) + sets[nsets++] = config->fonts[FcSetSystem]; + if (config->fonts[FcSetApplication]) + sets[nsets++] = config->fonts[FcSetApplication]; + return FcFontSetList (config, sets, nsets, p, os); +} +#define __fclist__ +#include "fcaliastail.h" +#undef __fclist__ diff --git a/fontconfig/src/fcmatch.c b/fontconfig/src/fcmatch.c index c6bb11ef2..1b9162b46 100644 --- a/fontconfig/src/fcmatch.c +++ b/fontconfig/src/fcmatch.c @@ -1,840 +1,840 @@ -/*
- * fontconfig/src/fcmatch.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-
-static double
-FcCompareNumber (FcValue *value1, FcValue *value2)
-{
- double v1, v2, v;
-
- switch (value1->type) {
- case FcTypeInteger:
- v1 = (double) value1->u.i;
- break;
- case FcTypeDouble:
- v1 = value1->u.d;
- break;
- default:
- return -1.0;
- }
- switch (value2->type) {
- case FcTypeInteger:
- v2 = (double) value2->u.i;
- break;
- case FcTypeDouble:
- v2 = value2->u.d;
- break;
- default:
- return -1.0;
- }
- v = v2 - v1;
- if (v < 0)
- v = -v;
- return v;
-}
-
-static double
-FcCompareString (FcValue *v1, FcValue *v2)
-{
- return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0;
-}
-
-static double
-FcCompareFamily (FcValue *v1, FcValue *v2)
-{
- /* rely on the guarantee in FcPatternObjectAddWithBinding that
- * families are always FcTypeString. */
- const FcChar8* v1_string = FcValueString(v1);
- const FcChar8* v2_string = FcValueString(v2);
-
- if (FcToLower(*v1_string) != FcToLower(*v2_string) &&
- *v1_string != ' ' && *v2_string != ' ')
- return 1.0;
-
- return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
-}
-
-static double
-FcCompareLang (FcValue *v1, FcValue *v2)
-{
- FcLangResult result;
- FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
-
- switch (value1.type) {
- case FcTypeLangSet:
- switch (value2.type) {
- case FcTypeLangSet:
- result = FcLangSetCompare (value1.u.l, value2.u.l);
- break;
- case FcTypeString:
- result = FcLangSetHasLang (value1.u.l,
- value2.u.s);
- break;
- default:
- return -1.0;
- }
- break;
- case FcTypeString:
- switch (value2.type) {
- case FcTypeLangSet:
- result = FcLangSetHasLang (value2.u.l, value1.u.s);
- break;
- case FcTypeString:
- result = FcLangCompare (value1.u.s,
- value2.u.s);
- break;
- default:
- return -1.0;
- }
- break;
- default:
- return -1.0;
- }
- switch (result) {
- case FcLangEqual:
- return 0;
- case FcLangDifferentCountry:
- return 1;
- case FcLangDifferentLang:
- default:
- return 2;
- }
-}
-
-static double
-FcCompareBool (FcValue *v1, FcValue *v2)
-{
- if (v2->type != FcTypeBool || v1->type != FcTypeBool)
- return -1.0;
- return (double) v2->u.b != v1->u.b;
-}
-
-static double
-FcCompareCharSet (FcValue *v1, FcValue *v2)
-{
- return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2));
-}
-
-static double
-FcCompareSize (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;
-}
-
-typedef struct _FcMatcher {
- FcObject object;
- double (*compare) (FcValue *value1, FcValue *value2);
- int strong, weak;
-} FcMatcher;
-
-/*
- * Order is significant, it defines the precedence of
- * each value, earlier values are more significant than
- * later values
- */
-static const FcMatcher _FcMatchers [] = {
- { FC_FOUNDRY_OBJECT, FcCompareString, 0, 0 },
-#define MATCH_FOUNDRY 0
- { FC_CHARSET_OBJECT, FcCompareCharSet, 1, 1 },
-#define MATCH_CHARSET 1
- { FC_FAMILY_OBJECT, FcCompareFamily, 2, 4 },
-#define MATCH_FAMILY 2
- { FC_LANG_OBJECT, FcCompareLang, 3, 3 },
-#define MATCH_LANG 3
-#define MATCH_LANG_INDEX 3
- { FC_SPACING_OBJECT, FcCompareNumber, 5, 5 },
-#define MATCH_SPACING 4
- { FC_PIXEL_SIZE_OBJECT, FcCompareSize, 6, 6 },
-#define MATCH_PIXEL_SIZE 5
- { FC_STYLE_OBJECT, FcCompareString, 7, 7 },
-#define MATCH_STYLE 6
- { FC_SLANT_OBJECT, FcCompareNumber, 8, 8 },
-#define MATCH_SLANT 7
- { FC_WEIGHT_OBJECT, FcCompareNumber, 9, 9 },
-#define MATCH_WEIGHT 8
- { FC_WIDTH_OBJECT, FcCompareNumber, 10, 10 },
-#define MATCH_WIDTH 9
- { FC_DECORATIVE_OBJECT, FcCompareBool, 11, 11 },
-#define MATCH_DECORATIVE 10
- { FC_ANTIALIAS_OBJECT, FcCompareBool, 12, 12 },
-#define MATCH_ANTIALIAS 11
- { FC_RASTERIZER_OBJECT, FcCompareString, 13, 13 },
-#define MATCH_RASTERIZER 12
- { FC_OUTLINE_OBJECT, FcCompareBool, 14, 14 },
-#define MATCH_OUTLINE 13
- { FC_FONTVERSION_OBJECT, FcCompareNumber, 15, 15 },
-#define MATCH_FONTVERSION 14
-};
-
-#define NUM_MATCH_VALUES 16
-
-static const FcMatcher*
-FcObjectToMatcher (FcObject object)
-{
- int i;
-
- i = -1;
- switch (object) {
- case FC_FOUNDRY_OBJECT:
- i = MATCH_FOUNDRY; break;
- case FC_FONTVERSION_OBJECT:
- i = MATCH_FONTVERSION; break;
- case FC_FAMILY_OBJECT:
- i = MATCH_FAMILY; break;
- case FC_CHARSET_OBJECT:
- i = MATCH_CHARSET; break;
- case FC_ANTIALIAS_OBJECT:
- i = MATCH_ANTIALIAS; break;
- case FC_LANG_OBJECT:
- i = MATCH_LANG; break;
- case FC_SPACING_OBJECT:
- i = MATCH_SPACING; break;
- case FC_STYLE_OBJECT:
- i = MATCH_STYLE; break;
- case FC_SLANT_OBJECT:
- i = MATCH_SLANT; break;
- case FC_PIXEL_SIZE_OBJECT:
- i = MATCH_PIXEL_SIZE; break;
- case FC_WIDTH_OBJECT:
- i = MATCH_WIDTH; break;
- case FC_WEIGHT_OBJECT:
- i = MATCH_WEIGHT; break;
- case FC_RASTERIZER_OBJECT:
- i = MATCH_RASTERIZER; break;
- case FC_OUTLINE_OBJECT:
- i = MATCH_OUTLINE; break;
- case FC_DECORATIVE_OBJECT:
- i = MATCH_DECORATIVE; break;
- }
-
- if (i < 0)
- return NULL;
-
- return _FcMatchers+i;
-}
-
-static FcBool
-FcCompareValueList (FcObject object,
- FcValueListPtr v1orig, /* pattern */
- FcValueListPtr v2orig, /* target */
- FcValue *bestValue,
- double *value,
- FcResult *result)
-{
- FcValueListPtr v1, v2;
- double v, best, bestStrong, bestWeak;
- int j;
- const FcMatcher *match = FcObjectToMatcher(object);
-
- if (!match)
- {
- if (bestValue)
- *bestValue = FcValueCanonicalize(&v2orig->value);
- return FcTrue;
- }
-
- best = 1e99;
- bestStrong = 1e99;
- bestWeak = 1e99;
- j = 1;
- for (v1 = v1orig; v1; v1 = FcValueListNext(v1))
- {
- for (v2 = v2orig; v2; v2 = FcValueListNext(v2))
- {
- v = (match->compare) (&v1->value, &v2->value);
- if (v < 0)
- {
- *result = FcResultTypeMismatch;
- return FcFalse;
- }
- v = v * 1000 + j;
- if (v < best)
- {
- if (bestValue)
- *bestValue = FcValueCanonicalize(&v2->value);
- best = v;
- }
- if (v1->binding == FcValueBindingStrong)
- {
- if (v < bestStrong)
- bestStrong = v;
- }
- else
- {
- if (v < bestWeak)
- bestWeak = v;
- }
- }
- j++;
- }
- if (FcDebug () & FC_DBG_MATCHV)
- {
- printf (" %s: %g ", FcObjectName (object), best);
- FcValueListPrint (v1orig);
- printf (", ");
- FcValueListPrint (v2orig);
- printf ("\n");
- }
- if (value)
- {
- int weak = match->weak;
- int strong = match->strong;
- if (weak == strong)
- value[strong] += best;
- else
- {
- value[weak] += bestWeak;
- value[strong] += bestStrong;
- }
- }
- 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_MATCH_VALUES; i++)
- value[i] = 0.0;
-
- i1 = 0;
- i2 = 0;
- while (i1 < pat->num && i2 < fnt->num)
- {
- FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1];
- FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2];
-
- i = FcObjectCompare(elt_i1->object, elt_i2->object);
- if (i > 0)
- i2++;
- else if (i < 0)
- i1++;
- else
- {
- if (!FcCompareValueList (elt_i1->object,
- FcPatternEltValues(elt_i1),
- FcPatternEltValues(elt_i2),
- 0, value, result))
- return FcFalse;
- i1++;
- i2++;
- }
- }
- return FcTrue;
-}
-
-FcPattern *
-FcFontRenderPrepare (FcConfig *config,
- FcPattern *pat,
- FcPattern *font)
-{
- FcPattern *new;
- int i;
- FcPatternElt *fe, *pe;
- FcValue v;
- FcResult result;
-
- new = FcPatternCreate ();
- if (!new)
- return 0;
- for (i = 0; i < font->num; i++)
- {
- fe = &FcPatternElts(font)[i];
- pe = FcPatternObjectFindElt (pat, fe->object);
- if (pe)
- {
- if (!FcCompareValueList (pe->object, FcPatternEltValues(pe),
- FcPatternEltValues(fe), &v, 0, &result))
- {
- FcPatternDestroy (new);
- return 0;
- }
- }
- else
- v = FcValueCanonicalize(&FcPatternEltValues (fe)->value);
- FcPatternObjectAdd (new, fe->object, v, FcFalse);
- }
- for (i = 0; i < pat->num; i++)
- {
- pe = &FcPatternElts(pat)[i];
- fe = FcPatternObjectFindElt (font, pe->object);
- if (!fe)
- {
- v = FcValueCanonicalize(&FcPatternEltValues(pe)->value);
- FcPatternObjectAdd (new, pe->object, v, FcTrue);
- }
- }
-
- FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
- return new;
-}
-
-static FcPattern *
-FcFontSetMatchInternal (FcConfig *config,
- FcFontSet **sets,
- int nsets,
- FcPattern *p,
- FcResult *result)
-{
- double score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
- int f;
- FcFontSet *s;
- FcPattern *best;
- int i;
- int set;
-
- for (i = 0; i < NUM_MATCH_VALUES; i++)
- bestscore[i] = 0;
- best = 0;
- if (FcDebug () & FC_DBG_MATCH)
- {
- printf ("Match ");
- FcPatternPrint (p);
- }
- for (set = 0; set < nsets; set++)
- {
- s = sets[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_MATCH_VALUES; i++)
- {
- printf (" %g", score[i]);
- }
- printf ("\n");
- }
- for (i = 0; i < NUM_MATCH_VALUES; i++)
- {
- if (best && bestscore[i] < score[i])
- break;
- if (!best || score[i] < bestscore[i])
- {
- for (i = 0; i < NUM_MATCH_VALUES; i++)
- bestscore[i] = score[i];
- best = s->fonts[f];
- break;
- }
- }
- }
- }
- if (FcDebug () & FC_DBG_MATCH)
- {
- printf ("Best score");
- for (i = 0; i < NUM_MATCH_VALUES; i++)
- printf (" %g", bestscore[i]);
- printf ("\n");
- FcPatternPrint (best);
- }
- if (!best)
- {
- *result = FcResultNoMatch;
- return 0;
- }
- return best;
-}
-
-FcPattern *
-FcFontSetMatch (FcConfig *config,
- FcFontSet **sets,
- int nsets,
- FcPattern *p,
- FcResult *result)
-{
- FcPattern *best;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- best = FcFontSetMatchInternal (config, sets, nsets, p, result);
- if (best)
- return FcFontRenderPrepare (config, p, best);
- else
- return NULL;
-}
-
-FcPattern *
-FcFontMatch (FcConfig *config,
- FcPattern *p,
- FcResult *result)
-{
- FcFontSet *sets[2];
- int nsets;
- FcPattern *best;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- nsets = 0;
- if (config->fonts[FcSetSystem])
- sets[nsets++] = config->fonts[FcSetSystem];
- if (config->fonts[FcSetApplication])
- sets[nsets++] = config->fonts[FcSetApplication];
-
- best = FcFontSetMatchInternal (config, sets, nsets, p, result);
- if (best)
- return FcFontRenderPrepare (config, p, best);
- else
- return NULL;
-}
-
-typedef struct _FcSortNode {
- FcPattern *pattern;
- double score[NUM_MATCH_VALUES];
-} FcSortNode;
-
-static int
-FcSortCompare (const void *aa, const void *ab)
-{
- FcSortNode *a = *(FcSortNode **) aa;
- FcSortNode *b = *(FcSortNode **) ab;
- double *as = &a->score[0];
- double *bs = &b->score[0];
- double ad = 0, bd = 0;
- int i;
-
- i = NUM_MATCH_VALUES;
- while (i-- && (ad = *as++) == (bd = *bs++))
- ;
- return ad < bd ? -1 : ad > bd ? 1 : 0;
-}
-
-static FcBool
-FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
-{
- FcBool ret = FcFalse;
- FcCharSet *cs;
-
- cs = 0;
- if (trim || csp)
- {
- cs = FcCharSetCreate ();
- if (cs == NULL)
- goto bail;
- }
-
- while (nnode--)
- {
- FcSortNode *node = *n++;
- FcBool adds_chars = FcFalse;
-
- /*
- * Only fetch node charset if we'd need it
- */
- if (cs)
- {
- FcCharSet *ncs;
-
- if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
- FcResultMatch)
- continue;
-
- if (!FcCharSetMerge (cs, ncs, &adds_chars))
- goto bail;
- }
-
- /*
- * If this font isn't a subset of the previous fonts,
- * add it to the list
- */
- if (!trim || adds_chars)
- {
- FcPatternReference (node->pattern);
- if (FcDebug () & FC_DBG_MATCHV)
- {
- printf ("Add ");
- FcPatternPrint (node->pattern);
- }
- if (!FcFontSetAdd (fs, node->pattern))
- {
- FcPatternDestroy (node->pattern);
- goto bail;
- }
- }
- }
- if (csp)
- {
- *csp = cs;
- cs = 0;
- }
-
- ret = FcTrue;
-
-bail:
- if (cs)
- FcCharSetDestroy (cs);
-
- return ret;
-}
-
-void
-FcFontSetSortDestroy (FcFontSet *fs)
-{
- FcFontSetDestroy (fs);
-}
-
-FcFontSet *
-FcFontSetSort (FcConfig *config,
- FcFontSet **sets,
- int nsets,
- FcPattern *p,
- FcBool trim,
- FcCharSet **csp,
- FcResult *result)
-{
- FcFontSet *ret;
- FcFontSet *s;
- FcSortNode *nodes;
- FcSortNode **nodeps, **nodep;
- int nnodes;
- FcSortNode *new;
- int set;
- int f;
- int i;
- int nPatternLang;
- FcBool *patternLangSat;
- FcValue patternLang;
-
- if (FcDebug () & FC_DBG_MATCH)
- {
- printf ("Sort ");
- FcPatternPrint (p);
- }
- nnodes = 0;
- for (set = 0; set < nsets; set++)
- {
- s = sets[set];
- if (!s)
- continue;
- nnodes += s->nfont;
- }
- if (!nnodes)
- goto bail0;
-
- for (nPatternLang = 0;
- FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
- nPatternLang++)
- ;
-
- /* freed below */
- nodes = malloc (nnodes * sizeof (FcSortNode) +
- nnodes * sizeof (FcSortNode *) +
- nPatternLang * sizeof (FcBool));
- if (!nodes)
- goto bail0;
- nodeps = (FcSortNode **) (nodes + nnodes);
- patternLangSat = (FcBool *) (nodeps + nnodes);
-
- new = nodes;
- nodep = nodeps;
- for (set = 0; set < nsets; set++)
- {
- s = sets[set];
- if (!s)
- continue;
- for (f = 0; f < s->nfont; f++)
- {
- if (FcDebug () & FC_DBG_MATCHV)
- {
- printf ("Font %d ", f);
- FcPatternPrint (s->fonts[f]);
- }
- new->pattern = s->fonts[f];
- if (!FcCompare (p, new->pattern, new->score, result))
- goto bail1;
- if (FcDebug () & FC_DBG_MATCHV)
- {
- printf ("Score");
- for (i = 0; i < NUM_MATCH_VALUES; i++)
- {
- printf (" %g", new->score[i]);
- }
- printf ("\n");
- }
- *nodep = new;
- new++;
- nodep++;
- }
- }
-
- nnodes = new - nodes;
-
- qsort (nodeps, nnodes, sizeof (FcSortNode *),
- FcSortCompare);
-
- for (i = 0; i < nPatternLang; i++)
- patternLangSat[i] = FcFalse;
-
- for (f = 0; f < nnodes; f++)
- {
- FcBool satisfies = FcFalse;
- /*
- * If this node matches any language, go check
- * which ones and satisfy those entries
- */
- if (nodeps[f]->score[MATCH_LANG_INDEX] < 2000)
- {
- for (i = 0; i < nPatternLang; i++)
- {
- FcValue nodeLang;
-
- if (!patternLangSat[i] &&
- FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
- FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
- {
- double compare = FcCompareLang (&patternLang, &nodeLang);
- if (compare >= 0 && compare < 2)
- {
- if (FcDebug () & FC_DBG_MATCHV)
- {
- FcChar8 *family;
- FcChar8 *style;
-
- if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
- FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
- printf ("Font %s:%s matches language %d\n", family, style, i);
- }
- patternLangSat[i] = FcTrue;
- satisfies = FcTrue;
- break;
- }
- }
- }
- }
- if (!satisfies)
- nodeps[f]->score[MATCH_LANG_INDEX] = 10000.0;
- }
-
- /*
- * Re-sort once the language issues have been settled
- */
- qsort (nodeps, nnodes, sizeof (FcSortNode *),
- FcSortCompare);
-
- ret = FcFontSetCreate ();
- if (!ret)
- goto bail1;
-
- if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
- goto bail2;
-
- free (nodes);
-
- if (FcDebug() & FC_DBG_MATCH)
- {
- printf ("First font ");
- FcPatternPrint (ret->fonts[0]);
- }
- return ret;
-
-bail2:
- FcFontSetDestroy (ret);
-bail1:
- free (nodes);
-bail0:
- return 0;
-}
-
-FcFontSet *
-FcFontSort (FcConfig *config,
- FcPattern *p,
- FcBool trim,
- FcCharSet **csp,
- FcResult *result)
-{
- FcFontSet *sets[2];
- int nsets;
-
- if (!config)
- {
- config = FcConfigGetCurrent ();
- if (!config)
- return 0;
- }
- nsets = 0;
- if (config->fonts[FcSetSystem])
- sets[nsets++] = config->fonts[FcSetSystem];
- if (config->fonts[FcSetApplication])
- sets[nsets++] = config->fonts[FcSetApplication];
- return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
-}
-#define __fcmatch__
-#include "fcaliastail.h"
-#undef __fcmatch__
+/* + * fontconfig/src/fcmatch.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <string.h> +#include <ctype.h> +#include <stdio.h> + +static double +FcCompareNumber (FcValue *value1, FcValue *value2) +{ + double v1, v2, v; + + switch (value1->type) { + case FcTypeInteger: + v1 = (double) value1->u.i; + break; + case FcTypeDouble: + v1 = value1->u.d; + break; + default: + return -1.0; + } + switch (value2->type) { + case FcTypeInteger: + v2 = (double) value2->u.i; + break; + case FcTypeDouble: + v2 = value2->u.d; + break; + default: + return -1.0; + } + v = v2 - v1; + if (v < 0) + v = -v; + return v; +} + +static double +FcCompareString (FcValue *v1, FcValue *v2) +{ + return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0; +} + +static double +FcCompareFamily (FcValue *v1, FcValue *v2) +{ + /* rely on the guarantee in FcPatternObjectAddWithBinding that + * families are always FcTypeString. */ + const FcChar8* v1_string = FcValueString(v1); + const FcChar8* v2_string = FcValueString(v2); + + if (FcToLower(*v1_string) != FcToLower(*v2_string) && + *v1_string != ' ' && *v2_string != ' ') + return 1.0; + + return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0; +} + +static double +FcCompareLang (FcValue *v1, FcValue *v2) +{ + FcLangResult result; + FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2); + + switch (value1.type) { + case FcTypeLangSet: + switch (value2.type) { + case FcTypeLangSet: + result = FcLangSetCompare (value1.u.l, value2.u.l); + break; + case FcTypeString: + result = FcLangSetHasLang (value1.u.l, + value2.u.s); + break; + default: + return -1.0; + } + break; + case FcTypeString: + switch (value2.type) { + case FcTypeLangSet: + result = FcLangSetHasLang (value2.u.l, value1.u.s); + break; + case FcTypeString: + result = FcLangCompare (value1.u.s, + value2.u.s); + break; + default: + return -1.0; + } + break; + default: + return -1.0; + } + switch (result) { + case FcLangEqual: + return 0; + case FcLangDifferentCountry: + return 1; + case FcLangDifferentLang: + default: + return 2; + } +} + +static double +FcCompareBool (FcValue *v1, FcValue *v2) +{ + if (v2->type != FcTypeBool || v1->type != FcTypeBool) + return -1.0; + return (double) v2->u.b != v1->u.b; +} + +static double +FcCompareCharSet (FcValue *v1, FcValue *v2) +{ + return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2)); +} + +static double +FcCompareSize (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; +} + +typedef struct _FcMatcher { + FcObject object; + double (*compare) (FcValue *value1, FcValue *value2); + int strong, weak; +} FcMatcher; + +/* + * Order is significant, it defines the precedence of + * each value, earlier values are more significant than + * later values + */ +static const FcMatcher _FcMatchers [] = { + { FC_FOUNDRY_OBJECT, FcCompareString, 0, 0 }, +#define MATCH_FOUNDRY 0 + { FC_CHARSET_OBJECT, FcCompareCharSet, 1, 1 }, +#define MATCH_CHARSET 1 + { FC_FAMILY_OBJECT, FcCompareFamily, 2, 4 }, +#define MATCH_FAMILY 2 + { FC_LANG_OBJECT, FcCompareLang, 3, 3 }, +#define MATCH_LANG 3 +#define MATCH_LANG_INDEX 3 + { FC_SPACING_OBJECT, FcCompareNumber, 5, 5 }, +#define MATCH_SPACING 4 + { FC_PIXEL_SIZE_OBJECT, FcCompareSize, 6, 6 }, +#define MATCH_PIXEL_SIZE 5 + { FC_STYLE_OBJECT, FcCompareString, 7, 7 }, +#define MATCH_STYLE 6 + { FC_SLANT_OBJECT, FcCompareNumber, 8, 8 }, +#define MATCH_SLANT 7 + { FC_WEIGHT_OBJECT, FcCompareNumber, 9, 9 }, +#define MATCH_WEIGHT 8 + { FC_WIDTH_OBJECT, FcCompareNumber, 10, 10 }, +#define MATCH_WIDTH 9 + { FC_DECORATIVE_OBJECT, FcCompareBool, 11, 11 }, +#define MATCH_DECORATIVE 10 + { FC_ANTIALIAS_OBJECT, FcCompareBool, 12, 12 }, +#define MATCH_ANTIALIAS 11 + { FC_RASTERIZER_OBJECT, FcCompareString, 13, 13 }, +#define MATCH_RASTERIZER 12 + { FC_OUTLINE_OBJECT, FcCompareBool, 14, 14 }, +#define MATCH_OUTLINE 13 + { FC_FONTVERSION_OBJECT, FcCompareNumber, 15, 15 }, +#define MATCH_FONTVERSION 14 +}; + +#define NUM_MATCH_VALUES 16 + +static const FcMatcher* +FcObjectToMatcher (FcObject object) +{ + int i; + + i = -1; + switch (object) { + case FC_FOUNDRY_OBJECT: + i = MATCH_FOUNDRY; break; + case FC_FONTVERSION_OBJECT: + i = MATCH_FONTVERSION; break; + case FC_FAMILY_OBJECT: + i = MATCH_FAMILY; break; + case FC_CHARSET_OBJECT: + i = MATCH_CHARSET; break; + case FC_ANTIALIAS_OBJECT: + i = MATCH_ANTIALIAS; break; + case FC_LANG_OBJECT: + i = MATCH_LANG; break; + case FC_SPACING_OBJECT: + i = MATCH_SPACING; break; + case FC_STYLE_OBJECT: + i = MATCH_STYLE; break; + case FC_SLANT_OBJECT: + i = MATCH_SLANT; break; + case FC_PIXEL_SIZE_OBJECT: + i = MATCH_PIXEL_SIZE; break; + case FC_WIDTH_OBJECT: + i = MATCH_WIDTH; break; + case FC_WEIGHT_OBJECT: + i = MATCH_WEIGHT; break; + case FC_RASTERIZER_OBJECT: + i = MATCH_RASTERIZER; break; + case FC_OUTLINE_OBJECT: + i = MATCH_OUTLINE; break; + case FC_DECORATIVE_OBJECT: + i = MATCH_DECORATIVE; break; + } + + if (i < 0) + return NULL; + + return _FcMatchers+i; +} + +static FcBool +FcCompareValueList (FcObject object, + FcValueListPtr v1orig, /* pattern */ + FcValueListPtr v2orig, /* target */ + FcValue *bestValue, + double *value, + FcResult *result) +{ + FcValueListPtr v1, v2; + double v, best, bestStrong, bestWeak; + int j; + const FcMatcher *match = FcObjectToMatcher(object); + + if (!match) + { + if (bestValue) + *bestValue = FcValueCanonicalize(&v2orig->value); + return FcTrue; + } + + best = 1e99; + bestStrong = 1e99; + bestWeak = 1e99; + j = 1; + for (v1 = v1orig; v1; v1 = FcValueListNext(v1)) + { + for (v2 = v2orig; v2; v2 = FcValueListNext(v2)) + { + v = (match->compare) (&v1->value, &v2->value); + if (v < 0) + { + *result = FcResultTypeMismatch; + return FcFalse; + } + v = v * 1000 + j; + if (v < best) + { + if (bestValue) + *bestValue = FcValueCanonicalize(&v2->value); + best = v; + } + if (v1->binding == FcValueBindingStrong) + { + if (v < bestStrong) + bestStrong = v; + } + else + { + if (v < bestWeak) + bestWeak = v; + } + } + j++; + } + if (FcDebug () & FC_DBG_MATCHV) + { + printf (" %s: %g ", FcObjectName (object), best); + FcValueListPrint (v1orig); + printf (", "); + FcValueListPrint (v2orig); + printf ("\n"); + } + if (value) + { + int weak = match->weak; + int strong = match->strong; + if (weak == strong) + value[strong] += best; + else + { + value[weak] += bestWeak; + value[strong] += bestStrong; + } + } + 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_MATCH_VALUES; i++) + value[i] = 0.0; + + i1 = 0; + i2 = 0; + while (i1 < pat->num && i2 < fnt->num) + { + FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1]; + FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2]; + + i = FcObjectCompare(elt_i1->object, elt_i2->object); + if (i > 0) + i2++; + else if (i < 0) + i1++; + else + { + if (!FcCompareValueList (elt_i1->object, + FcPatternEltValues(elt_i1), + FcPatternEltValues(elt_i2), + 0, value, result)) + return FcFalse; + i1++; + i2++; + } + } + return FcTrue; +} + +FcPattern * +FcFontRenderPrepare (FcConfig *config, + FcPattern *pat, + FcPattern *font) +{ + FcPattern *new; + int i; + FcPatternElt *fe, *pe; + FcValue v; + FcResult result; + + new = FcPatternCreate (); + if (!new) + return 0; + for (i = 0; i < font->num; i++) + { + fe = &FcPatternElts(font)[i]; + pe = FcPatternObjectFindElt (pat, fe->object); + if (pe) + { + if (!FcCompareValueList (pe->object, FcPatternEltValues(pe), + FcPatternEltValues(fe), &v, 0, &result)) + { + FcPatternDestroy (new); + return 0; + } + } + else + v = FcValueCanonicalize(&FcPatternEltValues (fe)->value); + FcPatternObjectAdd (new, fe->object, v, FcFalse); + } + for (i = 0; i < pat->num; i++) + { + pe = &FcPatternElts(pat)[i]; + fe = FcPatternObjectFindElt (font, pe->object); + if (!fe) + { + v = FcValueCanonicalize(&FcPatternEltValues(pe)->value); + FcPatternObjectAdd (new, pe->object, v, FcTrue); + } + } + + FcConfigSubstituteWithPat (config, new, pat, FcMatchFont); + return new; +} + +static FcPattern * +FcFontSetMatchInternal (FcConfig *config, + FcFontSet **sets, + int nsets, + FcPattern *p, + FcResult *result) +{ + double score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES]; + int f; + FcFontSet *s; + FcPattern *best; + int i; + int set; + + for (i = 0; i < NUM_MATCH_VALUES; i++) + bestscore[i] = 0; + best = 0; + if (FcDebug () & FC_DBG_MATCH) + { + printf ("Match "); + FcPatternPrint (p); + } + for (set = 0; set < nsets; set++) + { + s = sets[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_MATCH_VALUES; i++) + { + printf (" %g", score[i]); + } + printf ("\n"); + } + for (i = 0; i < NUM_MATCH_VALUES; i++) + { + if (best && bestscore[i] < score[i]) + break; + if (!best || score[i] < bestscore[i]) + { + for (i = 0; i < NUM_MATCH_VALUES; i++) + bestscore[i] = score[i]; + best = s->fonts[f]; + break; + } + } + } + } + if (FcDebug () & FC_DBG_MATCH) + { + printf ("Best score"); + for (i = 0; i < NUM_MATCH_VALUES; i++) + printf (" %g", bestscore[i]); + printf ("\n"); + FcPatternPrint (best); + } + if (!best) + { + *result = FcResultNoMatch; + return 0; + } + return best; +} + +FcPattern * +FcFontSetMatch (FcConfig *config, + FcFontSet **sets, + int nsets, + FcPattern *p, + FcResult *result) +{ + FcPattern *best; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + best = FcFontSetMatchInternal (config, sets, nsets, p, result); + if (best) + return FcFontRenderPrepare (config, p, best); + else + return NULL; +} + +FcPattern * +FcFontMatch (FcConfig *config, + FcPattern *p, + FcResult *result) +{ + FcFontSet *sets[2]; + int nsets; + FcPattern *best; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + nsets = 0; + if (config->fonts[FcSetSystem]) + sets[nsets++] = config->fonts[FcSetSystem]; + if (config->fonts[FcSetApplication]) + sets[nsets++] = config->fonts[FcSetApplication]; + + best = FcFontSetMatchInternal (config, sets, nsets, p, result); + if (best) + return FcFontRenderPrepare (config, p, best); + else + return NULL; +} + +typedef struct _FcSortNode { + FcPattern *pattern; + double score[NUM_MATCH_VALUES]; +} FcSortNode; + +static int +FcSortCompare (const void *aa, const void *ab) +{ + FcSortNode *a = *(FcSortNode **) aa; + FcSortNode *b = *(FcSortNode **) ab; + double *as = &a->score[0]; + double *bs = &b->score[0]; + double ad = 0, bd = 0; + int i; + + i = NUM_MATCH_VALUES; + while (i-- && (ad = *as++) == (bd = *bs++)) + ; + return ad < bd ? -1 : ad > bd ? 1 : 0; +} + +static FcBool +FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim) +{ + FcBool ret = FcFalse; + FcCharSet *cs; + + cs = 0; + if (trim || csp) + { + cs = FcCharSetCreate (); + if (cs == NULL) + goto bail; + } + + while (nnode--) + { + FcSortNode *node = *n++; + FcBool adds_chars = FcFalse; + + /* + * Only fetch node charset if we'd need it + */ + if (cs) + { + FcCharSet *ncs; + + if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) != + FcResultMatch) + continue; + + if (!FcCharSetMerge (cs, ncs, &adds_chars)) + goto bail; + } + + /* + * If this font isn't a subset of the previous fonts, + * add it to the list + */ + if (!trim || adds_chars) + { + FcPatternReference (node->pattern); + if (FcDebug () & FC_DBG_MATCHV) + { + printf ("Add "); + FcPatternPrint (node->pattern); + } + if (!FcFontSetAdd (fs, node->pattern)) + { + FcPatternDestroy (node->pattern); + goto bail; + } + } + } + if (csp) + { + *csp = cs; + cs = 0; + } + + ret = FcTrue; + +bail: + if (cs) + FcCharSetDestroy (cs); + + return ret; +} + +void +FcFontSetSortDestroy (FcFontSet *fs) +{ + FcFontSetDestroy (fs); +} + +FcFontSet * +FcFontSetSort (FcConfig *config, + FcFontSet **sets, + int nsets, + FcPattern *p, + FcBool trim, + FcCharSet **csp, + FcResult *result) +{ + FcFontSet *ret; + FcFontSet *s; + FcSortNode *nodes; + FcSortNode **nodeps, **nodep; + int nnodes; + FcSortNode *new; + int set; + int f; + int i; + int nPatternLang; + FcBool *patternLangSat; + FcValue patternLang; + + if (FcDebug () & FC_DBG_MATCH) + { + printf ("Sort "); + FcPatternPrint (p); + } + nnodes = 0; + for (set = 0; set < nsets; set++) + { + s = sets[set]; + if (!s) + continue; + nnodes += s->nfont; + } + if (!nnodes) + goto bail0; + + for (nPatternLang = 0; + FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch; + nPatternLang++) + ; + + /* freed below */ + nodes = malloc (nnodes * sizeof (FcSortNode) + + nnodes * sizeof (FcSortNode *) + + nPatternLang * sizeof (FcBool)); + if (!nodes) + goto bail0; + nodeps = (FcSortNode **) (nodes + nnodes); + patternLangSat = (FcBool *) (nodeps + nnodes); + + new = nodes; + nodep = nodeps; + for (set = 0; set < nsets; set++) + { + s = sets[set]; + if (!s) + continue; + for (f = 0; f < s->nfont; f++) + { + if (FcDebug () & FC_DBG_MATCHV) + { + printf ("Font %d ", f); + FcPatternPrint (s->fonts[f]); + } + new->pattern = s->fonts[f]; + if (!FcCompare (p, new->pattern, new->score, result)) + goto bail1; + if (FcDebug () & FC_DBG_MATCHV) + { + printf ("Score"); + for (i = 0; i < NUM_MATCH_VALUES; i++) + { + printf (" %g", new->score[i]); + } + printf ("\n"); + } + *nodep = new; + new++; + nodep++; + } + } + + nnodes = new - nodes; + + qsort (nodeps, nnodes, sizeof (FcSortNode *), + FcSortCompare); + + for (i = 0; i < nPatternLang; i++) + patternLangSat[i] = FcFalse; + + for (f = 0; f < nnodes; f++) + { + FcBool satisfies = FcFalse; + /* + * If this node matches any language, go check + * which ones and satisfy those entries + */ + if (nodeps[f]->score[MATCH_LANG_INDEX] < 2000) + { + for (i = 0; i < nPatternLang; i++) + { + FcValue nodeLang; + + if (!patternLangSat[i] && + FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch && + FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch) + { + double compare = FcCompareLang (&patternLang, &nodeLang); + if (compare >= 0 && compare < 2) + { + if (FcDebug () & FC_DBG_MATCHV) + { + FcChar8 *family; + FcChar8 *style; + + if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch && + FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch) + printf ("Font %s:%s matches language %d\n", family, style, i); + } + patternLangSat[i] = FcTrue; + satisfies = FcTrue; + break; + } + } + } + } + if (!satisfies) + nodeps[f]->score[MATCH_LANG_INDEX] = 10000.0; + } + + /* + * Re-sort once the language issues have been settled + */ + qsort (nodeps, nnodes, sizeof (FcSortNode *), + FcSortCompare); + + ret = FcFontSetCreate (); + if (!ret) + goto bail1; + + if (!FcSortWalk (nodeps, nnodes, ret, csp, trim)) + goto bail2; + + free (nodes); + + if (FcDebug() & FC_DBG_MATCH) + { + printf ("First font "); + FcPatternPrint (ret->fonts[0]); + } + return ret; + +bail2: + FcFontSetDestroy (ret); +bail1: + free (nodes); +bail0: + return 0; +} + +FcFontSet * +FcFontSort (FcConfig *config, + FcPattern *p, + FcBool trim, + FcCharSet **csp, + FcResult *result) +{ + FcFontSet *sets[2]; + int nsets; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + nsets = 0; + if (config->fonts[FcSetSystem]) + sets[nsets++] = config->fonts[FcSetSystem]; + if (config->fonts[FcSetApplication]) + sets[nsets++] = config->fonts[FcSetApplication]; + return FcFontSetSort (config, sets, nsets, p, trim, csp, result); +} +#define __fcmatch__ +#include "fcaliastail.h" +#undef __fcmatch__ diff --git a/fontconfig/src/fcmatrix.c b/fontconfig/src/fcmatrix.c index 2daa0044f..f0c613918 100644 --- a/fontconfig/src/fcmatrix.c +++ b/fontconfig/src/fcmatrix.c @@ -1,120 +1,120 @@ -/*
- * fontconfig/src/fcmatrix.c
- *
- * 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 "fcint.h"
-#include <math.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-const FcMatrix FcIdentityMatrix = { 1, 0, 0, 1 };
-
-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)
-{
- if (mat != &FcIdentityMatrix)
- {
- 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);
-}
-#define __fcmatrix__
-#include "fcaliastail.h"
-#undef __fcmatrix__
+/* + * fontconfig/src/fcmatrix.c + * + * 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 "fcint.h" +#include <math.h> +#include <stdlib.h> +#include <ctype.h> + +const FcMatrix FcIdentityMatrix = { 1, 0, 0, 1 }; + +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) +{ + if (mat != &FcIdentityMatrix) + { + 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); +} +#define __fcmatrix__ +#include "fcaliastail.h" +#undef __fcmatrix__ diff --git a/fontconfig/src/fcname.c b/fontconfig/src/fcname.c index 98b50b457..d77eff6f7 100644 --- a/fontconfig/src/fcname.c +++ b/fontconfig/src/fcname.c @@ -1,902 +1,902 @@ -/*
- * fontconfig/src/fcname.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-/*
- * Please do not change this list, it is used to initialize the object
- * list in this order to match the FC_foo_OBJECT constants. Those
- * constants are written into cache files.
- */
-
-static const FcObjectType _FcBaseObjectTypes[] = {
- { FC_FAMILY, FcTypeString, }, /* 1 */
- { FC_FAMILYLANG, FcTypeString, },
- { FC_STYLE, FcTypeString, },
- { FC_STYLELANG, FcTypeString, },
- { FC_FULLNAME, FcTypeString, },
- { FC_FULLNAMELANG, FcTypeString, },
- { FC_SLANT, FcTypeInteger, },
- { FC_WEIGHT, FcTypeInteger, },
- { FC_WIDTH, FcTypeInteger, },
- { FC_SIZE, FcTypeDouble, },
- { FC_ASPECT, FcTypeDouble, },
- { FC_PIXEL_SIZE, FcTypeDouble, },
- { FC_SPACING, FcTypeInteger, },
- { FC_FOUNDRY, FcTypeString, },
- { FC_ANTIALIAS, FcTypeBool, },
- { FC_HINT_STYLE, FcTypeInteger, },
- { FC_HINTING, FcTypeBool, },
- { FC_VERTICAL_LAYOUT, FcTypeBool, },
- { FC_AUTOHINT, FcTypeBool, },
- { FC_GLOBAL_ADVANCE, FcTypeBool, },
- { FC_FILE, FcTypeString, },
- { FC_INDEX, FcTypeInteger, },
- { FC_RASTERIZER, FcTypeString, },
- { FC_OUTLINE, FcTypeBool, },
- { FC_SCALABLE, FcTypeBool, },
- { FC_DPI, FcTypeDouble },
- { FC_RGBA, FcTypeInteger, },
- { FC_SCALE, FcTypeDouble, },
- { FC_MINSPACE, FcTypeBool, },
- { FC_CHAR_WIDTH, FcTypeInteger },
- { FC_CHAR_HEIGHT, FcTypeInteger },
- { FC_MATRIX, FcTypeMatrix },
- { FC_CHARSET, FcTypeCharSet },
- { FC_LANG, FcTypeLangSet },
- { FC_FONTVERSION, FcTypeInteger },
- { FC_CAPABILITY, FcTypeString },
- { FC_FONTFORMAT, FcTypeString },
- { FC_EMBOLDEN, FcTypeBool },
- { FC_EMBEDDED_BITMAP, FcTypeBool },
- { FC_DECORATIVE, FcTypeBool },
- { FC_LCD_FILTER, FcTypeInteger }, /* 41 */
-};
-
-#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;
-
-#define OBJECT_HASH_SIZE 31
-
-typedef struct _FcObjectBucket {
- struct _FcObjectBucket *next;
- FcChar32 hash;
- FcObject id;
-} FcObjectBucket;
-
-static FcObjectBucket *FcObjectBuckets[OBJECT_HASH_SIZE];
-
-static FcObjectType *FcObjects = (FcObjectType *) _FcBaseObjectTypes;
-static int FcObjectsNumber = NUM_OBJECT_TYPES;
-static int FcObjectsSize = 0;
-static FcBool FcObjectsInited;
-
-static FcObjectType *
-FcObjectInsert (const char *name, FcType type)
-{
- FcObjectType *o;
- if (FcObjectsNumber >= FcObjectsSize)
- {
- int newsize = FcObjectsNumber * 2;
- FcObjectType *newobjects;
-
- if (FcObjectsSize)
- newobjects = realloc (FcObjects, newsize * sizeof (FcObjectType));
- else
- {
- newobjects = malloc (newsize * sizeof (FcObjectType));
- if (newobjects)
- memcpy (newobjects, FcObjects,
- FcObjectsNumber * sizeof (FcObjectType));
- }
- if (!newobjects)
- return NULL;
- FcObjects = newobjects;
- FcObjectsSize = newsize;
- }
- o = &FcObjects[FcObjectsNumber];
- o->object = name;
- o->type = type;
- ++FcObjectsNumber;
- return o;
-}
-
-static FcObject
-FcObjectId (FcObjectType *o)
-{
- return o - FcObjects + 1;
-}
-
-static FcObjectType *
-FcObjectFindByName (const char *object, FcBool insert)
-{
- FcChar32 hash = FcStringHash ((const FcChar8 *) object);
- FcObjectBucket **p;
- FcObjectBucket *b;
- FcObjectType *o;
-
- if (!FcObjectsInited)
- FcObjectInit ();
- for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
- {
- o = FcObjects + b->id - 1;
- if (b->hash == hash && !strcmp (object, (o->object)))
- return o;
- }
- if (!insert)
- return NULL;
- /*
- * Hook it into the hash chain
- */
- b = malloc (sizeof(FcObjectBucket));
- if (!b)
- return NULL;
- object = (const char *) FcStrCopy ((FcChar8 *) object);
- if (!object) {
- free (b);
- return NULL;
- }
- o = FcObjectInsert (object, -1);
- b->next = NULL;
- b->hash = hash;
- b->id = FcObjectId (o);
- *p = b;
- return o;
-}
-
-static FcObjectType *
-FcObjectFindById (FcObject object)
-{
- if (1 <= object && object <= FcObjectsNumber)
- return FcObjects + object - 1;
- return NULL;
-}
-
-static FcBool
-FcObjectHashInsert (const FcObjectType *object, FcBool copy)
-{
- FcChar32 hash = FcStringHash ((const FcChar8 *) object->object);
- FcObjectBucket **p;
- FcObjectBucket *b;
- FcObjectType *o;
-
- if (!FcObjectsInited)
- FcObjectInit ();
- for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
- {
- o = FcObjects + b->id - 1;
- if (b->hash == hash && !strcmp (object->object, o->object))
- return FcFalse;
- }
- /*
- * Hook it into the hash chain
- */
- b = malloc (sizeof(FcObjectBucket));
- if (!b)
- return FcFalse;
- if (copy)
- {
- o = FcObjectInsert (object->object, object->type);
- if (!o)
- {
- free (b);
- return FcFalse;
- }
- }
- else
- o = (FcObjectType *) object;
- b->next = NULL;
- b->hash = hash;
- b->id = FcObjectId (o);
- *p = b;
- return FcTrue;
-}
-
-static void
-FcObjectHashRemove (const FcObjectType *object, FcBool cleanobj)
-{
- FcChar32 hash = FcStringHash ((const FcChar8 *) object->object);
- FcObjectBucket **p;
- FcObjectBucket *b;
- FcObjectType *o;
-
- if (!FcObjectsInited)
- FcObjectInit ();
- for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
- {
- o = FcObjects + b->id - 1;
- if (b->hash == hash && !strcmp (object->object, o->object))
- {
- *p = b->next;
- free (b);
- if (cleanobj)
- {
- /* Clean up object array */
- o->object = NULL;
- o->type = -1;
- while (FcObjects[FcObjectsNumber-1].object == NULL)
- --FcObjectsNumber;
- }
- break;
- }
- }
-}
-
-FcBool
-FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
-{
- int i;
-
- for (i = 0; i < ntypes; i++)
- if (!FcObjectHashInsert (&types[i], FcTrue))
- return FcFalse;
- return FcTrue;
-}
-
-FcBool
-FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
-{
- int i;
-
- for (i = 0; i < ntypes; i++)
- FcObjectHashRemove (&types[i], FcTrue);
- return FcTrue;
-}
-
-const FcObjectType *
-FcNameGetObjectType (const char *object)
-{
- return FcObjectFindByName (object, FcFalse);
-}
-
-FcBool
-FcObjectValidType (FcObject object, FcType type)
-{
- FcObjectType *t = FcObjectFindById (object);
-
- if (t) {
- switch (t->type) {
- case -1:
- return FcTrue;
- case FcTypeDouble:
- case FcTypeInteger:
- if (type == FcTypeDouble || type == FcTypeInteger)
- return FcTrue;
- break;
- case FcTypeLangSet:
- if (type == FcTypeLangSet || type == FcTypeString)
- return FcTrue;
- break;
- default:
- if (type == t->type)
- return FcTrue;
- break;
- }
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcObject
-FcObjectFromName (const char * name)
-{
- FcObjectType *o = FcObjectFindByName (name, FcTrue);
-
- if (o)
- return FcObjectId (o);
- return 0;
-}
-
-FcObjectSet *
-FcObjectGetSet (void)
-{
- int i;
- FcObjectSet *os = NULL;
-
-
- os = FcObjectSetCreate ();
- for (i = 0; i < FcObjectsNumber; i++)
- FcObjectSetAdd (os, FcObjects[i].object);
-
- return os;
-}
-
-FcBool
-FcObjectInit (void)
-{
- int i;
-
- if (FcObjectsInited)
- return FcTrue;
-
- FcObjectsInited = FcTrue;
- for (i = 0; i < NUM_OBJECT_TYPES; i++)
- if (!FcObjectHashInsert (&_FcBaseObjectTypes[i], FcFalse))
- return FcFalse;
- return FcTrue;
-}
-
-void
-FcObjectFini (void)
-{
- int i;
- FcObjectBucket *b, *next;
-
- for (i = 0; i < OBJECT_HASH_SIZE; i++)
- {
- for (b = FcObjectBuckets[i]; b; b = next)
- {
- next = b->next;
- free (b);
- }
- FcObjectBuckets[i] = 0;
- }
- for (i = 0; i < FcObjectsNumber; i++)
- if (FcObjects[i].type == -1)
- free ((void*) FcObjects[i].object);
- if (FcObjects != _FcBaseObjectTypes)
- free (FcObjects);
- FcObjects = (FcObjectType *) _FcBaseObjectTypes;
- FcObjectsNumber = NUM_OBJECT_TYPES;
- FcObjectsSize = 0;
- FcObjectsInited = FcFalse;
-}
-
-const char *
-FcObjectName (FcObject object)
-{
- FcObjectType *o = FcObjectFindById (object);
-
- if (o)
- return o->object;
- return NULL;
-}
-
-static const FcConstant _FcBaseConstants[] = {
- { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, },
- { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, },
- { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, },
- { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, },
- { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, },
- { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, },
- { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, },
- { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, },
- { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, },
- { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, },
- { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, },
- { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, },
- { (FcChar8 *) "black", "weight", FC_WEIGHT_BLACK, },
- { (FcChar8 *) "heavy", "weight", FC_WEIGHT_HEAVY, },
-
- { (FcChar8 *) "roman", "slant", FC_SLANT_ROMAN, },
- { (FcChar8 *) "italic", "slant", FC_SLANT_ITALIC, },
- { (FcChar8 *) "oblique", "slant", FC_SLANT_OBLIQUE, },
-
- { (FcChar8 *) "ultracondensed", "width", FC_WIDTH_ULTRACONDENSED },
- { (FcChar8 *) "extracondensed", "width", FC_WIDTH_EXTRACONDENSED },
- { (FcChar8 *) "condensed", "width", FC_WIDTH_CONDENSED },
- { (FcChar8 *) "semicondensed", "width", FC_WIDTH_SEMICONDENSED },
- { (FcChar8 *) "normal", "width", FC_WIDTH_NORMAL },
- { (FcChar8 *) "semiexpanded", "width", FC_WIDTH_SEMIEXPANDED },
- { (FcChar8 *) "expanded", "width", FC_WIDTH_EXPANDED },
- { (FcChar8 *) "extraexpanded", "width", FC_WIDTH_EXTRAEXPANDED },
- { (FcChar8 *) "ultraexpanded", "width", FC_WIDTH_ULTRAEXPANDED },
-
- { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, },
- { (FcChar8 *) "dual", "spacing", FC_DUAL, },
- { (FcChar8 *) "mono", "spacing", FC_MONO, },
- { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, },
-
- { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN },
- { (FcChar8 *) "rgb", "rgba", FC_RGBA_RGB, },
- { (FcChar8 *) "bgr", "rgba", FC_RGBA_BGR, },
- { (FcChar8 *) "vrgb", "rgba", FC_RGBA_VRGB },
- { (FcChar8 *) "vbgr", "rgba", FC_RGBA_VBGR },
- { (FcChar8 *) "none", "rgba", FC_RGBA_NONE },
-
- { (FcChar8 *) "hintnone", "hintstyle", FC_HINT_NONE },
- { (FcChar8 *) "hintslight", "hintstyle", FC_HINT_SLIGHT },
- { (FcChar8 *) "hintmedium", "hintstyle", FC_HINT_MEDIUM },
- { (FcChar8 *) "hintfull", "hintstyle", FC_HINT_FULL },
-
- { (FcChar8 *) "antialias", "antialias", FcTrue },
- { (FcChar8 *) "hinting", "hinting", FcTrue },
- { (FcChar8 *) "verticallayout", "verticallayout", FcTrue },
- { (FcChar8 *) "autohint", "autohint", FcTrue },
- { (FcChar8 *) "globaladvance", "globaladvance", FcTrue },
- { (FcChar8 *) "outline", "outline", FcTrue },
- { (FcChar8 *) "scalable", "scalable", FcTrue },
- { (FcChar8 *) "minspace", "minspace", FcTrue },
- { (FcChar8 *) "embolden", "embolden", FcTrue },
- { (FcChar8 *) "embeddedbitmap", "embeddedbitmap", FcTrue },
- { (FcChar8 *) "decorative", "decorative", FcTrue },
- { (FcChar8 *) "lcdnone", "lcdfilter", FC_LCD_NONE },
- { (FcChar8 *) "lcddefault", "lcdfilter", FC_LCD_DEFAULT },
- { (FcChar8 *) "lcdlight", "lcdfilter", FC_LCD_LIGHT },
- { (FcChar8 *) "lcdlegacy", "lcdfilter", FC_LCD_LEGACY },
-};
-
-#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;
- FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
- 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;
- FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
- free ((void *) l);
- return FcTrue;
- }
- }
- return FcFalse;
-}
-
-const FcConstant *
-FcNameGetConstant (FcChar8 *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 (FcChar8 *string, int *result)
-{
- const FcConstant *c;
-
- if ((c = FcNameGetConstant(string)))
- {
- *result = c->value;
- return FcTrue;
- }
- return FcFalse;
-}
-
-FcBool
-FcNameBool (const FcChar8 *v, FcBool *result)
-{
- char c0, c1;
-
- c0 = *v;
- c0 = FcToLower (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];
- c1 = FcToLower (c1);
- if (c1 == 'n')
- {
- *result = FcTrue;
- return FcTrue;
- }
- if (c1 == 'f')
- {
- *result = FcFalse;
- return FcTrue;
- }
- }
- return FcFalse;
-}
-
-static FcValue
-FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
-{
- FcValue v;
-
- v.type = type;
- switch (v.type) {
- case FcTypeInteger:
- if (!FcNameConstant (string, &v.u.i))
- v.u.i = atoi ((char *) string);
- break;
- case FcTypeString:
- v.u.s = FcStrStaticName(string);
- if (!v.u.s)
- v.type = FcTypeVoid;
- break;
- case FcTypeBool:
- if (!FcNameBool (string, &v.u.b))
- v.u.b = FcFalse;
- break;
- case FcTypeDouble:
- v.u.d = strtod ((char *) string, 0);
- break;
- case FcTypeMatrix:
- v.u.m = m;
- sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
- break;
- case FcTypeCharSet:
- v.u.c = FcNameParseCharSet (string);
- if (!v.u.c)
- v.type = FcTypeVoid;
- break;
- case FcTypeLangSet:
- v.u.l = FcNameParseLangSet (string);
- if (!v.u.l)
- v.type = FcTypeVoid;
- break;
- default:
- break;
- }
- return v;
-}
-
-static const FcChar8 *
-FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
-{
- FcChar8 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 FcChar8 *name)
-{
- FcChar8 *save;
- FcPattern *pat;
- double d;
- FcChar8 *e;
- FcChar8 delim;
- FcValue v;
- FcMatrix m;
- const FcObjectType *t;
- const FcConstant *c;
-
- /* freed below */
- save = malloc (strlen ((char *) 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 ((char *) save, (char **) &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 ((char *) save);
- for (;;)
- {
- name = FcNameFindNext (name, ":,", save, &delim);
- if (t)
- {
- v = FcNameConvert (t->type, save, &m);
- if (!FcPatternAdd (pat, t->object, v, FcTrue))
- {
- switch (v.type) {
- case FcTypeCharSet:
- FcCharSetDestroy ((FcCharSet *) v.u.c);
- break;
- case FcTypeLangSet:
- FcLangSetDestroy ((FcLangSet *) v.u.l);
- break;
- default:
- break;
- }
- goto bail2;
- }
- switch (v.type) {
- case FcTypeCharSet:
- FcCharSetDestroy ((FcCharSet *) v.u.c);
- break;
- case FcTypeLangSet:
- FcLangSetDestroy ((FcLangSet *) v.u.l);
- break;
- default:
- break;
- }
- }
- if (delim != ',')
- break;
- }
- }
- else
- {
- if ((c = FcNameGetConstant (save)))
- {
- t = FcNameGetObjectType ((char *) c->object);
- switch (t->type) {
- case FcTypeInteger:
- case FcTypeDouble:
- if (!FcPatternAddInteger (pat, c->object, c->value))
- goto bail2;
- break;
- case FcTypeBool:
- if (!FcPatternAddBool (pat, c->object, c->value))
- goto bail2;
- break;
- default:
- break;
- }
- }
- }
- }
- }
-
- free (save);
- return pat;
-
-bail2:
- FcPatternDestroy (pat);
-bail1:
- free (save);
-bail0:
- return 0;
-}
-static FcBool
-FcNameUnparseString (FcStrBuf *buf,
- const FcChar8 *string,
- const FcChar8 *escape)
-{
- FcChar8 c;
- while ((c = *string++))
- {
- if (escape && strchr ((char *) escape, (char) c))
- {
- if (!FcStrBufChar (buf, escape[0]))
- return FcFalse;
- }
- if (!FcStrBufChar (buf, c))
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcBool
-FcNameUnparseValue (FcStrBuf *buf,
- FcValue *v0,
- FcChar8 *escape)
-{
- FcChar8 temp[1024];
- FcValue v = FcValueCanonicalize(v0);
-
- 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 ? (FcChar8 *) "True" : (FcChar8 *) "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);
- case FcTypeLangSet:
- return FcNameUnparseLangSet (buf, v.u.l);
- case FcTypeFTFace:
- return FcTrue;
- }
- return FcFalse;
-}
-
-FcBool
-FcNameUnparseValueList (FcStrBuf *buf,
- FcValueListPtr v,
- FcChar8 *escape)
-{
- while (v)
- {
- if (!FcNameUnparseValue (buf, &v->value, escape))
- return FcFalse;
- if ((v = FcValueListNext(v)) != NULL)
- if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
- return FcFalse;
- }
- return FcTrue;
-}
-
-#define FC_ESCAPE_FIXED "\\-:,"
-#define FC_ESCAPE_VARIABLE "\\=_:,"
-
-FcChar8 *
-FcNameUnparse (FcPattern *pat)
-{
- return FcNameUnparseEscaped (pat, FcTrue);
-}
-
-FcChar8 *
-FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
-{
- FcStrBuf buf;
- FcChar8 buf_static[8192];
- int i;
- FcPatternElt *e;
- const FcObjectTypeList *l;
- const FcObjectType *o;
-
- FcStrBufInit (&buf, buf_static, sizeof (buf_static));
- e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
- if (e)
- {
- if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
- goto bail0;
- }
- e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
- if (e)
- {
- if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
- goto bail0;
- if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
- 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))
- continue;
-
- e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object));
- if (e)
- {
- if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
- goto bail0;
- if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
- goto bail0;
- if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
- goto bail0;
- if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
- (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
- goto bail0;
- }
- }
- }
- return FcStrBufDone (&buf);
-bail0:
- FcStrBufDestroy (&buf);
- return 0;
-}
-#define __fcname__
-#include "fcaliastail.h"
-#undef __fcname__
+/* + * fontconfig/src/fcname.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +/* + * Please do not change this list, it is used to initialize the object + * list in this order to match the FC_foo_OBJECT constants. Those + * constants are written into cache files. + */ + +static const FcObjectType _FcBaseObjectTypes[] = { + { FC_FAMILY, FcTypeString, }, /* 1 */ + { FC_FAMILYLANG, FcTypeString, }, + { FC_STYLE, FcTypeString, }, + { FC_STYLELANG, FcTypeString, }, + { FC_FULLNAME, FcTypeString, }, + { FC_FULLNAMELANG, FcTypeString, }, + { FC_SLANT, FcTypeInteger, }, + { FC_WEIGHT, FcTypeInteger, }, + { FC_WIDTH, FcTypeInteger, }, + { FC_SIZE, FcTypeDouble, }, + { FC_ASPECT, FcTypeDouble, }, + { FC_PIXEL_SIZE, FcTypeDouble, }, + { FC_SPACING, FcTypeInteger, }, + { FC_FOUNDRY, FcTypeString, }, + { FC_ANTIALIAS, FcTypeBool, }, + { FC_HINT_STYLE, FcTypeInteger, }, + { FC_HINTING, FcTypeBool, }, + { FC_VERTICAL_LAYOUT, FcTypeBool, }, + { FC_AUTOHINT, FcTypeBool, }, + { FC_GLOBAL_ADVANCE, FcTypeBool, }, + { FC_FILE, FcTypeString, }, + { FC_INDEX, FcTypeInteger, }, + { FC_RASTERIZER, FcTypeString, }, + { FC_OUTLINE, FcTypeBool, }, + { FC_SCALABLE, FcTypeBool, }, + { FC_DPI, FcTypeDouble }, + { FC_RGBA, FcTypeInteger, }, + { FC_SCALE, FcTypeDouble, }, + { FC_MINSPACE, FcTypeBool, }, + { FC_CHAR_WIDTH, FcTypeInteger }, + { FC_CHAR_HEIGHT, FcTypeInteger }, + { FC_MATRIX, FcTypeMatrix }, + { FC_CHARSET, FcTypeCharSet }, + { FC_LANG, FcTypeLangSet }, + { FC_FONTVERSION, FcTypeInteger }, + { FC_CAPABILITY, FcTypeString }, + { FC_FONTFORMAT, FcTypeString }, + { FC_EMBOLDEN, FcTypeBool }, + { FC_EMBEDDED_BITMAP, FcTypeBool }, + { FC_DECORATIVE, FcTypeBool }, + { FC_LCD_FILTER, FcTypeInteger }, /* 41 */ +}; + +#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; + +#define OBJECT_HASH_SIZE 31 + +typedef struct _FcObjectBucket { + struct _FcObjectBucket *next; + FcChar32 hash; + FcObject id; +} FcObjectBucket; + +static FcObjectBucket *FcObjectBuckets[OBJECT_HASH_SIZE]; + +static FcObjectType *FcObjects = (FcObjectType *) _FcBaseObjectTypes; +static int FcObjectsNumber = NUM_OBJECT_TYPES; +static int FcObjectsSize = 0; +static FcBool FcObjectsInited; + +static FcObjectType * +FcObjectInsert (const char *name, FcType type) +{ + FcObjectType *o; + if (FcObjectsNumber >= FcObjectsSize) + { + int newsize = FcObjectsNumber * 2; + FcObjectType *newobjects; + + if (FcObjectsSize) + newobjects = realloc (FcObjects, newsize * sizeof (FcObjectType)); + else + { + newobjects = malloc (newsize * sizeof (FcObjectType)); + if (newobjects) + memcpy (newobjects, FcObjects, + FcObjectsNumber * sizeof (FcObjectType)); + } + if (!newobjects) + return NULL; + FcObjects = newobjects; + FcObjectsSize = newsize; + } + o = &FcObjects[FcObjectsNumber]; + o->object = name; + o->type = type; + ++FcObjectsNumber; + return o; +} + +static FcObject +FcObjectId (FcObjectType *o) +{ + return o - FcObjects + 1; +} + +static FcObjectType * +FcObjectFindByName (const char *object, FcBool insert) +{ + FcChar32 hash = FcStringHash ((const FcChar8 *) object); + FcObjectBucket **p; + FcObjectBucket *b; + FcObjectType *o; + + if (!FcObjectsInited) + FcObjectInit (); + for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + { + o = FcObjects + b->id - 1; + if (b->hash == hash && !strcmp (object, (o->object))) + return o; + } + if (!insert) + return NULL; + /* + * Hook it into the hash chain + */ + b = malloc (sizeof(FcObjectBucket)); + if (!b) + return NULL; + object = (const char *) FcStrCopy ((FcChar8 *) object); + if (!object) { + free (b); + return NULL; + } + o = FcObjectInsert (object, -1); + b->next = NULL; + b->hash = hash; + b->id = FcObjectId (o); + *p = b; + return o; +} + +static FcObjectType * +FcObjectFindById (FcObject object) +{ + if (1 <= object && object <= FcObjectsNumber) + return FcObjects + object - 1; + return NULL; +} + +static FcBool +FcObjectHashInsert (const FcObjectType *object, FcBool copy) +{ + FcChar32 hash = FcStringHash ((const FcChar8 *) object->object); + FcObjectBucket **p; + FcObjectBucket *b; + FcObjectType *o; + + if (!FcObjectsInited) + FcObjectInit (); + for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + { + o = FcObjects + b->id - 1; + if (b->hash == hash && !strcmp (object->object, o->object)) + return FcFalse; + } + /* + * Hook it into the hash chain + */ + b = malloc (sizeof(FcObjectBucket)); + if (!b) + return FcFalse; + if (copy) + { + o = FcObjectInsert (object->object, object->type); + if (!o) + { + free (b); + return FcFalse; + } + } + else + o = (FcObjectType *) object; + b->next = NULL; + b->hash = hash; + b->id = FcObjectId (o); + *p = b; + return FcTrue; +} + +static void +FcObjectHashRemove (const FcObjectType *object, FcBool cleanobj) +{ + FcChar32 hash = FcStringHash ((const FcChar8 *) object->object); + FcObjectBucket **p; + FcObjectBucket *b; + FcObjectType *o; + + if (!FcObjectsInited) + FcObjectInit (); + for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + { + o = FcObjects + b->id - 1; + if (b->hash == hash && !strcmp (object->object, o->object)) + { + *p = b->next; + free (b); + if (cleanobj) + { + /* Clean up object array */ + o->object = NULL; + o->type = -1; + while (FcObjects[FcObjectsNumber-1].object == NULL) + --FcObjectsNumber; + } + break; + } + } +} + +FcBool +FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes) +{ + int i; + + for (i = 0; i < ntypes; i++) + if (!FcObjectHashInsert (&types[i], FcTrue)) + return FcFalse; + return FcTrue; +} + +FcBool +FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes) +{ + int i; + + for (i = 0; i < ntypes; i++) + FcObjectHashRemove (&types[i], FcTrue); + return FcTrue; +} + +const FcObjectType * +FcNameGetObjectType (const char *object) +{ + return FcObjectFindByName (object, FcFalse); +} + +FcBool +FcObjectValidType (FcObject object, FcType type) +{ + FcObjectType *t = FcObjectFindById (object); + + if (t) { + switch (t->type) { + case -1: + return FcTrue; + case FcTypeDouble: + case FcTypeInteger: + if (type == FcTypeDouble || type == FcTypeInteger) + return FcTrue; + break; + case FcTypeLangSet: + if (type == FcTypeLangSet || type == FcTypeString) + return FcTrue; + break; + default: + if (type == t->type) + return FcTrue; + break; + } + return FcFalse; + } + return FcTrue; +} + +FcObject +FcObjectFromName (const char * name) +{ + FcObjectType *o = FcObjectFindByName (name, FcTrue); + + if (o) + return FcObjectId (o); + return 0; +} + +FcObjectSet * +FcObjectGetSet (void) +{ + int i; + FcObjectSet *os = NULL; + + + os = FcObjectSetCreate (); + for (i = 0; i < FcObjectsNumber; i++) + FcObjectSetAdd (os, FcObjects[i].object); + + return os; +} + +FcBool +FcObjectInit (void) +{ + int i; + + if (FcObjectsInited) + return FcTrue; + + FcObjectsInited = FcTrue; + for (i = 0; i < NUM_OBJECT_TYPES; i++) + if (!FcObjectHashInsert (&_FcBaseObjectTypes[i], FcFalse)) + return FcFalse; + return FcTrue; +} + +void +FcObjectFini (void) +{ + int i; + FcObjectBucket *b, *next; + + for (i = 0; i < OBJECT_HASH_SIZE; i++) + { + for (b = FcObjectBuckets[i]; b; b = next) + { + next = b->next; + free (b); + } + FcObjectBuckets[i] = 0; + } + for (i = 0; i < FcObjectsNumber; i++) + if (FcObjects[i].type == -1) + free ((void*) FcObjects[i].object); + if (FcObjects != _FcBaseObjectTypes) + free (FcObjects); + FcObjects = (FcObjectType *) _FcBaseObjectTypes; + FcObjectsNumber = NUM_OBJECT_TYPES; + FcObjectsSize = 0; + FcObjectsInited = FcFalse; +} + +const char * +FcObjectName (FcObject object) +{ + FcObjectType *o = FcObjectFindById (object); + + if (o) + return o->object; + return NULL; +} + +static const FcConstant _FcBaseConstants[] = { + { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, }, + { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, }, + { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, }, + { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, }, + { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, }, + { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, }, + { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, }, + { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, }, + { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, }, + { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, }, + { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, }, + { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, }, + { (FcChar8 *) "black", "weight", FC_WEIGHT_BLACK, }, + { (FcChar8 *) "heavy", "weight", FC_WEIGHT_HEAVY, }, + + { (FcChar8 *) "roman", "slant", FC_SLANT_ROMAN, }, + { (FcChar8 *) "italic", "slant", FC_SLANT_ITALIC, }, + { (FcChar8 *) "oblique", "slant", FC_SLANT_OBLIQUE, }, + + { (FcChar8 *) "ultracondensed", "width", FC_WIDTH_ULTRACONDENSED }, + { (FcChar8 *) "extracondensed", "width", FC_WIDTH_EXTRACONDENSED }, + { (FcChar8 *) "condensed", "width", FC_WIDTH_CONDENSED }, + { (FcChar8 *) "semicondensed", "width", FC_WIDTH_SEMICONDENSED }, + { (FcChar8 *) "normal", "width", FC_WIDTH_NORMAL }, + { (FcChar8 *) "semiexpanded", "width", FC_WIDTH_SEMIEXPANDED }, + { (FcChar8 *) "expanded", "width", FC_WIDTH_EXPANDED }, + { (FcChar8 *) "extraexpanded", "width", FC_WIDTH_EXTRAEXPANDED }, + { (FcChar8 *) "ultraexpanded", "width", FC_WIDTH_ULTRAEXPANDED }, + + { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, }, + { (FcChar8 *) "dual", "spacing", FC_DUAL, }, + { (FcChar8 *) "mono", "spacing", FC_MONO, }, + { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, }, + + { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN }, + { (FcChar8 *) "rgb", "rgba", FC_RGBA_RGB, }, + { (FcChar8 *) "bgr", "rgba", FC_RGBA_BGR, }, + { (FcChar8 *) "vrgb", "rgba", FC_RGBA_VRGB }, + { (FcChar8 *) "vbgr", "rgba", FC_RGBA_VBGR }, + { (FcChar8 *) "none", "rgba", FC_RGBA_NONE }, + + { (FcChar8 *) "hintnone", "hintstyle", FC_HINT_NONE }, + { (FcChar8 *) "hintslight", "hintstyle", FC_HINT_SLIGHT }, + { (FcChar8 *) "hintmedium", "hintstyle", FC_HINT_MEDIUM }, + { (FcChar8 *) "hintfull", "hintstyle", FC_HINT_FULL }, + + { (FcChar8 *) "antialias", "antialias", FcTrue }, + { (FcChar8 *) "hinting", "hinting", FcTrue }, + { (FcChar8 *) "verticallayout", "verticallayout", FcTrue }, + { (FcChar8 *) "autohint", "autohint", FcTrue }, + { (FcChar8 *) "globaladvance", "globaladvance", FcTrue }, + { (FcChar8 *) "outline", "outline", FcTrue }, + { (FcChar8 *) "scalable", "scalable", FcTrue }, + { (FcChar8 *) "minspace", "minspace", FcTrue }, + { (FcChar8 *) "embolden", "embolden", FcTrue }, + { (FcChar8 *) "embeddedbitmap", "embeddedbitmap", FcTrue }, + { (FcChar8 *) "decorative", "decorative", FcTrue }, + { (FcChar8 *) "lcdnone", "lcdfilter", FC_LCD_NONE }, + { (FcChar8 *) "lcddefault", "lcdfilter", FC_LCD_DEFAULT }, + { (FcChar8 *) "lcdlight", "lcdfilter", FC_LCD_LIGHT }, + { (FcChar8 *) "lcdlegacy", "lcdfilter", FC_LCD_LEGACY }, +}; + +#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; + FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList)); + 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; + FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList)); + free ((void *) l); + return FcTrue; + } + } + return FcFalse; +} + +const FcConstant * +FcNameGetConstant (FcChar8 *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 (FcChar8 *string, int *result) +{ + const FcConstant *c; + + if ((c = FcNameGetConstant(string))) + { + *result = c->value; + return FcTrue; + } + return FcFalse; +} + +FcBool +FcNameBool (const FcChar8 *v, FcBool *result) +{ + char c0, c1; + + c0 = *v; + c0 = FcToLower (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]; + c1 = FcToLower (c1); + if (c1 == 'n') + { + *result = FcTrue; + return FcTrue; + } + if (c1 == 'f') + { + *result = FcFalse; + return FcTrue; + } + } + return FcFalse; +} + +static FcValue +FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m) +{ + FcValue v; + + v.type = type; + switch (v.type) { + case FcTypeInteger: + if (!FcNameConstant (string, &v.u.i)) + v.u.i = atoi ((char *) string); + break; + case FcTypeString: + v.u.s = FcStrStaticName(string); + if (!v.u.s) + v.type = FcTypeVoid; + break; + case FcTypeBool: + if (!FcNameBool (string, &v.u.b)) + v.u.b = FcFalse; + break; + case FcTypeDouble: + v.u.d = strtod ((char *) string, 0); + break; + case FcTypeMatrix: + v.u.m = m; + sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy); + break; + case FcTypeCharSet: + v.u.c = FcNameParseCharSet (string); + if (!v.u.c) + v.type = FcTypeVoid; + break; + case FcTypeLangSet: + v.u.l = FcNameParseLangSet (string); + if (!v.u.l) + v.type = FcTypeVoid; + break; + default: + break; + } + return v; +} + +static const FcChar8 * +FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last) +{ + FcChar8 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 FcChar8 *name) +{ + FcChar8 *save; + FcPattern *pat; + double d; + FcChar8 *e; + FcChar8 delim; + FcValue v; + FcMatrix m; + const FcObjectType *t; + const FcConstant *c; + + /* freed below */ + save = malloc (strlen ((char *) 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 ((char *) save, (char **) &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 ((char *) save); + for (;;) + { + name = FcNameFindNext (name, ":,", save, &delim); + if (t) + { + v = FcNameConvert (t->type, save, &m); + if (!FcPatternAdd (pat, t->object, v, FcTrue)) + { + switch (v.type) { + case FcTypeCharSet: + FcCharSetDestroy ((FcCharSet *) v.u.c); + break; + case FcTypeLangSet: + FcLangSetDestroy ((FcLangSet *) v.u.l); + break; + default: + break; + } + goto bail2; + } + switch (v.type) { + case FcTypeCharSet: + FcCharSetDestroy ((FcCharSet *) v.u.c); + break; + case FcTypeLangSet: + FcLangSetDestroy ((FcLangSet *) v.u.l); + break; + default: + break; + } + } + if (delim != ',') + break; + } + } + else + { + if ((c = FcNameGetConstant (save))) + { + t = FcNameGetObjectType ((char *) c->object); + switch (t->type) { + case FcTypeInteger: + case FcTypeDouble: + if (!FcPatternAddInteger (pat, c->object, c->value)) + goto bail2; + break; + case FcTypeBool: + if (!FcPatternAddBool (pat, c->object, c->value)) + goto bail2; + break; + default: + break; + } + } + } + } + } + + free (save); + return pat; + +bail2: + FcPatternDestroy (pat); +bail1: + free (save); +bail0: + return 0; +} +static FcBool +FcNameUnparseString (FcStrBuf *buf, + const FcChar8 *string, + const FcChar8 *escape) +{ + FcChar8 c; + while ((c = *string++)) + { + if (escape && strchr ((char *) escape, (char) c)) + { + if (!FcStrBufChar (buf, escape[0])) + return FcFalse; + } + if (!FcStrBufChar (buf, c)) + return FcFalse; + } + return FcTrue; +} + +FcBool +FcNameUnparseValue (FcStrBuf *buf, + FcValue *v0, + FcChar8 *escape) +{ + FcChar8 temp[1024]; + FcValue v = FcValueCanonicalize(v0); + + 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 ? (FcChar8 *) "True" : (FcChar8 *) "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); + case FcTypeLangSet: + return FcNameUnparseLangSet (buf, v.u.l); + case FcTypeFTFace: + return FcTrue; + } + return FcFalse; +} + +FcBool +FcNameUnparseValueList (FcStrBuf *buf, + FcValueListPtr v, + FcChar8 *escape) +{ + while (v) + { + if (!FcNameUnparseValue (buf, &v->value, escape)) + return FcFalse; + if ((v = FcValueListNext(v)) != NULL) + if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0)) + return FcFalse; + } + return FcTrue; +} + +#define FC_ESCAPE_FIXED "\\-:," +#define FC_ESCAPE_VARIABLE "\\=_:," + +FcChar8 * +FcNameUnparse (FcPattern *pat) +{ + return FcNameUnparseEscaped (pat, FcTrue); +} + +FcChar8 * +FcNameUnparseEscaped (FcPattern *pat, FcBool escape) +{ + FcStrBuf buf; + FcChar8 buf_static[8192]; + int i; + FcPatternElt *e; + const FcObjectTypeList *l; + const FcObjectType *o; + + FcStrBufInit (&buf, buf_static, sizeof (buf_static)); + e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT); + if (e) + { + if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) + goto bail0; + } + e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT); + if (e) + { + if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0)) + goto bail0; + if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) + 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)) + continue; + + e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object)); + if (e) + { + if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0)) + goto bail0; + if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) + goto bail0; + if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0)) + goto bail0; + if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? + (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) + goto bail0; + } + } + } + return FcStrBufDone (&buf); +bail0: + FcStrBufDestroy (&buf); + return 0; +} +#define __fcname__ +#include "fcaliastail.h" +#undef __fcname__ diff --git a/fontconfig/src/fcpat.c b/fontconfig/src/fcpat.c index 0d2402043..8f63659df 100644 --- a/fontconfig/src/fcpat.c +++ b/fontconfig/src/fcpat.c @@ -1,1267 +1,1267 @@ -/*
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include "fcftint.h"
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-static FcBool
-FcHashOwnsName(const FcChar8 *name);
-
-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_offset = FcPtrToOffset (p, NULL);
- p->ref = 1;
- return p;
-}
-
-void
-FcValueDestroy (FcValue v)
-{
- switch (v.type) {
- case FcTypeString:
- if (!FcHashOwnsName(v.u.s))
- FcStrFree ((FcChar8 *) v.u.s);
- break;
- case FcTypeMatrix:
- FcMatrixFree ((FcMatrix *) v.u.m);
- break;
- case FcTypeCharSet:
- FcCharSetDestroy ((FcCharSet *) v.u.c);
- break;
- case FcTypeLangSet:
- FcLangSetDestroy ((FcLangSet *) v.u.l);
- break;
- default:
- break;
- }
-}
-
-FcValue
-FcValueCanonicalize (const FcValue *v)
-{
- FcValue new;
-
- switch (v->type)
- {
- case FcTypeString:
- new.u.s = FcValueString(v);
- new.type = FcTypeString;
- break;
- case FcTypeCharSet:
- new.u.c = FcValueCharSet(v);
- new.type = FcTypeCharSet;
- break;
- case FcTypeLangSet:
- new.u.l = FcValueLangSet(v);
- new.type = FcTypeLangSet;
- break;
- default:
- new = *v;
- break;
- }
- return new;
-}
-
-FcValue
-FcValueSave (FcValue v)
-{
- switch (v.type) {
- case FcTypeString:
- v.u.s = FcStrStaticName (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;
- case FcTypeLangSet:
- v.u.l = FcLangSetCopy (v.u.l);
- if (!v.u.l)
- v.type = FcTypeVoid;
- break;
- default:
- break;
- }
- return v;
-}
-
-void
-FcValueListDestroy (FcValueListPtr l)
-{
- FcValueListPtr next;
- for (; l; l = next)
- {
- switch (l->value.type) {
- case FcTypeString:
- if (!FcHashOwnsName((FcChar8 *)l->value.u.s))
- 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;
- case FcTypeLangSet:
- FcLangSetDestroy
- ((FcLangSet *) (l->value.u.l));
- break;
- default:
- break;
- }
- next = FcValueListNext(l);
- FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
- free(l);
- }
-}
-
-FcBool
-FcValueEqual (FcValue va, FcValue vb)
-{
- if (va.type != vb.type)
- {
- if (va.type == FcTypeInteger)
- {
- va.type = FcTypeDouble;
- va.u.d = va.u.i;
- }
- if (vb.type == FcTypeInteger)
- {
- vb.type = FcTypeDouble;
- vb.u.d = vb.u.i;
- }
- if (va.type != vb.type)
- return FcFalse;
- }
- switch (va.type) {
- case FcTypeVoid:
- return FcTrue;
- case FcTypeInteger:
- return va.u.i == vb.u.i;
- case FcTypeDouble:
- return va.u.d == vb.u.d;
- case FcTypeString:
- return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
- case FcTypeBool:
- return va.u.b == vb.u.b;
- case FcTypeMatrix:
- return FcMatrixEqual (va.u.m, vb.u.m);
- case FcTypeCharSet:
- return FcCharSetEqual (va.u.c, vb.u.c);
- case FcTypeFTFace:
- return va.u.f == vb.u.f;
- case FcTypeLangSet:
- return FcLangSetEqual (va.u.l, vb.u.l);
- }
- return FcFalse;
-}
-
-static FcChar32
-FcDoubleHash (double d)
-{
- if (d < 0)
- d = -d;
- if (d > 0xffffffff)
- d = 0xffffffff;
- return (FcChar32) d;
-}
-
-FcChar32
-FcStringHash (const FcChar8 *s)
-{
- FcChar8 c;
- FcChar32 h = 0;
-
- if (s)
- while ((c = *s++))
- h = ((h << 1) | (h >> 31)) ^ c;
- return h;
-}
-
-static FcChar32
-FcValueHash (const FcValue *v)
-{
- switch (v->type) {
- case FcTypeVoid:
- return 0;
- case FcTypeInteger:
- return (FcChar32) v->u.i;
- case FcTypeDouble:
- return FcDoubleHash (v->u.d);
- case FcTypeString:
- return FcStringHash (FcValueString(v));
- case FcTypeBool:
- return (FcChar32) v->u.b;
- case FcTypeMatrix:
- return (FcDoubleHash (v->u.m->xx) ^
- FcDoubleHash (v->u.m->xy) ^
- FcDoubleHash (v->u.m->yx) ^
- FcDoubleHash (v->u.m->yy));
- case FcTypeCharSet:
- return (FcChar32) FcValueCharSet(v)->num;
- case FcTypeFTFace:
- return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
- FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
- case FcTypeLangSet:
- return FcLangSetHash (FcValueLangSet(v));
- }
- return FcFalse;
-}
-
-static FcBool
-FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
-{
- if (la == lb)
- return FcTrue;
-
- while (la && lb)
- {
- if (!FcValueEqual (la->value, lb->value))
- return FcFalse;
- la = FcValueListNext(la);
- lb = FcValueListNext(lb);
- }
- if (la || lb)
- return FcFalse;
- return FcTrue;
-}
-
-static FcChar32
-FcValueListHash (FcValueListPtr l)
-{
- FcChar32 hash = 0;
-
- for (; l; l = FcValueListNext(l))
- {
- hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
- }
- return hash;
-}
-
-void
-FcPatternDestroy (FcPattern *p)
-{
- int i;
- FcPatternElt *elts;
-
- if (p->ref == FC_REF_CONSTANT)
- {
- FcCacheObjectDereference (p);
- return;
- }
-
- if (--p->ref > 0)
- return;
-
- elts = FcPatternElts (p);
- for (i = 0; i < p->num; i++)
- FcValueListDestroy (FcPatternEltValues(&elts[i]));
-
- FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
- free (elts);
- FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
- free (p);
-}
-
-static int
-FcPatternObjectPosition (const FcPattern *p, FcObject object)
-{
- int low, high, mid, c;
- FcPatternElt *elts = FcPatternElts(p);
-
- low = 0;
- high = p->num - 1;
- c = 1;
- mid = 0;
- while (low <= high)
- {
- mid = (low + high) >> 1;
- c = elts[mid].object - object;
- if (c == 0)
- return mid;
- if (c < 0)
- low = mid + 1;
- else
- high = mid - 1;
- }
- if (c < 0)
- mid++;
- return -(mid + 1);
-}
-
-FcPatternElt *
-FcPatternObjectFindElt (const FcPattern *p, FcObject object)
-{
- int i = FcPatternObjectPosition (p, object);
- if (i < 0)
- return 0;
- return &FcPatternElts(p)[i];
-}
-
-FcPatternElt *
-FcPatternObjectInsertElt (FcPattern *p, FcObject object)
-{
- int i;
- FcPatternElt *e;
-
- i = FcPatternObjectPosition (p, object);
- if (i < 0)
- {
- i = -i - 1;
-
- /* reallocate array */
- if (p->num + 1 >= p->size)
- {
- int s = p->size + 16;
- if (p->size)
- {
- FcPatternElt *e0 = FcPatternElts(p);
- e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
- if (!e) /* maybe it was mmapped */
- {
- e = malloc(s * sizeof (FcPatternElt));
- if (e)
- memcpy(e, e0, p->num * sizeof (FcPatternElt));
- }
- }
- else
- e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
- if (!e)
- return FcFalse;
- p->elts_offset = FcPtrToOffset (p, e);
- if (p->size)
- FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
- FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
- while (p->size < s)
- {
- e[p->size].object = 0;
- e[p->size].values = NULL;
- p->size++;
- }
- }
-
- e = FcPatternElts(p);
- /* move elts up */
- memmove (e + i + 1,
- e + i,
- sizeof (FcPatternElt) *
- (p->num - i));
-
- /* bump count */
- p->num++;
-
- e[i].object = object;
- e[i].values = NULL;
- }
-
- return FcPatternElts(p) + i;
-}
-
-FcBool
-FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
-{
- int i;
- FcPatternElt *pae, *pbe;
-
- if (pa == pb)
- return FcTrue;
-
- if (pa->num != pb->num)
- return FcFalse;
- pae = FcPatternElts(pa);
- pbe = FcPatternElts(pb);
- for (i = 0; i < pa->num; i++)
- {
- if (pae[i].object != pbe[i].object)
- return FcFalse;
- if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
- FcPatternEltValues(&pbe[i])))
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcChar32
-FcPatternHash (const FcPattern *p)
-{
- int i;
- FcChar32 h = 0;
- FcPatternElt *pe = FcPatternElts(p);
-
- for (i = 0; i < p->num; i++)
- {
- h = (((h << 1) | (h >> 31)) ^
- pe[i].object ^
- FcValueListHash (FcPatternEltValues(&pe[i])));
- }
- return h;
-}
-
-FcBool
-FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
-{
- FcPatternElt *ea, *eb;
- int i;
-
- for (i = 0; i < os->nobject; i++)
- {
- FcObject object = FcObjectFromName (os->objects[i]);
- ea = FcPatternObjectFindElt (pai, object);
- eb = FcPatternObjectFindElt (pbi, object);
- if (ea)
- {
- if (!eb)
- return FcFalse;
- if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
- return FcFalse;
- }
- else
- {
- if (eb)
- return FcFalse;
- }
- }
- return FcTrue;
-}
-
-FcBool
-FcPatternObjectAddWithBinding (FcPattern *p,
- FcObject object,
- FcValue value,
- FcValueBinding binding,
- FcBool append)
-{
- FcPatternElt *e;
- FcValueListPtr new, *prev;
-
- if (p->ref == FC_REF_CONSTANT)
- goto bail0;
-
- new = malloc (sizeof (FcValueList));
- if (!new)
- goto bail0;
-
- memset(new, 0, sizeof (FcValueList));
- FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
- value = FcValueSave (value);
- if (value.type == FcTypeVoid)
- goto bail1;
-
- /*
- * Make sure the stored type is valid for built-in objects
- */
- if (!FcObjectValidType (object, value.type))
- {
- if (FcDebug() & FC_DBG_OBJTYPES)
- {
- printf ("FcPattern object %s does not accept value ",
- FcObjectName (object));
- FcValuePrint (value);
- }
- goto bail1;
- }
-
- new->value = value;
- new->binding = binding;
- new->next = NULL;
-
- e = FcPatternObjectInsertElt (p, object);
- 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:
- FcValueDestroy (value);
-bail1:
- FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
- free (new);
-bail0:
- return FcFalse;
-}
-
-FcBool
-FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
-{
- return FcPatternObjectAddWithBinding (p, object,
- value, FcValueBindingStrong, append);
-}
-
-FcBool
-FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
-{
- return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
- value, FcValueBindingStrong, append);
-}
-
-FcBool
-FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
-{
- return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
- value, FcValueBindingWeak, append);
-}
-
-FcBool
-FcPatternObjectDel (FcPattern *p, FcObject object)
-{
- FcPatternElt *e;
-
- e = FcPatternObjectFindElt (p, object);
- if (!e)
- return FcFalse;
-
- /* destroy value */
- FcValueListDestroy (e->values);
-
- /* shuffle existing ones down */
- memmove (e, e+1,
- (FcPatternElts(p) + p->num - (e + 1)) *
- sizeof (FcPatternElt));
- p->num--;
- e = FcPatternElts(p) + p->num;
- e->object = 0;
- e->values = NULL;
- return FcTrue;
-}
-
-FcBool
-FcPatternDel (FcPattern *p, const char *object)
-{
- return FcPatternObjectDel (p, FcObjectFromName (object));
-}
-
-FcBool
-FcPatternRemove (FcPattern *p, const char *object, int id)
-{
- FcPatternElt *e;
- FcValueListPtr *prev, l;
-
- e = FcPatternObjectFindElt (p, FcObjectFromName (object));
- if (!e)
- return FcFalse;
- for (prev = &e->values; (l = *prev); prev = &l->next)
- {
- if (!id)
- {
- *prev = l->next;
- l->next = NULL;
- FcValueListDestroy (l);
- if (!e->values)
- FcPatternDel (p, object);
- return FcTrue;
- }
- id--;
- }
- return FcFalse;
-}
-
-FcBool
-FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
-{
- FcValue v;
-
- v.type = FcTypeInteger;
- v.u.i = i;
- return FcPatternObjectAdd (p, object, v, FcTrue);
-}
-
-FcBool
-FcPatternAddInteger (FcPattern *p, const char *object, int i)
-{
- return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
-}
-
-FcBool
-FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
-{
- FcValue v;
-
- v.type = FcTypeDouble;
- v.u.d = d;
- return FcPatternObjectAdd (p, object, v, FcTrue);
-}
-
-
-FcBool
-FcPatternAddDouble (FcPattern *p, const char *object, double d)
-{
- return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
-}
-
-FcBool
-FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
-{
- FcValue v;
-
- if (!s)
- {
- v.type = FcTypeVoid;
- v.u.s = 0;
- return FcPatternObjectAdd (p, object, v, FcTrue);
- }
-
- v.type = FcTypeString;
- v.u.s = FcStrStaticName(s);
- return FcPatternObjectAdd (p, object, v, FcTrue);
-}
-
-FcBool
-FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
-{
- return FcPatternObjectAddString (p, FcObjectFromName (object), s);
-}
-
-FcBool
-FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
-{
- FcValue v;
-
- v.type = FcTypeMatrix;
- v.u.m = s;
- return FcPatternAdd (p, object, v, FcTrue);
-}
-
-
-FcBool
-FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
-{
- FcValue v;
-
- v.type = FcTypeBool;
- v.u.b = b;
- return FcPatternObjectAdd (p, object, v, FcTrue);
-}
-
-FcBool
-FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
-{
- return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
-}
-
-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);
-}
-
-FcBool
-FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
-{
- FcValue v;
-
- v.type = FcTypeFTFace;
- v.u.f = (void *) f;
- return FcPatternAdd (p, object, v, FcTrue);
-}
-
-FcBool
-FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
-{
- FcValue v;
-
- v.type = FcTypeLangSet;
- v.u.l = (FcLangSet *)ls;
- return FcPatternAdd (p, object, v, FcTrue);
-}
-
-FcResult
-FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
-{
- FcPatternElt *e;
- FcValueListPtr l;
-
- e = FcPatternObjectFindElt (p, object);
- if (!e)
- return FcResultNoMatch;
- for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
- {
- if (!id)
- {
- *v = FcValueCanonicalize(&l->value);
- return FcResultMatch;
- }
- id--;
- }
- return FcResultNoId;
-}
-
-FcResult
-FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
-{
- return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
-}
-
-FcResult
-FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
-{
- FcValue v;
- FcResult r;
-
- r = FcPatternObjectGet (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
-FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
-{
- return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
-}
-
-
-FcResult
-FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
-{
- FcValue v;
- FcResult r;
-
- r = FcPatternObjectGet (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
-FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
-{
- return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
-}
-
-FcResult
-FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
-{
- FcValue v;
- FcResult r;
-
- r = FcPatternObjectGet (p, object, id, &v);
- if (r != FcResultMatch)
- return r;
- if (v.type != FcTypeString)
- return FcResultTypeMismatch;
-
- *s = (FcChar8 *) v.u.s;
- return FcResultMatch;
-}
-
-FcResult
-FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
-{
- return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
-}
-
-FcResult
-FcPatternGetMatrix(const 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(const 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(const 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;
-}
-
-FcResult
-FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
-{
- FcValue v;
- FcResult r;
-
- r = FcPatternGet (p, object, id, &v);
- if (r != FcResultMatch)
- return r;
- if (v.type != FcTypeFTFace)
- return FcResultTypeMismatch;
- *f = (FT_Face) v.u.f;
- return FcResultMatch;
-}
-
-FcResult
-FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
-{
- FcValue v;
- FcResult r;
-
- r = FcPatternGet (p, object, id, &v);
- if (r != FcResultMatch)
- return r;
- if (v.type != FcTypeLangSet)
- return FcResultTypeMismatch;
- *ls = (FcLangSet *)v.u.l;
- return FcResultMatch;
-}
-
-FcPattern *
-FcPatternDuplicate (const FcPattern *orig)
-{
- FcPattern *new;
- FcPatternElt *e;
- int i;
- FcValueListPtr l;
-
- new = FcPatternCreate ();
- if (!new)
- goto bail0;
-
- e = FcPatternElts(orig);
-
- for (i = 0; i < orig->num; i++)
- {
- for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
- {
- if (!FcPatternObjectAddWithBinding (new, e[i].object,
- FcValueCanonicalize(&l->value),
- l->binding,
- FcTrue))
- goto bail1;
-
- }
- }
-
- return new;
-
-bail1:
- FcPatternDestroy (new);
-bail0:
- return 0;
-}
-
-void
-FcPatternReference (FcPattern *p)
-{
- if (p->ref != FC_REF_CONSTANT)
- p->ref++;
- else
- FcCacheObjectReference (p);
-}
-
-FcPattern *
-FcPatternVaBuild (FcPattern *p, va_list va)
-{
- FcPattern *ret;
-
- FcPatternVapBuild (ret, p, va);
- return ret;
-}
-
-FcPattern *
-FcPatternBuild (FcPattern *p, ...)
-{
- va_list va;
-
- va_start (va, p);
- FcPatternVapBuild (p, p, va);
- va_end (va);
- return p;
-}
-
-/*
- * Add all of the elements in 's' to 'p'
- */
-FcBool
-FcPatternAppend (FcPattern *p, FcPattern *s)
-{
- int i;
- FcPatternElt *e;
- FcValueListPtr v;
-
- for (i = 0; i < s->num; i++)
- {
- e = FcPatternElts(s)+i;
- for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
- {
- if (!FcPatternObjectAddWithBinding (p, e->object,
- FcValueCanonicalize(&v->value),
- v->binding, FcTrue))
- return FcFalse;
- }
- }
- return FcTrue;
-}
-
-FcPattern *
-FcPatternFilter (FcPattern *p, const FcObjectSet *os)
-{
- int i;
- FcPattern *ret;
- FcPatternElt *e;
- FcValueListPtr v;
-
- if (!os)
- return FcPatternDuplicate (p);
-
- ret = FcPatternCreate ();
- if (!ret)
- return NULL;
-
- for (i = 0; i < os->nobject; i++)
- {
- FcObject object = FcObjectFromName (os->objects[i]);
- e = FcPatternObjectFindElt (p, object);
- if (e)
- {
- for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
- {
- if (!FcPatternObjectAddWithBinding (ret, e->object,
- FcValueCanonicalize(&v->value),
- v->binding, FcTrue))
- goto bail0;
- }
- }
- }
- return ret;
-
-bail0:
- FcPatternDestroy (ret);
- return NULL;
-}
-
-#define OBJECT_HASH_SIZE 31
-static struct objectBucket {
- struct objectBucket *next;
- FcChar32 hash;
-} *FcObjectBuckets[OBJECT_HASH_SIZE];
-
-static FcBool
-FcHashOwnsName (const FcChar8 *name)
-{
- FcChar32 hash = FcStringHash (name);
- struct objectBucket **p;
- struct objectBucket *b;
-
- for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
- if (b->hash == hash && ((char *)name == (char *) (b + 1)))
- return FcTrue;
- return FcFalse;
-}
-
-const FcChar8 *
-FcStrStaticName (const FcChar8 *name)
-{
- FcChar32 hash = FcStringHash (name);
- struct objectBucket **p;
- struct objectBucket *b;
- int size;
-
- for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
- if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
- return (FcChar8 *) (b + 1);
- size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
- /*
- * workaround valgrind warning because glibc takes advantage of how it knows memory is
- * allocated to implement strlen by reading in groups of 4
- */
- size = (size + 3) & ~3;
- b = malloc (size);
- FcMemAlloc (FC_MEM_STATICSTR, size);
- if (!b)
- return NULL;
- b->next = 0;
- b->hash = hash;
- strcpy ((char *) (b + 1), (char *)name);
- *p = b;
- return (FcChar8 *) (b + 1);
-}
-
-static void
-FcStrStaticNameFini (void)
-{
- int i, size;
- struct objectBucket *b, *next;
- char *name;
-
- for (i = 0; i < OBJECT_HASH_SIZE; i++)
- {
- for (b = FcObjectBuckets[i]; b; b = next)
- {
- next = b->next;
- name = (char *) (b + 1);
- size = sizeof (struct objectBucket) + strlen (name) + 1;
- FcMemFree (FC_MEM_STATICSTR, size + sizeof (int));
- free (b);
- }
- FcObjectBuckets[i] = 0;
- }
-}
-
-void
-FcPatternFini (void)
-{
- FcStrStaticNameFini ();
- FcObjectFini ();
-}
-
-FcBool
-FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
-{
- int i;
- FcPatternElt *elts = FcPatternElts(pat);
-
- if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
- return FcFalse;
- if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
- return FcFalse;
- for (i = 0; i < pat->num; i++)
- if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
- return FcFalse;
- return FcTrue;
-}
-
-FcPattern *
-FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
-{
- FcPattern *pat_serialized;
- FcPatternElt *elts = FcPatternElts (pat);
- FcPatternElt *elts_serialized;
- FcValueList *values_serialized;
- int i;
-
- pat_serialized = FcSerializePtr (serialize, pat);
- if (!pat_serialized)
- return NULL;
- *pat_serialized = *pat;
- pat_serialized->size = pat->num;
- pat_serialized->ref = FC_REF_CONSTANT;
-
- elts_serialized = FcSerializePtr (serialize, elts);
- if (!elts_serialized)
- return NULL;
-
- pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
- elts_serialized);
-
- for (i = 0; i < pat->num; i++)
- {
- values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
- if (!values_serialized)
- return NULL;
- elts_serialized[i].object = elts[i].object;
- elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
- values_serialized,
- FcValueList);
- }
- if (FcDebug() & FC_DBG_CACHEV) {
- printf ("Raw pattern:\n");
- FcPatternPrint (pat);
- printf ("Serialized pattern:\n");
- FcPatternPrint (pat_serialized);
- printf ("\n");
- }
- return pat_serialized;
-}
-
-FcBool
-FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
-{
- while (vl)
- {
- if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
- return FcFalse;
- switch (vl->value.type) {
- case FcTypeString:
- if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
- return FcFalse;
- break;
- case FcTypeCharSet:
- if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
- return FcFalse;
- break;
- case FcTypeLangSet:
- if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
- return FcFalse;
- break;
- default:
- break;
- }
- vl = vl->next;
- }
- return FcTrue;
-}
-
-FcValueList *
-FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
-{
- FcValueList *vl_serialized;
- FcChar8 *s_serialized;
- FcCharSet *c_serialized;
- FcLangSet *l_serialized;
- FcValueList *head_serialized = NULL;
- FcValueList *prev_serialized = NULL;
-
- while (vl)
- {
- vl_serialized = FcSerializePtr (serialize, vl);
- if (!vl_serialized)
- return NULL;
-
- if (prev_serialized)
- prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
- vl_serialized,
- FcValueList);
- else
- head_serialized = vl_serialized;
-
- vl_serialized->next = NULL;
- vl_serialized->value.type = vl->value.type;
- switch (vl->value.type) {
- case FcTypeInteger:
- vl_serialized->value.u.i = vl->value.u.i;
- break;
- case FcTypeDouble:
- vl_serialized->value.u.d = vl->value.u.d;
- break;
- case FcTypeString:
- s_serialized = FcStrSerialize (serialize, vl->value.u.s);
- if (!s_serialized)
- return NULL;
- vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
- s_serialized,
- FcChar8);
- break;
- case FcTypeBool:
- vl_serialized->value.u.b = vl->value.u.b;
- break;
- case FcTypeMatrix:
- /* can't happen */
- break;
- case FcTypeCharSet:
- c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
- if (!c_serialized)
- return NULL;
- vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
- c_serialized,
- FcCharSet);
- break;
- case FcTypeFTFace:
- /* can't happen */
- break;
- case FcTypeLangSet:
- l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
- if (!l_serialized)
- return NULL;
- vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
- l_serialized,
- FcLangSet);
- break;
- default:
- break;
- }
- prev_serialized = vl_serialized;
- vl = vl->next;
- }
- return head_serialized;
-}
-#define __fcpat__
-#include "fcaliastail.h"
-#include "fcftaliastail.h"
-#undef __fcpat__
+/* + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include "fcftint.h" +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +static FcBool +FcHashOwnsName(const FcChar8 *name); + +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_offset = FcPtrToOffset (p, NULL); + p->ref = 1; + return p; +} + +void +FcValueDestroy (FcValue v) +{ + switch (v.type) { + case FcTypeString: + if (!FcHashOwnsName(v.u.s)) + FcStrFree ((FcChar8 *) v.u.s); + break; + case FcTypeMatrix: + FcMatrixFree ((FcMatrix *) v.u.m); + break; + case FcTypeCharSet: + FcCharSetDestroy ((FcCharSet *) v.u.c); + break; + case FcTypeLangSet: + FcLangSetDestroy ((FcLangSet *) v.u.l); + break; + default: + break; + } +} + +FcValue +FcValueCanonicalize (const FcValue *v) +{ + FcValue new; + + switch (v->type) + { + case FcTypeString: + new.u.s = FcValueString(v); + new.type = FcTypeString; + break; + case FcTypeCharSet: + new.u.c = FcValueCharSet(v); + new.type = FcTypeCharSet; + break; + case FcTypeLangSet: + new.u.l = FcValueLangSet(v); + new.type = FcTypeLangSet; + break; + default: + new = *v; + break; + } + return new; +} + +FcValue +FcValueSave (FcValue v) +{ + switch (v.type) { + case FcTypeString: + v.u.s = FcStrStaticName (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; + case FcTypeLangSet: + v.u.l = FcLangSetCopy (v.u.l); + if (!v.u.l) + v.type = FcTypeVoid; + break; + default: + break; + } + return v; +} + +void +FcValueListDestroy (FcValueListPtr l) +{ + FcValueListPtr next; + for (; l; l = next) + { + switch (l->value.type) { + case FcTypeString: + if (!FcHashOwnsName((FcChar8 *)l->value.u.s)) + 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; + case FcTypeLangSet: + FcLangSetDestroy + ((FcLangSet *) (l->value.u.l)); + break; + default: + break; + } + next = FcValueListNext(l); + FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); + free(l); + } +} + +FcBool +FcValueEqual (FcValue va, FcValue vb) +{ + if (va.type != vb.type) + { + if (va.type == FcTypeInteger) + { + va.type = FcTypeDouble; + va.u.d = va.u.i; + } + if (vb.type == FcTypeInteger) + { + vb.type = FcTypeDouble; + vb.u.d = vb.u.i; + } + if (va.type != vb.type) + return FcFalse; + } + switch (va.type) { + case FcTypeVoid: + return FcTrue; + case FcTypeInteger: + return va.u.i == vb.u.i; + case FcTypeDouble: + return va.u.d == vb.u.d; + case FcTypeString: + return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0; + case FcTypeBool: + return va.u.b == vb.u.b; + case FcTypeMatrix: + return FcMatrixEqual (va.u.m, vb.u.m); + case FcTypeCharSet: + return FcCharSetEqual (va.u.c, vb.u.c); + case FcTypeFTFace: + return va.u.f == vb.u.f; + case FcTypeLangSet: + return FcLangSetEqual (va.u.l, vb.u.l); + } + return FcFalse; +} + +static FcChar32 +FcDoubleHash (double d) +{ + if (d < 0) + d = -d; + if (d > 0xffffffff) + d = 0xffffffff; + return (FcChar32) d; +} + +FcChar32 +FcStringHash (const FcChar8 *s) +{ + FcChar8 c; + FcChar32 h = 0; + + if (s) + while ((c = *s++)) + h = ((h << 1) | (h >> 31)) ^ c; + return h; +} + +static FcChar32 +FcValueHash (const FcValue *v) +{ + switch (v->type) { + case FcTypeVoid: + return 0; + case FcTypeInteger: + return (FcChar32) v->u.i; + case FcTypeDouble: + return FcDoubleHash (v->u.d); + case FcTypeString: + return FcStringHash (FcValueString(v)); + case FcTypeBool: + return (FcChar32) v->u.b; + case FcTypeMatrix: + return (FcDoubleHash (v->u.m->xx) ^ + FcDoubleHash (v->u.m->xy) ^ + FcDoubleHash (v->u.m->yx) ^ + FcDoubleHash (v->u.m->yy)); + case FcTypeCharSet: + return (FcChar32) FcValueCharSet(v)->num; + case FcTypeFTFace: + return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^ + FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name); + case FcTypeLangSet: + return FcLangSetHash (FcValueLangSet(v)); + } + return FcFalse; +} + +static FcBool +FcValueListEqual (FcValueListPtr la, FcValueListPtr lb) +{ + if (la == lb) + return FcTrue; + + while (la && lb) + { + if (!FcValueEqual (la->value, lb->value)) + return FcFalse; + la = FcValueListNext(la); + lb = FcValueListNext(lb); + } + if (la || lb) + return FcFalse; + return FcTrue; +} + +static FcChar32 +FcValueListHash (FcValueListPtr l) +{ + FcChar32 hash = 0; + + for (; l; l = FcValueListNext(l)) + { + hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value); + } + return hash; +} + +void +FcPatternDestroy (FcPattern *p) +{ + int i; + FcPatternElt *elts; + + if (p->ref == FC_REF_CONSTANT) + { + FcCacheObjectDereference (p); + return; + } + + if (--p->ref > 0) + return; + + elts = FcPatternElts (p); + for (i = 0; i < p->num; i++) + FcValueListDestroy (FcPatternEltValues(&elts[i])); + + FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt)); + free (elts); + FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern)); + free (p); +} + +static int +FcPatternObjectPosition (const FcPattern *p, FcObject object) +{ + int low, high, mid, c; + FcPatternElt *elts = FcPatternElts(p); + + low = 0; + high = p->num - 1; + c = 1; + mid = 0; + while (low <= high) + { + mid = (low + high) >> 1; + c = elts[mid].object - object; + if (c == 0) + return mid; + if (c < 0) + low = mid + 1; + else + high = mid - 1; + } + if (c < 0) + mid++; + return -(mid + 1); +} + +FcPatternElt * +FcPatternObjectFindElt (const FcPattern *p, FcObject object) +{ + int i = FcPatternObjectPosition (p, object); + if (i < 0) + return 0; + return &FcPatternElts(p)[i]; +} + +FcPatternElt * +FcPatternObjectInsertElt (FcPattern *p, FcObject object) +{ + int i; + FcPatternElt *e; + + i = FcPatternObjectPosition (p, object); + if (i < 0) + { + i = -i - 1; + + /* reallocate array */ + if (p->num + 1 >= p->size) + { + int s = p->size + 16; + if (p->size) + { + FcPatternElt *e0 = FcPatternElts(p); + e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt)); + if (!e) /* maybe it was mmapped */ + { + e = malloc(s * sizeof (FcPatternElt)); + if (e) + memcpy(e, e0, p->num * sizeof (FcPatternElt)); + } + } + else + e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt)); + if (!e) + return FcFalse; + p->elts_offset = FcPtrToOffset (p, e); + if (p->size) + FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt)); + FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt)); + while (p->size < s) + { + e[p->size].object = 0; + e[p->size].values = NULL; + p->size++; + } + } + + e = FcPatternElts(p); + /* move elts up */ + memmove (e + i + 1, + e + i, + sizeof (FcPatternElt) * + (p->num - i)); + + /* bump count */ + p->num++; + + e[i].object = object; + e[i].values = NULL; + } + + return FcPatternElts(p) + i; +} + +FcBool +FcPatternEqual (const FcPattern *pa, const FcPattern *pb) +{ + int i; + FcPatternElt *pae, *pbe; + + if (pa == pb) + return FcTrue; + + if (pa->num != pb->num) + return FcFalse; + pae = FcPatternElts(pa); + pbe = FcPatternElts(pb); + for (i = 0; i < pa->num; i++) + { + if (pae[i].object != pbe[i].object) + return FcFalse; + if (!FcValueListEqual (FcPatternEltValues(&pae[i]), + FcPatternEltValues(&pbe[i]))) + return FcFalse; + } + return FcTrue; +} + +FcChar32 +FcPatternHash (const FcPattern *p) +{ + int i; + FcChar32 h = 0; + FcPatternElt *pe = FcPatternElts(p); + + for (i = 0; i < p->num; i++) + { + h = (((h << 1) | (h >> 31)) ^ + pe[i].object ^ + FcValueListHash (FcPatternEltValues(&pe[i]))); + } + return h; +} + +FcBool +FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os) +{ + FcPatternElt *ea, *eb; + int i; + + for (i = 0; i < os->nobject; i++) + { + FcObject object = FcObjectFromName (os->objects[i]); + ea = FcPatternObjectFindElt (pai, object); + eb = FcPatternObjectFindElt (pbi, object); + if (ea) + { + if (!eb) + return FcFalse; + if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb))) + return FcFalse; + } + else + { + if (eb) + return FcFalse; + } + } + return FcTrue; +} + +FcBool +FcPatternObjectAddWithBinding (FcPattern *p, + FcObject object, + FcValue value, + FcValueBinding binding, + FcBool append) +{ + FcPatternElt *e; + FcValueListPtr new, *prev; + + if (p->ref == FC_REF_CONSTANT) + goto bail0; + + new = malloc (sizeof (FcValueList)); + if (!new) + goto bail0; + + memset(new, 0, sizeof (FcValueList)); + FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); + value = FcValueSave (value); + if (value.type == FcTypeVoid) + goto bail1; + + /* + * Make sure the stored type is valid for built-in objects + */ + if (!FcObjectValidType (object, value.type)) + { + if (FcDebug() & FC_DBG_OBJTYPES) + { + printf ("FcPattern object %s does not accept value ", + FcObjectName (object)); + FcValuePrint (value); + } + goto bail1; + } + + new->value = value; + new->binding = binding; + new->next = NULL; + + e = FcPatternObjectInsertElt (p, object); + 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: + FcValueDestroy (value); +bail1: + FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); + free (new); +bail0: + return FcFalse; +} + +FcBool +FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append) +{ + return FcPatternObjectAddWithBinding (p, object, + value, FcValueBindingStrong, append); +} + +FcBool +FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append) +{ + return FcPatternObjectAddWithBinding (p, FcObjectFromName (object), + value, FcValueBindingStrong, append); +} + +FcBool +FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append) +{ + return FcPatternObjectAddWithBinding (p, FcObjectFromName (object), + value, FcValueBindingWeak, append); +} + +FcBool +FcPatternObjectDel (FcPattern *p, FcObject object) +{ + FcPatternElt *e; + + e = FcPatternObjectFindElt (p, object); + if (!e) + return FcFalse; + + /* destroy value */ + FcValueListDestroy (e->values); + + /* shuffle existing ones down */ + memmove (e, e+1, + (FcPatternElts(p) + p->num - (e + 1)) * + sizeof (FcPatternElt)); + p->num--; + e = FcPatternElts(p) + p->num; + e->object = 0; + e->values = NULL; + return FcTrue; +} + +FcBool +FcPatternDel (FcPattern *p, const char *object) +{ + return FcPatternObjectDel (p, FcObjectFromName (object)); +} + +FcBool +FcPatternRemove (FcPattern *p, const char *object, int id) +{ + FcPatternElt *e; + FcValueListPtr *prev, l; + + e = FcPatternObjectFindElt (p, FcObjectFromName (object)); + if (!e) + return FcFalse; + for (prev = &e->values; (l = *prev); prev = &l->next) + { + if (!id) + { + *prev = l->next; + l->next = NULL; + FcValueListDestroy (l); + if (!e->values) + FcPatternDel (p, object); + return FcTrue; + } + id--; + } + return FcFalse; +} + +FcBool +FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i) +{ + FcValue v; + + v.type = FcTypeInteger; + v.u.i = i; + return FcPatternObjectAdd (p, object, v, FcTrue); +} + +FcBool +FcPatternAddInteger (FcPattern *p, const char *object, int i) +{ + return FcPatternObjectAddInteger (p, FcObjectFromName (object), i); +} + +FcBool +FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d) +{ + FcValue v; + + v.type = FcTypeDouble; + v.u.d = d; + return FcPatternObjectAdd (p, object, v, FcTrue); +} + + +FcBool +FcPatternAddDouble (FcPattern *p, const char *object, double d) +{ + return FcPatternObjectAddDouble (p, FcObjectFromName (object), d); +} + +FcBool +FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s) +{ + FcValue v; + + if (!s) + { + v.type = FcTypeVoid; + v.u.s = 0; + return FcPatternObjectAdd (p, object, v, FcTrue); + } + + v.type = FcTypeString; + v.u.s = FcStrStaticName(s); + return FcPatternObjectAdd (p, object, v, FcTrue); +} + +FcBool +FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s) +{ + return FcPatternObjectAddString (p, FcObjectFromName (object), s); +} + +FcBool +FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s) +{ + FcValue v; + + v.type = FcTypeMatrix; + v.u.m = s; + return FcPatternAdd (p, object, v, FcTrue); +} + + +FcBool +FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b) +{ + FcValue v; + + v.type = FcTypeBool; + v.u.b = b; + return FcPatternObjectAdd (p, object, v, FcTrue); +} + +FcBool +FcPatternAddBool (FcPattern *p, const char *object, FcBool b) +{ + return FcPatternObjectAddBool (p, FcObjectFromName (object), b); +} + +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); +} + +FcBool +FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f) +{ + FcValue v; + + v.type = FcTypeFTFace; + v.u.f = (void *) f; + return FcPatternAdd (p, object, v, FcTrue); +} + +FcBool +FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls) +{ + FcValue v; + + v.type = FcTypeLangSet; + v.u.l = (FcLangSet *)ls; + return FcPatternAdd (p, object, v, FcTrue); +} + +FcResult +FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v) +{ + FcPatternElt *e; + FcValueListPtr l; + + e = FcPatternObjectFindElt (p, object); + if (!e) + return FcResultNoMatch; + for (l = FcPatternEltValues(e); l; l = FcValueListNext(l)) + { + if (!id) + { + *v = FcValueCanonicalize(&l->value); + return FcResultMatch; + } + id--; + } + return FcResultNoId; +} + +FcResult +FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v) +{ + return FcPatternObjectGet (p, FcObjectFromName (object), id, v); +} + +FcResult +FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i) +{ + FcValue v; + FcResult r; + + r = FcPatternObjectGet (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 +FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i) +{ + return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i); +} + + +FcResult +FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d) +{ + FcValue v; + FcResult r; + + r = FcPatternObjectGet (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 +FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d) +{ + return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d); +} + +FcResult +FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s) +{ + FcValue v; + FcResult r; + + r = FcPatternObjectGet (p, object, id, &v); + if (r != FcResultMatch) + return r; + if (v.type != FcTypeString) + return FcResultTypeMismatch; + + *s = (FcChar8 *) v.u.s; + return FcResultMatch; +} + +FcResult +FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s) +{ + return FcPatternObjectGetString (p, FcObjectFromName (object), id, s); +} + +FcResult +FcPatternGetMatrix(const 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(const 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(const 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; +} + +FcResult +FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f) +{ + FcValue v; + FcResult r; + + r = FcPatternGet (p, object, id, &v); + if (r != FcResultMatch) + return r; + if (v.type != FcTypeFTFace) + return FcResultTypeMismatch; + *f = (FT_Face) v.u.f; + return FcResultMatch; +} + +FcResult +FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls) +{ + FcValue v; + FcResult r; + + r = FcPatternGet (p, object, id, &v); + if (r != FcResultMatch) + return r; + if (v.type != FcTypeLangSet) + return FcResultTypeMismatch; + *ls = (FcLangSet *)v.u.l; + return FcResultMatch; +} + +FcPattern * +FcPatternDuplicate (const FcPattern *orig) +{ + FcPattern *new; + FcPatternElt *e; + int i; + FcValueListPtr l; + + new = FcPatternCreate (); + if (!new) + goto bail0; + + e = FcPatternElts(orig); + + for (i = 0; i < orig->num; i++) + { + for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l)) + { + if (!FcPatternObjectAddWithBinding (new, e[i].object, + FcValueCanonicalize(&l->value), + l->binding, + FcTrue)) + goto bail1; + + } + } + + return new; + +bail1: + FcPatternDestroy (new); +bail0: + return 0; +} + +void +FcPatternReference (FcPattern *p) +{ + if (p->ref != FC_REF_CONSTANT) + p->ref++; + else + FcCacheObjectReference (p); +} + +FcPattern * +FcPatternVaBuild (FcPattern *p, va_list va) +{ + FcPattern *ret; + + FcPatternVapBuild (ret, p, va); + return ret; +} + +FcPattern * +FcPatternBuild (FcPattern *p, ...) +{ + va_list va; + + va_start (va, p); + FcPatternVapBuild (p, p, va); + va_end (va); + return p; +} + +/* + * Add all of the elements in 's' to 'p' + */ +FcBool +FcPatternAppend (FcPattern *p, FcPattern *s) +{ + int i; + FcPatternElt *e; + FcValueListPtr v; + + for (i = 0; i < s->num; i++) + { + e = FcPatternElts(s)+i; + for (v = FcPatternEltValues(e); v; v = FcValueListNext(v)) + { + if (!FcPatternObjectAddWithBinding (p, e->object, + FcValueCanonicalize(&v->value), + v->binding, FcTrue)) + return FcFalse; + } + } + return FcTrue; +} + +FcPattern * +FcPatternFilter (FcPattern *p, const FcObjectSet *os) +{ + int i; + FcPattern *ret; + FcPatternElt *e; + FcValueListPtr v; + + if (!os) + return FcPatternDuplicate (p); + + ret = FcPatternCreate (); + if (!ret) + return NULL; + + for (i = 0; i < os->nobject; i++) + { + FcObject object = FcObjectFromName (os->objects[i]); + e = FcPatternObjectFindElt (p, object); + if (e) + { + for (v = FcPatternEltValues(e); v; v = FcValueListNext(v)) + { + if (!FcPatternObjectAddWithBinding (ret, e->object, + FcValueCanonicalize(&v->value), + v->binding, FcTrue)) + goto bail0; + } + } + } + return ret; + +bail0: + FcPatternDestroy (ret); + return NULL; +} + +#define OBJECT_HASH_SIZE 31 +static struct objectBucket { + struct objectBucket *next; + FcChar32 hash; +} *FcObjectBuckets[OBJECT_HASH_SIZE]; + +static FcBool +FcHashOwnsName (const FcChar8 *name) +{ + FcChar32 hash = FcStringHash (name); + struct objectBucket **p; + struct objectBucket *b; + + for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + if (b->hash == hash && ((char *)name == (char *) (b + 1))) + return FcTrue; + return FcFalse; +} + +const FcChar8 * +FcStrStaticName (const FcChar8 *name) +{ + FcChar32 hash = FcStringHash (name); + struct objectBucket **p; + struct objectBucket *b; + int size; + + for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1))) + return (FcChar8 *) (b + 1); + size = sizeof (struct objectBucket) + strlen ((char *)name) + 1; + /* + * workaround valgrind warning because glibc takes advantage of how it knows memory is + * allocated to implement strlen by reading in groups of 4 + */ + size = (size + 3) & ~3; + b = malloc (size); + FcMemAlloc (FC_MEM_STATICSTR, size); + if (!b) + return NULL; + b->next = 0; + b->hash = hash; + strcpy ((char *) (b + 1), (char *)name); + *p = b; + return (FcChar8 *) (b + 1); +} + +static void +FcStrStaticNameFini (void) +{ + int i, size; + struct objectBucket *b, *next; + char *name; + + for (i = 0; i < OBJECT_HASH_SIZE; i++) + { + for (b = FcObjectBuckets[i]; b; b = next) + { + next = b->next; + name = (char *) (b + 1); + size = sizeof (struct objectBucket) + strlen (name) + 1; + FcMemFree (FC_MEM_STATICSTR, size + sizeof (int)); + free (b); + } + FcObjectBuckets[i] = 0; + } +} + +void +FcPatternFini (void) +{ + FcStrStaticNameFini (); + FcObjectFini (); +} + +FcBool +FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat) +{ + int i; + FcPatternElt *elts = FcPatternElts(pat); + + if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern))) + return FcFalse; + if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt))) + return FcFalse; + for (i = 0; i < pat->num; i++) + if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i))) + return FcFalse; + return FcTrue; +} + +FcPattern * +FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat) +{ + FcPattern *pat_serialized; + FcPatternElt *elts = FcPatternElts (pat); + FcPatternElt *elts_serialized; + FcValueList *values_serialized; + int i; + + pat_serialized = FcSerializePtr (serialize, pat); + if (!pat_serialized) + return NULL; + *pat_serialized = *pat; + pat_serialized->size = pat->num; + pat_serialized->ref = FC_REF_CONSTANT; + + elts_serialized = FcSerializePtr (serialize, elts); + if (!elts_serialized) + return NULL; + + pat_serialized->elts_offset = FcPtrToOffset (pat_serialized, + elts_serialized); + + for (i = 0; i < pat->num; i++) + { + values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i)); + if (!values_serialized) + return NULL; + elts_serialized[i].object = elts[i].object; + elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i], + values_serialized, + FcValueList); + } + if (FcDebug() & FC_DBG_CACHEV) { + printf ("Raw pattern:\n"); + FcPatternPrint (pat); + printf ("Serialized pattern:\n"); + FcPatternPrint (pat_serialized); + printf ("\n"); + } + return pat_serialized; +} + +FcBool +FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl) +{ + while (vl) + { + if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList))) + return FcFalse; + switch (vl->value.type) { + case FcTypeString: + if (!FcStrSerializeAlloc (serialize, vl->value.u.s)) + return FcFalse; + break; + case FcTypeCharSet: + if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c)) + return FcFalse; + break; + case FcTypeLangSet: + if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l)) + return FcFalse; + break; + default: + break; + } + vl = vl->next; + } + return FcTrue; +} + +FcValueList * +FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl) +{ + FcValueList *vl_serialized; + FcChar8 *s_serialized; + FcCharSet *c_serialized; + FcLangSet *l_serialized; + FcValueList *head_serialized = NULL; + FcValueList *prev_serialized = NULL; + + while (vl) + { + vl_serialized = FcSerializePtr (serialize, vl); + if (!vl_serialized) + return NULL; + + if (prev_serialized) + prev_serialized->next = FcPtrToEncodedOffset (prev_serialized, + vl_serialized, + FcValueList); + else + head_serialized = vl_serialized; + + vl_serialized->next = NULL; + vl_serialized->value.type = vl->value.type; + switch (vl->value.type) { + case FcTypeInteger: + vl_serialized->value.u.i = vl->value.u.i; + break; + case FcTypeDouble: + vl_serialized->value.u.d = vl->value.u.d; + break; + case FcTypeString: + s_serialized = FcStrSerialize (serialize, vl->value.u.s); + if (!s_serialized) + return NULL; + vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value, + s_serialized, + FcChar8); + break; + case FcTypeBool: + vl_serialized->value.u.b = vl->value.u.b; + break; + case FcTypeMatrix: + /* can't happen */ + break; + case FcTypeCharSet: + c_serialized = FcCharSetSerialize (serialize, vl->value.u.c); + if (!c_serialized) + return NULL; + vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value, + c_serialized, + FcCharSet); + break; + case FcTypeFTFace: + /* can't happen */ + break; + case FcTypeLangSet: + l_serialized = FcLangSetSerialize (serialize, vl->value.u.l); + if (!l_serialized) + return NULL; + vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value, + l_serialized, + FcLangSet); + break; + default: + break; + } + prev_serialized = vl_serialized; + vl = vl->next; + } + return head_serialized; +} +#define __fcpat__ +#include "fcaliastail.h" +#include "fcftaliastail.h" +#undef __fcpat__ diff --git a/fontconfig/src/fcstr.c b/fontconfig/src/fcstr.c index 6aee5d288..8b94ecba5 100644 --- a/fontconfig/src/fcstr.c +++ b/fontconfig/src/fcstr.c @@ -1,1198 +1,1198 @@ -/*
- * fontconfig/src/fcstr.c
- *
- * Copyright © 2000 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-FcChar8 *
-FcStrCopy (const FcChar8 *s)
-{
- int len;
- FcChar8 *r;
-
- if (!s)
- return 0;
- len = strlen ((char *) s) + 1;
- r = (FcChar8 *) malloc (len);
- if (!r)
- return 0;
- FcMemAlloc (FC_MEM_STRING, len);
- memcpy (r, s, len);
- return r;
-}
-
-FcChar8 *
-FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
-{
- int l = strlen ((char *)s1) + strlen ((char *) s2) + 1;
- FcChar8 *s = malloc (l);
-
- if (!s)
- return 0;
- FcMemAlloc (FC_MEM_STRING, l);
- strcpy ((char *) s, (char *) s1);
- strcat ((char *) s, (char *) s2);
- return s;
-}
-
-void
-FcStrFree (FcChar8 *s)
-{
- FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1);
- free (s);
-}
-
-
-#include "../fc-case/fccase.h"
-
-#define FcCaseFoldUpperCount(cf) \
- ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
-
-#define FC_STR_CANON_BUF_LEN 1024
-
-typedef struct _FcCaseWalker {
- const FcChar8 *read;
- const FcChar8 *src;
- FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1];
-} FcCaseWalker;
-
-static void
-FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
-{
- w->src = src;
- w->read = 0;
-}
-
-static FcChar8
-FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
-{
- FcChar32 ucs4;
- int slen;
- int len = strlen((char*)w->src);
-
- slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
- if (slen <= 0)
- return r;
- if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
- {
- int min = 0;
- int max = FC_NUM_CASE_FOLD;
-
- while (min <= max)
- {
- int mid = (min + max) >> 1;
- FcChar32 low = fcCaseFold[mid].upper;
- FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
-
- if (high <= ucs4)
- min = mid + 1;
- else if (ucs4 < low)
- max = mid - 1;
- else
- {
- const FcCaseFold *fold = &fcCaseFold[mid];
- int dlen;
-
- switch (fold->method) {
- case FC_CASE_FOLD_EVEN_ODD:
- if ((ucs4 & 1) != (fold->upper & 1))
- return r;
- /* fall through ... */
- default:
- dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
- break;
- case FC_CASE_FOLD_FULL:
- dlen = fold->count;
- memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
- break;
- }
-
- /* consume rest of src utf-8 bytes */
- w->src += slen - 1;
-
- /* read from temp buffer */
- w->utf8[dlen] = '\0';
- w->read = w->utf8;
- return *w->read++;
- }
- }
- }
- return r;
-}
-
-static FcChar8
-FcStrCaseWalkerNext (FcCaseWalker *w)
-{
- FcChar8 r;
-
- if (w->read)
- {
- if ((r = *w->read++))
- return r;
- w->read = 0;
- }
- r = *w->src++;
-
- if ((r & 0xc0) == 0xc0)
- return FcStrCaseWalkerLong (w, r);
- if ('A' <= r && r <= 'Z')
- r = r - 'A' + 'a';
- return r;
-}
-
-static FcChar8
-FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w)
-{
- FcChar8 r;
-
- if (w->read)
- {
- if ((r = *w->read++))
- return r;
- w->read = 0;
- }
- do
- {
- r = *w->src++;
- } while (r == ' ');
-
- if ((r & 0xc0) == 0xc0)
- return FcStrCaseWalkerLong (w, r);
- if ('A' <= r && r <= 'Z')
- r = r - 'A' + 'a';
- return r;
-}
-
-FcChar8 *
-FcStrDowncase (const FcChar8 *s)
-{
- FcCaseWalker w;
- int len = 0;
- FcChar8 *dst, *d;
-
- FcStrCaseWalkerInit (s, &w);
- while (FcStrCaseWalkerNext (&w))
- len++;
- d = dst = malloc (len + 1);
- if (!d)
- return 0;
- FcMemAlloc (FC_MEM_STRING, len + 1);
- FcStrCaseWalkerInit (s, &w);
- while ((*d++ = FcStrCaseWalkerNext (&w)));
- return dst;
-}
-
-int
-FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcCaseWalker w1, w2;
- FcChar8 c1, c2;
-
- if (s1 == s2) return 0;
-
- FcStrCaseWalkerInit (s1, &w1);
- FcStrCaseWalkerInit (s2, &w2);
-
- for (;;)
- {
- c1 = FcStrCaseWalkerNext (&w1);
- c2 = FcStrCaseWalkerNext (&w2);
- if (!c1 || (c1 != c2))
- break;
- }
- return (int) c1 - (int) c2;
-}
-
-int
-FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcCaseWalker w1, w2;
- FcChar8 c1, c2;
-
- if (s1 == s2) return 0;
-
- FcStrCaseWalkerInit (s1, &w1);
- FcStrCaseWalkerInit (s2, &w2);
-
- for (;;)
- {
- c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
- c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
- if (!c1 || (c1 != c2))
- break;
- }
- return (int) c1 - (int) c2;
-}
-
-int
-FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcChar8 c1, c2;
-
- if (s1 == s2)
- return 0;
- for (;;)
- {
- c1 = *s1++;
- c2 = *s2++;
- if (!c1 || c1 != c2)
- break;
- }
- return (int) c1 - (int) c2;
-}
-
-/*
- * Return a hash value for a string
- */
-
-FcChar32
-FcStrHashIgnoreCase (const FcChar8 *s)
-{
- FcChar32 h = 0;
- FcCaseWalker w;
- FcChar8 c;
-
- FcStrCaseWalkerInit (s, &w);
- while ((c = FcStrCaseWalkerNext (&w)))
- h = ((h << 3) ^ (h >> 3)) ^ c;
- return h;
-}
-
-/*
- * Is the head of s1 equal to s2?
- */
-
-static FcBool
-FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcCaseWalker w1, w2;
- FcChar8 c1, c2;
-
- FcStrCaseWalkerInit (s1, &w1);
- FcStrCaseWalkerInit (s2, &w2);
-
- for (;;)
- {
- c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
- c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
- if (!c1 || (c1 != c2))
- break;
- }
- return c1 == c2 || !c2;
-}
-
-/*
- * Does s1 contain an instance of s2 (ignoring blanks and case)?
- */
-
-const FcChar8 *
-FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- while (*s1)
- {
- if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
- return s1;
- s1++;
- }
- return 0;
-}
-
-static FcBool
-FcCharIsPunct (const FcChar8 c)
-{
- if (c < '0')
- return FcTrue;
- if (c <= '9')
- return FcFalse;
- if (c < 'A')
- return FcTrue;
- if (c <= 'Z')
- return FcFalse;
- if (c < 'a')
- return FcTrue;
- if (c <= 'z')
- return FcFalse;
- if (c <= '~')
- return FcTrue;
- return FcFalse;
-}
-
-/*
- * Is the head of s1 equal to s2?
- */
-
-static FcBool
-FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcCaseWalker w1, w2;
- FcChar8 c1, c2;
-
- FcStrCaseWalkerInit (s1, &w1);
- FcStrCaseWalkerInit (s2, &w2);
-
- for (;;)
- {
- c1 = FcStrCaseWalkerNext (&w1);
- c2 = FcStrCaseWalkerNext (&w2);
- if (!c1 || (c1 != c2))
- break;
- }
- return c1 == c2 || !c2;
-}
-
-/*
- * Does s1 contain an instance of s2 (ignoring blanks and case)?
- */
-
-const FcChar8 *
-FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- while (*s1)
- {
- if (FcStrIsAtIgnoreCase (s1, s2))
- return s1;
- s1++;
- }
- return 0;
-}
-
-/*
- * Does s1 contain an instance of s2 on a word boundary (ignoring case)?
- */
-
-const FcChar8 *
-FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcBool wordStart = FcTrue;
- int s1len = strlen ((char *) s1);
- int s2len = strlen ((char *) s2);
-
- while (s1len >= s2len)
- {
- if (wordStart &&
- FcStrIsAtIgnoreCase (s1, s2) &&
- (s1len == s2len || FcCharIsPunct (s1[s2len])))
- {
- return s1;
- }
- wordStart = FcFalse;
- if (FcCharIsPunct (*s1))
- wordStart = FcTrue;
- s1++;
- s1len--;
- }
- return 0;
-}
-
-const FcChar8 *
-FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcCaseWalker w1, w2;
- FcChar8 c1, c2;
- const FcChar8 *cur;
-
- if (!s1 || !s2)
- return 0;
-
- if (s1 == s2)
- return s1;
-
- FcStrCaseWalkerInit (s1, &w1);
- FcStrCaseWalkerInit (s2, &w2);
-
- c2 = FcStrCaseWalkerNext (&w2);
-
- for (;;)
- {
- cur = w1.src;
- c1 = FcStrCaseWalkerNext (&w1);
- if (!c1)
- break;
- if (c1 == c2)
- {
- FcCaseWalker w1t = w1;
- FcCaseWalker w2t = w2;
- FcChar8 c1t, c2t;
-
- for (;;)
- {
- c1t = FcStrCaseWalkerNext (&w1t);
- c2t = FcStrCaseWalkerNext (&w2t);
-
- if (!c2t)
- return cur;
- if (c2t != c1t)
- break;
- }
- }
- }
- return 0;
-}
-
-const FcChar8 *
-FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
-{
- FcChar8 c1, c2;
- const FcChar8 * p = s1;
- const FcChar8 * b = s2;
-
- if (!s1 || !s2)
- return 0;
-
- if (s1 == s2)
- return s1;
-
-again:
- c2 = *s2++;
-
- if (!c2)
- return 0;
-
- for (;;)
- {
- p = s1;
- c1 = *s1++;
- if (!c1 || c1 == c2)
- break;
- }
-
- if (c1 != c2)
- return 0;
-
- for (;;)
- {
- c1 = *s1;
- c2 = *s2;
- if (c1 && c2 && c1 != c2)
- {
- s1 = p + 1;
- s2 = b;
- goto again;
- }
- if (!c2)
- return p;
- if (!c1)
- return 0;
- ++ s1;
- ++ s2;
- }
- /* never reached. */
-}
-
-int
-FcUtf8ToUcs4 (const FcChar8 *src_orig,
- FcChar32 *dst,
- int len)
-{
- const 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 (const 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;
-}
-
-int
-FcUcs4ToUtf8 (FcChar32 ucs4,
- FcChar8 dest[FC_UTF8_MAX_LEN])
-{
- int bits;
- FcChar8 *d = dest;
-
- if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
- else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
- else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
- else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
- else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
- else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
- else return 0;
-
- for ( ; bits >= 0; bits-= 6) {
- *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
- }
- return d - dest;
-}
-
-#define GetUtf16(src,endian) \
- ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
- (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
-
-int
-FcUtf16ToUcs4 (const FcChar8 *src_orig,
- FcEndian endian,
- FcChar32 *dst,
- int len) /* in bytes */
-{
- const FcChar8 *src = src_orig;
- FcChar16 a, b;
- FcChar32 result;
-
- if (len < 2)
- return 0;
-
- a = GetUtf16 (src, endian); src += 2; len -= 2;
-
- /*
- * Check for surrogate
- */
- if ((a & 0xfc00) == 0xd800)
- {
- if (len < 2)
- return 0;
- b = GetUtf16 (src, endian); src += 2; len -= 2;
- /*
- * Check for invalid surrogate sequence
- */
- if ((b & 0xfc00) != 0xdc00)
- return 0;
- result = ((((FcChar32) a & 0x3ff) << 10) |
- ((FcChar32) b & 0x3ff)) + 0x10000;
- }
- else
- result = a;
- *dst = result;
- return src - src_orig;
-}
-
-FcBool
-FcUtf16Len (const FcChar8 *string,
- FcEndian endian,
- int len, /* in bytes */
- int *nchar,
- int *wchar)
-{
- int n;
- int clen;
- FcChar32 c;
- FcChar32 max;
-
- n = 0;
- max = 0;
- while (len)
- {
- clen = FcUtf16ToUcs4 (string, endian, &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;
-}
-
-void
-FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
-{
- if (init)
- {
- buf->buf = init;
- buf->size = size;
- } else
- {
- buf->buf = buf->buf_static;
- buf->size = sizeof (buf->buf_static);
- }
- buf->allocated = FcFalse;
- buf->failed = FcFalse;
- buf->len = 0;
-}
-
-void
-FcStrBufDestroy (FcStrBuf *buf)
-{
- if (buf->allocated)
- {
- FcMemFree (FC_MEM_STRBUF, buf->size);
- free (buf->buf);
- FcStrBufInit (buf, 0, 0);
- }
-}
-
-FcChar8 *
-FcStrBufDone (FcStrBuf *buf)
-{
- FcChar8 *ret;
-
- if (buf->failed)
- ret = NULL;
- else
- ret = malloc (buf->len + 1);
- if (ret)
- {
- FcMemAlloc (FC_MEM_STRING, buf->len + 1);
- memcpy (ret, buf->buf, buf->len);
- ret[buf->len] = '\0';
- }
- FcStrBufDestroy (buf);
- return ret;
-}
-
-FcChar8 *
-FcStrBufDoneStatic (FcStrBuf *buf)
-{
- FcStrBufChar (buf, '\0');
-
- if (buf->failed)
- return NULL;
-
- return buf->buf;
-}
-
-FcBool
-FcStrBufChar (FcStrBuf *buf, FcChar8 c)
-{
- if (buf->len == buf->size)
- {
- FcChar8 *new;
- int size;
-
- if (buf->failed)
- return FcFalse;
-
- if (buf->allocated)
- {
- size = buf->size * 2;
- new = realloc (buf->buf, size);
- }
- else
- {
- size = buf->size + 64;
- new = malloc (size);
- if (new)
- {
- buf->allocated = FcTrue;
- memcpy (new, buf->buf, buf->len);
- }
- }
- if (!new)
- {
- buf->failed = FcTrue;
- return FcFalse;
- }
- if (buf->size)
- FcMemFree (FC_MEM_STRBUF, buf->size);
- FcMemAlloc (FC_MEM_STRBUF, size);
- buf->size = size;
- buf->buf = new;
- }
- buf->buf[buf->len++] = c;
- return FcTrue;
-}
-
-FcBool
-FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
-{
- FcChar8 c;
- while ((c = *s++))
- if (!FcStrBufChar (buf, c))
- return FcFalse;
- return FcTrue;
-}
-
-FcBool
-FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
-{
- while (len-- > 0)
- if (!FcStrBufChar (buf, *s++))
- return FcFalse;
- return FcTrue;
-}
-
-FcBool
-FcStrUsesHome (const FcChar8 *s)
-{
- return *s == '~';
-}
-
-FcChar8 *
-FcStrCopyFilename (const FcChar8 *s)
-{
- FcChar8 *new;
-
- if (*s == '~')
- {
- FcChar8 *home = FcConfigHome ();
- FcChar8 *full;
- int size;
- if (!home)
- return 0;
- size = strlen ((char *) home) + strlen ((char *) s);
- full = (FcChar8 *) malloc (size);
- if (!full)
- return 0;
- strcpy ((char *) full, (char *) home);
- strcat ((char *) full, (char *) s + 1);
- new = FcStrCanonFilename (full);
- free (full);
- }
- else
- new = FcStrCanonFilename (s);
- return new;
-}
-
-FcChar8 *
-FcStrLastSlash (const FcChar8 *path)
-{
- FcChar8 *slash;
-
- slash = (FcChar8 *) strrchr ((const char *) path, '/');
-#ifdef _WIN32
- {
- FcChar8 *backslash;
-
- backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
- if (!slash || (backslash && backslash > slash))
- slash = backslash;
- }
-#endif
-
- return slash;
-}
-
-FcChar8 *
-FcStrDirname (const FcChar8 *file)
-{
- FcChar8 *slash;
- FcChar8 *dir;
-
- slash = FcStrLastSlash (file);
- if (!slash)
- return FcStrCopy ((FcChar8 *) ".");
- dir = malloc ((slash - file) + 1);
- if (!dir)
- return 0;
- FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
- strncpy ((char *) dir, (const char *) file, slash - file);
- dir[slash - file] = '\0';
- return dir;
-}
-
-FcChar8 *
-FcStrBasename (const FcChar8 *file)
-{
- FcChar8 *slash;
-
- slash = FcStrLastSlash (file);
- if (!slash)
- return FcStrCopy (file);
- return FcStrCopy (slash + 1);
-}
-
-static FcChar8 *
-FcStrCanonAbsoluteFilename (const FcChar8 *s)
-{
- FcChar8 *file;
- FcChar8 *f;
- const FcChar8 *slash;
- int size;
-
- size = strlen ((char *) s) + 1;
- file = malloc (size);
- if (!file)
- return NULL;
- FcMemAlloc (FC_MEM_STRING, size);
- slash = NULL;
- f = file;
- for (;;) {
- if (*s == '/' || *s == '\0')
- {
- if (slash)
- {
- switch (s - slash) {
- case 1:
- f -= 1; /* squash // and trim final / from file */
- break;
- case 2:
- if (!strncmp ((char *) slash, "/.", 2))
- {
- f -= 2; /* trim /. from file */
- }
- break;
- case 3:
- if (!strncmp ((char *) slash, "/..", 3))
- {
- f -= 3; /* trim /.. from file */
- while (f > file) {
- if (*--f == '/')
- break;
- }
- }
- break;
- }
- }
- slash = s;
- }
- if (!(*f++ = *s++))
- break;
- }
- return file;
-}
-
-#ifdef _WIN32
-/*
- * Convert '\\' to '/' , remove double '/'
- */
-static void
-FcConvertDosPath (char *str)
-{
- size_t len = strlen (str);
- char *p = str;
- char *dest = str;
- char *end = str + len;
- char last = 0;
-
- if (*p == '\\')
- {
- *p = '/';
- p++;
- dest++;
- }
- while (p < end)
- {
- if (*p == '\\')
- *p = '/';
-
- if (*p != '/'
- || last != '/')
- {
- *dest++ = *p;
- }
-
- last = *p;
- p++;
- }
-
- *dest = 0;
-}
-#endif
-
-FcChar8 *
-FcStrCanonFilename (const FcChar8 *s)
-{
-#ifdef _WIN32
- FcChar8 full[FC_MAX_FILE_LEN + 2];
- int size = GetFullPathName (s, sizeof (full) -1,
- full, NULL);
-
- if (size == 0)
- perror ("GetFullPathName");
-
- FcConvertDosPath (full);
- return FcStrCanonAbsoluteFilename (full);
-#else
- if (s[0] == '/')
- return FcStrCanonAbsoluteFilename (s);
- else
- {
- FcChar8 *full;
- FcChar8 *file;
-
- FcChar8 cwd[FC_MAX_FILE_LEN + 2];
- if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL)
- return NULL;
- strcat ((char *) cwd, "/");
- full = FcStrPlus (cwd, s);
- file = FcStrCanonAbsoluteFilename (full);
- FcStrFree (full);
- return file;
- }
-#endif
-}
-
-
-FcStrSet *
-FcStrSetCreate (void)
-{
- FcStrSet *set = malloc (sizeof (FcStrSet));
- if (!set)
- return 0;
- FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
- set->ref = 1;
- set->num = 0;
- set->size = 0;
- set->strs = 0;
- return set;
-}
-
-static FcBool
-_FcStrSetAppend (FcStrSet *set, FcChar8 *s)
-{
- if (FcStrSetMember (set, s))
- {
- FcStrFree (s);
- return FcTrue;
- }
- if (set->num == set->size)
- {
- FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
-
- if (!strs)
- return FcFalse;
- FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
- if (set->num)
- memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
- if (set->strs)
- {
- FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *));
- free (set->strs);
- }
- set->size = set->size + 1;
- set->strs = strs;
- }
- set->strs[set->num++] = s;
- set->strs[set->num] = 0;
- return FcTrue;
-}
-
-FcBool
-FcStrSetMember (FcStrSet *set, const FcChar8 *s)
-{
- int i;
-
- for (i = 0; i < set->num; i++)
- if (!FcStrCmp (set->strs[i], s))
- return FcTrue;
- return FcFalse;
-}
-
-FcBool
-FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
-{
- int i;
- if (sa->num != sb->num)
- return FcFalse;
- for (i = 0; i < sa->num; i++)
- if (!FcStrSetMember (sb, sa->strs[i]))
- return FcFalse;
- return FcTrue;
-}
-
-FcBool
-FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
-{
- FcChar8 *new = FcStrCopy (s);
- if (!new)
- return FcFalse;
- if (!_FcStrSetAppend (set, new))
- {
- FcStrFree (new);
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcBool
-FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
-{
- FcChar8 *new = FcStrCopyFilename (s);
- if (!new)
- return FcFalse;
- if (!_FcStrSetAppend (set, new))
- {
- FcStrFree (new);
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcBool
-FcStrSetDel (FcStrSet *set, const FcChar8 *s)
-{
- int i;
-
- for (i = 0; i < set->num; i++)
- if (!FcStrCmp (set->strs[i], s))
- {
- FcStrFree (set->strs[i]);
- /*
- * copy remaining string pointers and trailing
- * NULL
- */
- memmove (&set->strs[i], &set->strs[i+1],
- (set->num - i) * sizeof (FcChar8 *));
- set->num--;
- return FcTrue;
- }
- return FcFalse;
-}
-
-void
-FcStrSetDestroy (FcStrSet *set)
-{
- if (--set->ref == 0)
- {
- int i;
-
- for (i = 0; i < set->num; i++)
- FcStrFree (set->strs[i]);
- if (set->strs)
- {
- FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *));
- free (set->strs);
- }
- FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
- free (set);
- }
-}
-
-FcStrList *
-FcStrListCreate (FcStrSet *set)
-{
- FcStrList *list;
-
- list = malloc (sizeof (FcStrList));
- if (!list)
- return 0;
- FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
- list->set = set;
- set->ref++;
- list->n = 0;
- return list;
-}
-
-FcChar8 *
-FcStrListNext (FcStrList *list)
-{
- if (list->n >= list->set->num)
- return 0;
- return list->set->strs[list->n++];
-}
-
-void
-FcStrListDone (FcStrList *list)
-{
- FcStrSetDestroy (list->set);
- FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
- free (list);
-}
-
-#define __fcstr__
-#include "fcaliastail.h"
-#undef __fcstr__
+/* + * fontconfig/src/fcstr.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#ifdef _WIN32 +#include <windows.h> +#endif + +FcChar8 * +FcStrCopy (const FcChar8 *s) +{ + int len; + FcChar8 *r; + + if (!s) + return 0; + len = strlen ((char *) s) + 1; + r = (FcChar8 *) malloc (len); + if (!r) + return 0; + FcMemAlloc (FC_MEM_STRING, len); + memcpy (r, s, len); + return r; +} + +FcChar8 * +FcStrPlus (const FcChar8 *s1, const FcChar8 *s2) +{ + int l = strlen ((char *)s1) + strlen ((char *) s2) + 1; + FcChar8 *s = malloc (l); + + if (!s) + return 0; + FcMemAlloc (FC_MEM_STRING, l); + strcpy ((char *) s, (char *) s1); + strcat ((char *) s, (char *) s2); + return s; +} + +void +FcStrFree (FcChar8 *s) +{ + FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1); + free (s); +} + + +#include "../fc-case/fccase.h" + +#define FcCaseFoldUpperCount(cf) \ + ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) + +#define FC_STR_CANON_BUF_LEN 1024 + +typedef struct _FcCaseWalker { + const FcChar8 *read; + const FcChar8 *src; + FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1]; +} FcCaseWalker; + +static void +FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w) +{ + w->src = src; + w->read = 0; +} + +static FcChar8 +FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) +{ + FcChar32 ucs4; + int slen; + int len = strlen((char*)w->src); + + slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1); + if (slen <= 0) + return r; + if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR) + { + int min = 0; + int max = FC_NUM_CASE_FOLD; + + while (min <= max) + { + int mid = (min + max) >> 1; + FcChar32 low = fcCaseFold[mid].upper; + FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]); + + if (high <= ucs4) + min = mid + 1; + else if (ucs4 < low) + max = mid - 1; + else + { + const FcCaseFold *fold = &fcCaseFold[mid]; + int dlen; + + switch (fold->method) { + case FC_CASE_FOLD_EVEN_ODD: + if ((ucs4 & 1) != (fold->upper & 1)) + return r; + /* fall through ... */ + default: + dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8); + break; + case FC_CASE_FOLD_FULL: + dlen = fold->count; + memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen); + break; + } + + /* consume rest of src utf-8 bytes */ + w->src += slen - 1; + + /* read from temp buffer */ + w->utf8[dlen] = '\0'; + w->read = w->utf8; + return *w->read++; + } + } + } + return r; +} + +static FcChar8 +FcStrCaseWalkerNext (FcCaseWalker *w) +{ + FcChar8 r; + + if (w->read) + { + if ((r = *w->read++)) + return r; + w->read = 0; + } + r = *w->src++; + + if ((r & 0xc0) == 0xc0) + return FcStrCaseWalkerLong (w, r); + if ('A' <= r && r <= 'Z') + r = r - 'A' + 'a'; + return r; +} + +static FcChar8 +FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w) +{ + FcChar8 r; + + if (w->read) + { + if ((r = *w->read++)) + return r; + w->read = 0; + } + do + { + r = *w->src++; + } while (r == ' '); + + if ((r & 0xc0) == 0xc0) + return FcStrCaseWalkerLong (w, r); + if ('A' <= r && r <= 'Z') + r = r - 'A' + 'a'; + return r; +} + +FcChar8 * +FcStrDowncase (const FcChar8 *s) +{ + FcCaseWalker w; + int len = 0; + FcChar8 *dst, *d; + + FcStrCaseWalkerInit (s, &w); + while (FcStrCaseWalkerNext (&w)) + len++; + d = dst = malloc (len + 1); + if (!d) + return 0; + FcMemAlloc (FC_MEM_STRING, len + 1); + FcStrCaseWalkerInit (s, &w); + while ((*d++ = FcStrCaseWalkerNext (&w))); + return dst; +} + +int +FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + if (s1 == s2) return 0; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNext (&w1); + c2 = FcStrCaseWalkerNext (&w2); + if (!c1 || (c1 != c2)) + break; + } + return (int) c1 - (int) c2; +} + +int +FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + if (s1 == s2) return 0; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1); + c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2); + if (!c1 || (c1 != c2)) + break; + } + return (int) c1 - (int) c2; +} + +int +FcStrCmp (const FcChar8 *s1, const FcChar8 *s2) +{ + FcChar8 c1, c2; + + if (s1 == s2) + return 0; + for (;;) + { + c1 = *s1++; + c2 = *s2++; + if (!c1 || c1 != c2) + break; + } + return (int) c1 - (int) c2; +} + +/* + * Return a hash value for a string + */ + +FcChar32 +FcStrHashIgnoreCase (const FcChar8 *s) +{ + FcChar32 h = 0; + FcCaseWalker w; + FcChar8 c; + + FcStrCaseWalkerInit (s, &w); + while ((c = FcStrCaseWalkerNext (&w))) + h = ((h << 3) ^ (h >> 3)) ^ c; + return h; +} + +/* + * Is the head of s1 equal to s2? + */ + +static FcBool +FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1); + c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2); + if (!c1 || (c1 != c2)) + break; + } + return c1 == c2 || !c2; +} + +/* + * Does s1 contain an instance of s2 (ignoring blanks and case)? + */ + +const FcChar8 * +FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) +{ + while (*s1) + { + if (FcStrIsAtIgnoreBlanksAndCase (s1, s2)) + return s1; + s1++; + } + return 0; +} + +static FcBool +FcCharIsPunct (const FcChar8 c) +{ + if (c < '0') + return FcTrue; + if (c <= '9') + return FcFalse; + if (c < 'A') + return FcTrue; + if (c <= 'Z') + return FcFalse; + if (c < 'a') + return FcTrue; + if (c <= 'z') + return FcFalse; + if (c <= '~') + return FcTrue; + return FcFalse; +} + +/* + * Is the head of s1 equal to s2? + */ + +static FcBool +FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNext (&w1); + c2 = FcStrCaseWalkerNext (&w2); + if (!c1 || (c1 != c2)) + break; + } + return c1 == c2 || !c2; +} + +/* + * Does s1 contain an instance of s2 (ignoring blanks and case)? + */ + +const FcChar8 * +FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) +{ + while (*s1) + { + if (FcStrIsAtIgnoreCase (s1, s2)) + return s1; + s1++; + } + return 0; +} + +/* + * Does s1 contain an instance of s2 on a word boundary (ignoring case)? + */ + +const FcChar8 * +FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) +{ + FcBool wordStart = FcTrue; + int s1len = strlen ((char *) s1); + int s2len = strlen ((char *) s2); + + while (s1len >= s2len) + { + if (wordStart && + FcStrIsAtIgnoreCase (s1, s2) && + (s1len == s2len || FcCharIsPunct (s1[s2len]))) + { + return s1; + } + wordStart = FcFalse; + if (FcCharIsPunct (*s1)) + wordStart = FcTrue; + s1++; + s1len--; + } + return 0; +} + +const FcChar8 * +FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + const FcChar8 *cur; + + if (!s1 || !s2) + return 0; + + if (s1 == s2) + return s1; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + c2 = FcStrCaseWalkerNext (&w2); + + for (;;) + { + cur = w1.src; + c1 = FcStrCaseWalkerNext (&w1); + if (!c1) + break; + if (c1 == c2) + { + FcCaseWalker w1t = w1; + FcCaseWalker w2t = w2; + FcChar8 c1t, c2t; + + for (;;) + { + c1t = FcStrCaseWalkerNext (&w1t); + c2t = FcStrCaseWalkerNext (&w2t); + + if (!c2t) + return cur; + if (c2t != c1t) + break; + } + } + } + return 0; +} + +const FcChar8 * +FcStrStr (const FcChar8 *s1, const FcChar8 *s2) +{ + FcChar8 c1, c2; + const FcChar8 * p = s1; + const FcChar8 * b = s2; + + if (!s1 || !s2) + return 0; + + if (s1 == s2) + return s1; + +again: + c2 = *s2++; + + if (!c2) + return 0; + + for (;;) + { + p = s1; + c1 = *s1++; + if (!c1 || c1 == c2) + break; + } + + if (c1 != c2) + return 0; + + for (;;) + { + c1 = *s1; + c2 = *s2; + if (c1 && c2 && c1 != c2) + { + s1 = p + 1; + s2 = b; + goto again; + } + if (!c2) + return p; + if (!c1) + return 0; + ++ s1; + ++ s2; + } + /* never reached. */ +} + +int +FcUtf8ToUcs4 (const FcChar8 *src_orig, + FcChar32 *dst, + int len) +{ + const 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 (const 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; +} + +int +FcUcs4ToUtf8 (FcChar32 ucs4, + FcChar8 dest[FC_UTF8_MAX_LEN]) +{ + int bits; + FcChar8 *d = dest; + + if (ucs4 < 0x80) { *d++= ucs4; bits= -6; } + else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; } + else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; } + else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; } + else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; } + else return 0; + + for ( ; bits >= 0; bits-= 6) { + *d++= ((ucs4 >> bits) & 0x3F) | 0x80; + } + return d - dest; +} + +#define GetUtf16(src,endian) \ + ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \ + (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0])) + +int +FcUtf16ToUcs4 (const FcChar8 *src_orig, + FcEndian endian, + FcChar32 *dst, + int len) /* in bytes */ +{ + const FcChar8 *src = src_orig; + FcChar16 a, b; + FcChar32 result; + + if (len < 2) + return 0; + + a = GetUtf16 (src, endian); src += 2; len -= 2; + + /* + * Check for surrogate + */ + if ((a & 0xfc00) == 0xd800) + { + if (len < 2) + return 0; + b = GetUtf16 (src, endian); src += 2; len -= 2; + /* + * Check for invalid surrogate sequence + */ + if ((b & 0xfc00) != 0xdc00) + return 0; + result = ((((FcChar32) a & 0x3ff) << 10) | + ((FcChar32) b & 0x3ff)) + 0x10000; + } + else + result = a; + *dst = result; + return src - src_orig; +} + +FcBool +FcUtf16Len (const FcChar8 *string, + FcEndian endian, + int len, /* in bytes */ + int *nchar, + int *wchar) +{ + int n; + int clen; + FcChar32 c; + FcChar32 max; + + n = 0; + max = 0; + while (len) + { + clen = FcUtf16ToUcs4 (string, endian, &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; +} + +void +FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) +{ + if (init) + { + buf->buf = init; + buf->size = size; + } else + { + buf->buf = buf->buf_static; + buf->size = sizeof (buf->buf_static); + } + buf->allocated = FcFalse; + buf->failed = FcFalse; + buf->len = 0; +} + +void +FcStrBufDestroy (FcStrBuf *buf) +{ + if (buf->allocated) + { + FcMemFree (FC_MEM_STRBUF, buf->size); + free (buf->buf); + FcStrBufInit (buf, 0, 0); + } +} + +FcChar8 * +FcStrBufDone (FcStrBuf *buf) +{ + FcChar8 *ret; + + if (buf->failed) + ret = NULL; + else + ret = malloc (buf->len + 1); + if (ret) + { + FcMemAlloc (FC_MEM_STRING, buf->len + 1); + memcpy (ret, buf->buf, buf->len); + ret[buf->len] = '\0'; + } + FcStrBufDestroy (buf); + return ret; +} + +FcChar8 * +FcStrBufDoneStatic (FcStrBuf *buf) +{ + FcStrBufChar (buf, '\0'); + + if (buf->failed) + return NULL; + + return buf->buf; +} + +FcBool +FcStrBufChar (FcStrBuf *buf, FcChar8 c) +{ + if (buf->len == buf->size) + { + FcChar8 *new; + int size; + + if (buf->failed) + return FcFalse; + + if (buf->allocated) + { + size = buf->size * 2; + new = realloc (buf->buf, size); + } + else + { + size = buf->size + 64; + new = malloc (size); + if (new) + { + buf->allocated = FcTrue; + memcpy (new, buf->buf, buf->len); + } + } + if (!new) + { + buf->failed = FcTrue; + return FcFalse; + } + if (buf->size) + FcMemFree (FC_MEM_STRBUF, buf->size); + FcMemAlloc (FC_MEM_STRBUF, size); + buf->size = size; + buf->buf = new; + } + buf->buf[buf->len++] = c; + return FcTrue; +} + +FcBool +FcStrBufString (FcStrBuf *buf, const FcChar8 *s) +{ + FcChar8 c; + while ((c = *s++)) + if (!FcStrBufChar (buf, c)) + return FcFalse; + return FcTrue; +} + +FcBool +FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) +{ + while (len-- > 0) + if (!FcStrBufChar (buf, *s++)) + return FcFalse; + return FcTrue; +} + +FcBool +FcStrUsesHome (const FcChar8 *s) +{ + return *s == '~'; +} + +FcChar8 * +FcStrCopyFilename (const FcChar8 *s) +{ + FcChar8 *new; + + if (*s == '~') + { + FcChar8 *home = FcConfigHome (); + FcChar8 *full; + int size; + if (!home) + return 0; + size = strlen ((char *) home) + strlen ((char *) s); + full = (FcChar8 *) malloc (size); + if (!full) + return 0; + strcpy ((char *) full, (char *) home); + strcat ((char *) full, (char *) s + 1); + new = FcStrCanonFilename (full); + free (full); + } + else + new = FcStrCanonFilename (s); + return new; +} + +FcChar8 * +FcStrLastSlash (const FcChar8 *path) +{ + FcChar8 *slash; + + slash = (FcChar8 *) strrchr ((const char *) path, '/'); +#ifdef _WIN32 + { + FcChar8 *backslash; + + backslash = (FcChar8 *) strrchr ((const char *) path, '\\'); + if (!slash || (backslash && backslash > slash)) + slash = backslash; + } +#endif + + return slash; +} + +FcChar8 * +FcStrDirname (const FcChar8 *file) +{ + FcChar8 *slash; + FcChar8 *dir; + + slash = FcStrLastSlash (file); + if (!slash) + return FcStrCopy ((FcChar8 *) "."); + dir = malloc ((slash - file) + 1); + if (!dir) + return 0; + FcMemAlloc (FC_MEM_STRING, (slash - file) + 1); + strncpy ((char *) dir, (const char *) file, slash - file); + dir[slash - file] = '\0'; + return dir; +} + +FcChar8 * +FcStrBasename (const FcChar8 *file) +{ + FcChar8 *slash; + + slash = FcStrLastSlash (file); + if (!slash) + return FcStrCopy (file); + return FcStrCopy (slash + 1); +} + +static FcChar8 * +FcStrCanonAbsoluteFilename (const FcChar8 *s) +{ + FcChar8 *file; + FcChar8 *f; + const FcChar8 *slash; + int size; + + size = strlen ((char *) s) + 1; + file = malloc (size); + if (!file) + return NULL; + FcMemAlloc (FC_MEM_STRING, size); + slash = NULL; + f = file; + for (;;) { + if (*s == '/' || *s == '\0') + { + if (slash) + { + switch (s - slash) { + case 1: + f -= 1; /* squash // and trim final / from file */ + break; + case 2: + if (!strncmp ((char *) slash, "/.", 2)) + { + f -= 2; /* trim /. from file */ + } + break; + case 3: + if (!strncmp ((char *) slash, "/..", 3)) + { + f -= 3; /* trim /.. from file */ + while (f > file) { + if (*--f == '/') + break; + } + } + break; + } + } + slash = s; + } + if (!(*f++ = *s++)) + break; + } + return file; +} + +#ifdef _WIN32 +/* + * Convert '\\' to '/' , remove double '/' + */ +static void +FcConvertDosPath (char *str) +{ + size_t len = strlen (str); + char *p = str; + char *dest = str; + char *end = str + len; + char last = 0; + + if (*p == '\\') + { + *p = '/'; + p++; + dest++; + } + while (p < end) + { + if (*p == '\\') + *p = '/'; + + if (*p != '/' + || last != '/') + { + *dest++ = *p; + } + + last = *p; + p++; + } + + *dest = 0; +} +#endif + +FcChar8 * +FcStrCanonFilename (const FcChar8 *s) +{ +#ifdef _WIN32 + FcChar8 full[FC_MAX_FILE_LEN + 2]; + int size = GetFullPathName (s, sizeof (full) -1, + full, NULL); + + if (size == 0) + perror ("GetFullPathName"); + + FcConvertDosPath (full); + return FcStrCanonAbsoluteFilename (full); +#else + if (s[0] == '/') + return FcStrCanonAbsoluteFilename (s); + else + { + FcChar8 *full; + FcChar8 *file; + + FcChar8 cwd[FC_MAX_FILE_LEN + 2]; + if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) + return NULL; + strcat ((char *) cwd, "/"); + full = FcStrPlus (cwd, s); + file = FcStrCanonAbsoluteFilename (full); + FcStrFree (full); + return file; + } +#endif +} + + +FcStrSet * +FcStrSetCreate (void) +{ + FcStrSet *set = malloc (sizeof (FcStrSet)); + if (!set) + return 0; + FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet)); + set->ref = 1; + set->num = 0; + set->size = 0; + set->strs = 0; + return set; +} + +static FcBool +_FcStrSetAppend (FcStrSet *set, FcChar8 *s) +{ + if (FcStrSetMember (set, s)) + { + FcStrFree (s); + return FcTrue; + } + if (set->num == set->size) + { + FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *)); + + if (!strs) + return FcFalse; + FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *)); + if (set->num) + memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); + if (set->strs) + { + FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *)); + free (set->strs); + } + set->size = set->size + 1; + set->strs = strs; + } + set->strs[set->num++] = s; + set->strs[set->num] = 0; + return FcTrue; +} + +FcBool +FcStrSetMember (FcStrSet *set, const FcChar8 *s) +{ + int i; + + for (i = 0; i < set->num; i++) + if (!FcStrCmp (set->strs[i], s)) + return FcTrue; + return FcFalse; +} + +FcBool +FcStrSetEqual (FcStrSet *sa, FcStrSet *sb) +{ + int i; + if (sa->num != sb->num) + return FcFalse; + for (i = 0; i < sa->num; i++) + if (!FcStrSetMember (sb, sa->strs[i])) + return FcFalse; + return FcTrue; +} + +FcBool +FcStrSetAdd (FcStrSet *set, const FcChar8 *s) +{ + FcChar8 *new = FcStrCopy (s); + if (!new) + return FcFalse; + if (!_FcStrSetAppend (set, new)) + { + FcStrFree (new); + return FcFalse; + } + return FcTrue; +} + +FcBool +FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) +{ + FcChar8 *new = FcStrCopyFilename (s); + if (!new) + return FcFalse; + if (!_FcStrSetAppend (set, new)) + { + FcStrFree (new); + return FcFalse; + } + return FcTrue; +} + +FcBool +FcStrSetDel (FcStrSet *set, const FcChar8 *s) +{ + int i; + + for (i = 0; i < set->num; i++) + if (!FcStrCmp (set->strs[i], s)) + { + FcStrFree (set->strs[i]); + /* + * copy remaining string pointers and trailing + * NULL + */ + memmove (&set->strs[i], &set->strs[i+1], + (set->num - i) * sizeof (FcChar8 *)); + set->num--; + return FcTrue; + } + return FcFalse; +} + +void +FcStrSetDestroy (FcStrSet *set) +{ + if (--set->ref == 0) + { + int i; + + for (i = 0; i < set->num; i++) + FcStrFree (set->strs[i]); + if (set->strs) + { + FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *)); + free (set->strs); + } + FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet)); + free (set); + } +} + +FcStrList * +FcStrListCreate (FcStrSet *set) +{ + FcStrList *list; + + list = malloc (sizeof (FcStrList)); + if (!list) + return 0; + FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList)); + list->set = set; + set->ref++; + list->n = 0; + return list; +} + +FcChar8 * +FcStrListNext (FcStrList *list) +{ + if (list->n >= list->set->num) + return 0; + return list->set->strs[list->n++]; +} + +void +FcStrListDone (FcStrList *list) +{ + FcStrSetDestroy (list->set); + FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList)); + free (list); +} + +#define __fcstr__ +#include "fcaliastail.h" +#undef __fcstr__ diff --git a/fontconfig/src/fcxml.c b/fontconfig/src/fcxml.c index 5c4e9bf24..e0bb72874 100644 --- a/fontconfig/src/fcxml.c +++ b/fontconfig/src/fcxml.c @@ -1,2807 +1,2807 @@ -/*
- * fontconfig/src/fcxml.c
- *
- * Copyright © 2002 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the author(s) not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. The authors make no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) 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"
-#include <fcntl.h>
-#include <stdarg.h>
-#include <dirent.h>
-
-#ifdef ENABLE_LIBXML2
-
-#include <libxml/parser.h>
-
-#define XML_Char xmlChar
-#define XML_Parser xmlParserCtxtPtr
-#define XML_ParserFree xmlFreeParserCtxt
-#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
-#define XML_GetErrorCode xmlCtxtGetLastError
-#define XML_ErrorString(Error) (Error)->message
-
-#else /* ENABLE_LIBXML2 */
-
-#ifndef HAVE_XMLPARSE_H
-#define HAVE_XMLPARSE_H 0
-#endif
-
-#if HAVE_XMLPARSE_H
-#include <xmlparse.h>
-#else
-#include <expat.h>
-#endif
-
-#endif /* ENABLE_LIBXML2 */
-
-#ifdef _WIN32
-#include <mbstring.h>
-#endif
-
-static void
-FcExprDestroy (FcExpr *e);
-
-void
-FcTestDestroy (FcTest *test)
-{
- if (test->next)
- FcTestDestroy (test->next);
- FcExprDestroy (test->expr);
- FcMemFree (FC_MEM_TEST, sizeof (FcTest));
- free (test);
-}
-
-static FcExpr *
-FcExprCreateInteger (FcConfig *config, int i)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpInteger;
- e->u.ival = i;
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateDouble (FcConfig *config, double d)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpDouble;
- e->u.dval = d;
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateString (FcConfig *config, const FcChar8 *s)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpString;
- e->u.sval = FcStrStaticName (s);
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpMatrix;
- e->u.mval = FcMatrixCopy (m);
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateBool (FcConfig *config, FcBool b)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpBool;
- e->u.bval = b;
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpCharSet;
- e->u.cval = FcCharSetCopy (charset);
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpLangSet;
- e->u.lval = FcLangSetCopy (langset);
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateField (FcConfig *config, const char *field)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpField;
- e->u.object = FcObjectFromName (field);
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = FcOpConst;
- e->u.constant = FcStrStaticName (constant);
- }
- return e;
-}
-
-static FcExpr *
-FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
-{
- FcExpr *e = FcConfigAllocExpr (config);
- if (e)
- {
- e->op = op;
- e->u.tree.left = left;
- e->u.tree.right = right;
- }
- return e;
-}
-
-static void
-FcExprDestroy (FcExpr *e)
-{
- if (!e)
- return;
- switch (e->op) {
- case FcOpInteger:
- break;
- case FcOpDouble:
- break;
- case FcOpString:
- break;
- case FcOpMatrix:
- FcMatrixFree (e->u.mval);
- break;
- case FcOpRange:
- break;
- case FcOpCharSet:
- FcCharSetDestroy (e->u.cval);
- break;
- case FcOpLangSet:
- FcLangSetDestroy (e->u.lval);
- break;
- case FcOpBool:
- break;
- case FcOpField:
- break;
- case FcOpConst:
- break;
- case FcOpAssign:
- case FcOpAssignReplace:
- case FcOpPrepend:
- case FcOpPrependFirst:
- case FcOpAppend:
- case FcOpAppendLast:
- break;
- case FcOpOr:
- case FcOpAnd:
- case FcOpEqual:
- case FcOpNotEqual:
- case FcOpLess:
- case FcOpLessEqual:
- case FcOpMore:
- case FcOpMoreEqual:
- case FcOpContains:
- case FcOpListing:
- case FcOpNotContains:
- case FcOpPlus:
- case FcOpMinus:
- case FcOpTimes:
- case FcOpDivide:
- case FcOpQuest:
- case FcOpComma:
- FcExprDestroy (e->u.tree.right);
- /* fall through */
- case FcOpNot:
- case FcOpFloor:
- case FcOpCeil:
- case FcOpRound:
- case FcOpTrunc:
- FcExprDestroy (e->u.tree.left);
- break;
- case FcOpNil:
- case FcOpInvalid:
- break;
- }
-
- e->op = FcOpNil;
-}
-
-void
-FcEditDestroy (FcEdit *e)
-{
- if (e->next)
- FcEditDestroy (e->next);
- if (e->expr)
- FcExprDestroy (e->expr);
- free (e);
-}
-
-typedef enum _FcElement {
- FcElementNone,
- FcElementFontconfig,
- FcElementDir,
- FcElementCacheDir,
- FcElementCache,
- FcElementInclude,
- FcElementConfig,
- FcElementMatch,
- FcElementAlias,
-
- FcElementBlank,
- FcElementRescan,
-
- FcElementPrefer,
- FcElementAccept,
- FcElementDefault,
- FcElementFamily,
-
- FcElementSelectfont,
- FcElementAcceptfont,
- FcElementRejectfont,
- FcElementGlob,
- FcElementPattern,
- FcElementPatelt,
-
- FcElementTest,
- FcElementEdit,
- FcElementInt,
- FcElementDouble,
- FcElementString,
- FcElementMatrix,
- FcElementRange,
- FcElementBool,
- FcElementCharSet,
- FcElementLangSet,
- FcElementName,
- FcElementConst,
- FcElementOr,
- FcElementAnd,
- FcElementEq,
- FcElementNotEq,
- FcElementLess,
- FcElementLessEq,
- FcElementMore,
- FcElementMoreEq,
- FcElementContains,
- FcElementNotContains,
- FcElementPlus,
- FcElementMinus,
- FcElementTimes,
- FcElementDivide,
- FcElementNot,
- FcElementIf,
- FcElementFloor,
- FcElementCeil,
- FcElementRound,
- FcElementTrunc,
- FcElementUnknown
-} FcElement;
-
-static const struct {
- const char name[16];
- FcElement element;
-} fcElementMap[] = {
- { "fontconfig", FcElementFontconfig },
- { "dir", FcElementDir },
- { "cachedir", FcElementCacheDir },
- { "cache", FcElementCache },
- { "include", FcElementInclude },
- { "config", FcElementConfig },
- { "match", FcElementMatch },
- { "alias", FcElementAlias },
-
- { "blank", FcElementBlank },
- { "rescan", FcElementRescan },
-
- { "prefer", FcElementPrefer },
- { "accept", FcElementAccept },
- { "default", FcElementDefault },
- { "family", FcElementFamily },
-
- { "selectfont", FcElementSelectfont },
- { "acceptfont", FcElementAcceptfont },
- { "rejectfont", FcElementRejectfont },
- { "glob", FcElementGlob },
- { "pattern", FcElementPattern },
- { "patelt", FcElementPatelt },
-
- { "test", FcElementTest },
- { "edit", FcElementEdit },
- { "int", FcElementInt },
- { "double", FcElementDouble },
- { "string", FcElementString },
- { "matrix", FcElementMatrix },
- { "range", FcElementRange },
- { "bool", FcElementBool },
- { "charset", FcElementCharSet },
- { "langset", FcElementLangSet },
- { "name", FcElementName },
- { "const", FcElementConst },
- { "or", FcElementOr },
- { "and", FcElementAnd },
- { "eq", FcElementEq },
- { "not_eq", FcElementNotEq },
- { "less", FcElementLess },
- { "less_eq", FcElementLessEq },
- { "more", FcElementMore },
- { "more_eq", FcElementMoreEq },
- { "contains", FcElementContains },
- { "not_contains", FcElementNotContains },
- { "plus", FcElementPlus },
- { "minus", FcElementMinus },
- { "times", FcElementTimes },
- { "divide", FcElementDivide },
- { "not", FcElementNot },
- { "if", FcElementIf },
- { "floor", FcElementFloor },
- { "ceil", FcElementCeil },
- { "round", FcElementRound },
- { "trunc", FcElementTrunc },
-};
-#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
-
-static FcElement
-FcElementMap (const XML_Char *name)
-{
-
- int i;
- for (i = 0; i < NUM_ELEMENT_MAPS; i++)
- if (!strcmp ((char *) name, fcElementMap[i].name))
- return fcElementMap[i].element;
- return FcElementUnknown;
-}
-
-typedef struct _FcPStack {
- struct _FcPStack *prev;
- FcElement element;
- FcChar8 **attr;
- FcStrBuf str;
- FcChar8 *attr_buf_static[16];
-} FcPStack;
-
-typedef enum _FcVStackTag {
- FcVStackNone,
-
- FcVStackString,
- FcVStackFamily,
- FcVStackField,
- FcVStackConstant,
- FcVStackGlob,
- FcVStackPattern,
-
- FcVStackPrefer,
- FcVStackAccept,
- FcVStackDefault,
-
- FcVStackInteger,
- FcVStackDouble,
- FcVStackMatrix,
- FcVStackRange,
- FcVStackBool,
- FcVStackCharSet,
- FcVStackLangSet,
-
- FcVStackTest,
- FcVStackExpr,
- FcVStackEdit
-} FcVStackTag;
-
-typedef struct _FcVStack {
- struct _FcVStack *prev;
- FcPStack *pstack; /* related parse element */
- FcVStackTag tag;
- union {
- FcChar8 *string;
-
- int integer;
- double _double;
- FcMatrix *matrix;
- FcRange range;
- FcBool bool_;
- FcCharSet *charset;
- FcLangSet *langset;
-
- FcTest *test;
- FcQual qual;
- FcOp op;
- FcExpr *expr;
- FcEdit *edit;
-
- FcPattern *pattern;
- } u;
-} FcVStack;
-
-typedef struct _FcConfigParse {
- FcPStack *pstack;
- FcVStack *vstack;
- FcBool error;
- const FcChar8 *name;
- FcConfig *config;
- XML_Parser parser;
- int pstack_static_used;
- FcPStack pstack_static[8];
- int vstack_static_used;
- FcVStack vstack_static[64];
-} FcConfigParse;
-
-typedef enum _FcConfigSeverity {
- FcSevereInfo, FcSevereWarning, FcSevereError
-} FcConfigSeverity;
-
-static void
-FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
-{
- const char *s = "unknown";
- va_list args;
-
- va_start (args, fmt);
-
- switch (severe) {
- case FcSevereInfo: s = "info"; break;
- case FcSevereWarning: s = "warning"; break;
- case FcSevereError: s = "error"; break;
- }
- if (parse)
- {
- if (parse->name)
- fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
- parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
- else
- fprintf (stderr, "Fontconfig %s: line %d: ", s,
- (int)XML_GetCurrentLineNumber (parse->parser));
- if (severe >= FcSevereError)
- parse->error = FcTrue;
- }
- else
- fprintf (stderr, "Fontconfig %s: ", s);
- vfprintf (stderr, fmt, args);
- fprintf (stderr, "\n");
- va_end (args);
-}
-
-
-static const char *
-FcTypeName (FcType type)
-{
- switch (type) {
- case FcTypeVoid:
- return "void";
- case FcTypeInteger:
- case FcTypeDouble:
- return "number";
- case FcTypeString:
- return "string";
- case FcTypeBool:
- return "bool";
- case FcTypeMatrix:
- return "matrix";
- case FcTypeCharSet:
- return "charset";
- case FcTypeFTFace:
- return "FT_Face";
- case FcTypeLangSet:
- return "langset";
- default:
- return "unknown";
- }
-}
-
-static void
-FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
-{
- if (value == FcTypeInteger)
- value = FcTypeDouble;
- if (type == FcTypeInteger)
- type = FcTypeDouble;
- if (value != type)
- {
- if ((value == FcTypeLangSet && type == FcTypeString) ||
- (value == FcTypeString && type == FcTypeLangSet))
- return;
- if (type == (FcType) -1)
- return;
- FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
- FcTypeName (value), FcTypeName (type));
- }
-}
-
-static void
-FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
-{
- const FcObjectType *o;
- const FcConstant *c;
-
- /* If parsing the expression failed, some nodes may be NULL */
- if (!expr)
- return;
-
- switch (expr->op) {
- case FcOpInteger:
- case FcOpDouble:
- FcTypecheckValue (parse, FcTypeDouble, type);
- break;
- case FcOpString:
- FcTypecheckValue (parse, FcTypeString, type);
- break;
- case FcOpMatrix:
- FcTypecheckValue (parse, FcTypeMatrix, type);
- break;
- case FcOpBool:
- FcTypecheckValue (parse, FcTypeBool, type);
- break;
- case FcOpCharSet:
- FcTypecheckValue (parse, FcTypeCharSet, type);
- break;
- case FcOpLangSet:
- FcTypecheckValue (parse, FcTypeLangSet, type);
- break;
- case FcOpNil:
- break;
- case FcOpField:
- o = FcNameGetObjectType (FcObjectName (expr->u.object));
- if (o)
- FcTypecheckValue (parse, o->type, type);
- break;
- case FcOpConst:
- c = FcNameGetConstant (expr->u.constant);
- if (c)
- {
- o = FcNameGetObjectType (c->object);
- if (o)
- FcTypecheckValue (parse, o->type, type);
- }
- else
- FcConfigMessage (parse, FcSevereWarning,
- "invalid constant used : %s",
- expr->u.constant);
- break;
- case FcOpQuest:
- FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
- FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
- FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
- break;
- case FcOpAssign:
- case FcOpAssignReplace:
- break;
- case FcOpEqual:
- case FcOpNotEqual:
- case FcOpLess:
- case FcOpLessEqual:
- case FcOpMore:
- case FcOpMoreEqual:
- case FcOpContains:
- case FcOpNotContains:
- case FcOpListing:
- FcTypecheckValue (parse, FcTypeBool, type);
- break;
- case FcOpComma:
- case FcOpOr:
- case FcOpAnd:
- case FcOpPlus:
- case FcOpMinus:
- case FcOpTimes:
- case FcOpDivide:
- FcTypecheckExpr (parse, expr->u.tree.left, type);
- FcTypecheckExpr (parse, expr->u.tree.right, type);
- break;
- case FcOpNot:
- FcTypecheckValue (parse, FcTypeBool, type);
- FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
- break;
- case FcOpFloor:
- case FcOpCeil:
- case FcOpRound:
- case FcOpTrunc:
- FcTypecheckValue (parse, FcTypeDouble, type);
- FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
- break;
- default:
- break;
- }
-}
-
-static FcTest *
-FcTestCreate (FcConfigParse *parse,
- FcMatchKind kind,
- FcQual qual,
- const FcChar8 *field,
- FcOp compare,
- FcExpr *expr)
-{
- FcTest *test = (FcTest *) malloc (sizeof (FcTest));
-
- if (test)
- {
- const FcObjectType *o;
-
- FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
- test->next = 0;
- test->kind = kind;
- test->qual = qual;
- test->object = FcObjectFromName ((const char *) field);
- test->op = compare;
- test->expr = expr;
- o = FcNameGetObjectType (FcObjectName (test->object));
- if (o)
- FcTypecheckExpr (parse, expr, o->type);
- }
- return test;
-}
-
-static FcEdit *
-FcEditCreate (FcConfigParse *parse,
- FcObject object,
- FcOp op,
- FcExpr *expr,
- FcValueBinding binding)
-{
- FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
-
- if (e)
- {
- const FcObjectType *o;
-
- e->next = 0;
- e->object = object;
- e->op = op;
- e->expr = expr;
- e->binding = binding;
- o = FcNameGetObjectType (FcObjectName (e->object));
- if (o)
- FcTypecheckExpr (parse, expr, o->type);
- }
- return e;
-}
-
-static FcVStack *
-FcVStackCreateAndPush (FcConfigParse *parse)
-{
- FcVStack *new;
-
- if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
- new = &parse->vstack_static[parse->vstack_static_used++];
- else
- {
- new = malloc (sizeof (FcVStack));
- if (!new)
- return 0;
- FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
- }
- new->tag = FcVStackNone;
- new->prev = 0;
-
- new->prev = parse->vstack;
- new->pstack = parse->pstack ? parse->pstack->prev : 0;
- parse->vstack = new;
-
- return new;
-}
-
-static FcBool
-FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.string = string;
- vstack->tag = tag;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushInteger (FcConfigParse *parse, int integer)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.integer = integer;
- vstack->tag = FcVStackInteger;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushDouble (FcConfigParse *parse, double _double)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u._double = _double;
- vstack->tag = FcVStackDouble;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
-{
- FcVStack *vstack;
- matrix = FcMatrixCopy (matrix);
- if (!matrix)
- return FcFalse;
- vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.matrix = matrix;
- vstack->tag = FcVStackMatrix;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushRange (FcConfigParse *parse, FcRange *range)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.range.begin = range->begin;
- vstack->u.range.end = range->end;
- vstack->tag = FcVStackRange;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.bool_ = bool_;
- vstack->tag = FcVStackBool;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
-{
- FcVStack *vstack;
- if (!charset)
- return FcFalse;
- vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.charset = charset;
- vstack->tag = FcVStackCharSet;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
-{
- FcVStack *vstack;
- if (!langset)
- return FcFalse;
- vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.langset = langset;
- vstack->tag = FcVStackLangSet;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushTest (FcConfigParse *parse, FcTest *test)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.test = test;
- vstack->tag = FcVStackTest;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.expr = expr;
- vstack->tag = tag;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.edit = edit;
- vstack->tag = FcVStackEdit;
- return FcTrue;
-}
-
-static FcBool
-FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
-{
- FcVStack *vstack = FcVStackCreateAndPush (parse);
- if (!vstack)
- return FcFalse;
- vstack->u.pattern = pattern;
- vstack->tag = FcVStackPattern;
- return FcTrue;
-}
-
-static FcVStack *
-FcVStackFetch (FcConfigParse *parse, int off)
-{
- FcVStack *vstack;
-
- for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
- return vstack;
-}
-
-static FcVStack *
-FcVStackPeek (FcConfigParse *parse)
-{
- FcVStack *vstack = parse->vstack;
-
- return vstack && vstack->pstack == parse->pstack ? vstack : 0;
-}
-
-static void
-FcVStackPopAndDestroy (FcConfigParse *parse)
-{
- FcVStack *vstack = parse->vstack;
-
- if (!vstack || vstack->pstack != parse->pstack)
- return;
-
- parse->vstack = vstack->prev;
-
- switch (vstack->tag) {
- case FcVStackNone:
- break;
- case FcVStackFamily:
- break;
- case FcVStackString:
- case FcVStackField:
- case FcVStackConstant:
- case FcVStackGlob:
- FcStrFree (vstack->u.string);
- break;
- case FcVStackPattern:
- FcPatternDestroy (vstack->u.pattern);
- break;
- case FcVStackInteger:
- case FcVStackDouble:
- break;
- case FcVStackMatrix:
- FcMatrixFree (vstack->u.matrix);
- break;
- case FcVStackRange:
- case FcVStackBool:
- break;
- case FcVStackCharSet:
- FcCharSetDestroy (vstack->u.charset);
- break;
- case FcVStackLangSet:
- FcLangSetDestroy (vstack->u.langset);
- break;
- case FcVStackTest:
- FcTestDestroy (vstack->u.test);
- break;
- case FcVStackExpr:
- case FcVStackPrefer:
- case FcVStackAccept:
- case FcVStackDefault:
- FcExprDestroy (vstack->u.expr);
- break;
- case FcVStackEdit:
- FcEditDestroy (vstack->u.edit);
- break;
- }
-
- if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
- parse->vstack_static_used--;
- else
- {
- FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
- free (vstack);
- }
-}
-
-static void
-FcVStackClear (FcConfigParse *parse)
-{
- while (FcVStackPeek (parse))
- FcVStackPopAndDestroy (parse);
-}
-
-static int
-FcVStackElements (FcConfigParse *parse)
-{
- int h = 0;
- FcVStack *vstack = parse->vstack;
- while (vstack && vstack->pstack == parse->pstack)
- {
- h++;
- vstack = vstack->prev;
- }
- return h;
-}
-
-static FcChar8 **
-FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
-{
- int slen;
- int i;
- FcChar8 **new;
- FcChar8 *s;
-
- if (!attr)
- return 0;
- slen = 0;
- for (i = 0; attr[i]; i++)
- slen += strlen ((char *) attr[i]) + 1;
- if (i == 0)
- return 0;
- slen += (i + 1) * sizeof (FcChar8 *);
- if (slen <= size_bytes)
- new = buf;
- else
- {
- new = malloc (slen);
- if (!new)
- {
- FcConfigMessage (0, FcSevereError, "out of memory");
- return 0;
- }
- FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
- }
- s = (FcChar8 *) (new + (i + 1));
- for (i = 0; attr[i]; i++)
- {
- new[i] = s;
- strcpy ((char *) s, (char *) attr[i]);
- s += strlen ((char *) s) + 1;
- }
- new[i] = 0;
- return new;
-}
-
-static FcBool
-FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
-{
- FcPStack *new;
-
- if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
- new = &parse->pstack_static[parse->pstack_static_used++];
- else
- {
- new = malloc (sizeof (FcPStack));
- if (!new)
- return FcFalse;
- FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
- }
-
- new->prev = parse->pstack;
- new->element = element;
- new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
- FcStrBufInit (&new->str, 0, 0);
- parse->pstack = new;
- return FcTrue;
-}
-
-static FcBool
-FcPStackPop (FcConfigParse *parse)
-{
- FcPStack *old;
-
- if (!parse->pstack)
- {
- FcConfigMessage (parse, FcSevereError, "mismatching element");
- return FcFalse;
- }
- FcVStackClear (parse);
- old = parse->pstack;
- parse->pstack = old->prev;
- FcStrBufDestroy (&old->str);
- if (old->attr && old->attr != old->attr_buf_static)
- {
- FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
- free (old->attr);
- }
-
- if (old == &parse->pstack_static[parse->pstack_static_used - 1])
- parse->pstack_static_used--;
- else
- {
- FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
- free (old);
- }
- return FcTrue;
-}
-
-static FcBool
-FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
-{
- parse->pstack = 0;
- parse->pstack_static_used = 0;
- parse->vstack = 0;
- parse->vstack_static_used = 0;
- parse->error = FcFalse;
- parse->name = name;
- parse->config = config;
- parse->parser = parser;
- return FcTrue;
-}
-
-static void
-FcConfigCleanup (FcConfigParse *parse)
-{
- while (parse->pstack)
- FcPStackPop (parse);
-}
-
-static const FcChar8 *
-FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
-{
- FcChar8 **attrs;
- if (!parse->pstack)
- return 0;
-
- attrs = parse->pstack->attr;
- if (!attrs)
- return 0;
-
- while (*attrs)
- {
- if (!strcmp ((char *) *attrs, attr))
- return attrs[1];
- attrs += 2;
- }
- return 0;
-}
-
-static void
-FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
-{
- FcConfigParse *parse = userData;
- FcElement element;
-
- element = FcElementMap (name);
- if (element == FcElementUnknown)
- FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
-
- if (!FcPStackPush (parse, element, attr))
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- return;
-}
-
-static void
-FcParseBlank (FcConfigParse *parse)
-{
- int n = FcVStackElements (parse);
- FcChar32 i;
- while (n-- > 0)
- {
- FcVStack *v = FcVStackFetch (parse, n);
- if (!parse->config->blanks)
- {
- parse->config->blanks = FcBlanksCreate ();
- if (!parse->config->blanks)
- goto bail;
- }
- switch (v->tag) {
- case FcVStackInteger:
- if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
- goto bail;
- break;
- case FcVStackRange:
- if (v->u.range.begin <= v->u.range.end)
- {
- for (i = v->u.range.begin; i <= v->u.range.end; i++)
- {
- if (!FcBlanksAdd (parse->config->blanks, i))
- goto bail;
- }
- }
- break;
- default:
- FcConfigMessage (parse, FcSevereError, "invalid element in blank");
- break;
- }
- }
- return;
- bail:
- FcConfigMessage (parse, FcSevereError, "out of memory");
-}
-
-static void
-FcParseRescan (FcConfigParse *parse)
-{
- int n = FcVStackElements (parse);
- while (n-- > 0)
- {
- FcVStack *v = FcVStackFetch (parse, n);
- if (v->tag != FcVStackInteger)
- FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
- else
- parse->config->rescanInterval = v->u.integer;
- }
-}
-
-static void
-FcParseInt (FcConfigParse *parse)
-{
- FcChar8 *s, *end;
- int l;
-
- if (!parse->pstack)
- return;
- s = FcStrBufDoneStatic (&parse->pstack->str);
- if (!s)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- end = 0;
- l = (int) strtol ((char *) s, (char **)&end, 0);
- if (end != s + strlen ((char *) s))
- FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
- else
- FcVStackPushInteger (parse, l);
- FcStrBufDestroy (&parse->pstack->str);
-}
-
-/*
- * idea copied from glib g_ascii_strtod with
- * permission of the author (Alexander Larsson)
- */
-
-#include <locale.h>
-
-static double
-FcStrtod (char *s, char **end)
-{
- struct lconv *locale_data;
- char *dot;
- double v;
-
- /*
- * Have to swap the decimal point to match the current locale
- * if that locale doesn't use 0x2e
- */
- if ((dot = strchr (s, 0x2e)) &&
- (locale_data = localeconv ()) &&
- (locale_data->decimal_point[0] != 0x2e ||
- locale_data->decimal_point[1] != 0))
- {
- char buf[128];
- int slen = strlen (s);
- int dlen = strlen (locale_data->decimal_point);
-
- if (slen + dlen > (int) sizeof (buf))
- {
- if (end)
- *end = s;
- v = 0;
- }
- else
- {
- char *buf_end;
- /* mantissa */
- strncpy (buf, s, dot - s);
- /* decimal point */
- strcpy (buf + (dot - s), locale_data->decimal_point);
- /* rest of number */
- strcpy (buf + (dot - s) + dlen, dot + 1);
- buf_end = 0;
- v = strtod (buf, &buf_end);
- if (buf_end) {
- buf_end = s + (buf_end - buf);
- if (buf_end > dot)
- buf_end -= dlen - 1;
- }
- if (end)
- *end = buf_end;
- }
- }
- else
- v = strtod (s, end);
- return v;
-}
-
-static void
-FcParseDouble (FcConfigParse *parse)
-{
- FcChar8 *s, *end;
- double d;
-
- if (!parse->pstack)
- return;
- s = FcStrBufDoneStatic (&parse->pstack->str);
- if (!s)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- end = 0;
- d = FcStrtod ((char *) s, (char **)&end);
- if (end != s + strlen ((char *) s))
- FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
- else
- FcVStackPushDouble (parse, d);
- FcStrBufDestroy (&parse->pstack->str);
-}
-
-static void
-FcParseString (FcConfigParse *parse, FcVStackTag tag)
-{
- FcChar8 *s;
-
- if (!parse->pstack)
- return;
- s = FcStrBufDone (&parse->pstack->str);
- if (!s)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- if (!FcVStackPushString (parse, tag, s))
- FcStrFree (s);
-}
-
-static void
-FcParseMatrix (FcConfigParse *parse)
-{
- FcVStack *vstack;
- enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
- FcMatrix m;
-
- while ((vstack = FcVStackPeek (parse)))
- {
- double v;
- switch (vstack->tag) {
- case FcVStackInteger:
- v = vstack->u.integer;
- break;
- case FcVStackDouble:
- v = vstack->u._double;
- break;
- default:
- FcConfigMessage (parse, FcSevereError, "non-double matrix element");
- v = 1.0;
- break;
- }
- 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;
- }
- FcVStackPopAndDestroy (parse);
- matrix_state--;
- }
- if (matrix_state != m_done)
- FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
- else
- FcVStackPushMatrix (parse, &m);
-}
-
-static void
-FcParseRange (FcConfigParse *parse)
-{
- FcVStack *vstack;
- FcRange r;
- FcChar32 n;
- int count = 1;
-
- while ((vstack = FcVStackPeek (parse)))
- {
- if (count < 0)
- {
- FcConfigMessage (parse, FcSevereError, "too many elements in range");
- return;
- }
- switch (vstack->tag) {
- case FcVStackInteger:
- n = vstack->u.integer;
- break;
- default:
- FcConfigMessage (parse, FcSevereError, "invalid element in range");
- break;
- }
- if (count == 1)
- r.end = n;
- else
- r.begin = n;
- count--;
- FcVStackPopAndDestroy (parse);
- }
- if (count < 0)
- {
- if (r.begin > r.end)
- {
- FcConfigMessage (parse, FcSevereError, "invalid range");
- return;
- }
- FcVStackPushRange (parse, &r);
- }
- else
- FcConfigMessage (parse, FcSevereError, "invalid range");
-}
-
-static FcBool
-FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
-{
- FcBool result = FcFalse;
-
- if (!FcNameBool (bool_, &result))
- FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
- bool_);
- return result;
-}
-
-static void
-FcParseBool (FcConfigParse *parse)
-{
- FcChar8 *s;
-
- if (!parse->pstack)
- return;
- s = FcStrBufDoneStatic (&parse->pstack->str);
- if (!s)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- FcVStackPushBool (parse, FcConfigLexBool (parse, s));
- FcStrBufDestroy (&parse->pstack->str);
-}
-
-static void
-FcParseCharSet (FcConfigParse *parse)
-{
- FcVStack *vstack;
- FcCharSet *charset = FcCharSetCreate ();
- FcChar32 i;
- int n = 0;
-
- while ((vstack = FcVStackPeek (parse)))
- {
- switch (vstack->tag) {
- case FcVStackInteger:
- if (!FcCharSetAddChar (charset, vstack->u.integer))
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
- }
- else
- n++;
- break;
- case FcVStackRange:
- if (vstack->u.range.begin <= vstack->u.range.end)
- {
- for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
- {
- if (!FcCharSetAddChar (charset, i))
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
- }
- else
- n++;
- }
- }
- break;
- default:
- FcConfigMessage (parse, FcSevereError, "invalid element in charset");
- break;
- }
- FcVStackPopAndDestroy (parse);
- }
- if (n > 0)
- FcVStackPushCharSet (parse, charset);
- else
- FcCharSetDestroy (charset);
-}
-
-static void
-FcParseLangSet (FcConfigParse *parse)
-{
- FcVStack *vstack;
- FcLangSet *langset = FcLangSetCreate ();
- int n = 0;
-
- while ((vstack = FcVStackPeek (parse)))
- {
- switch (vstack->tag) {
- case FcVStackString:
- if (!FcLangSetAdd (langset, vstack->u.string))
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
- }
- else
- n++;
- break;
- default:
- FcConfigMessage (parse, FcSevereError, "invalid element in langset");
- break;
- }
- FcVStackPopAndDestroy (parse);
- }
- if (n > 0)
- FcVStackPushLangSet (parse, langset);
- else
- FcLangSetDestroy (langset);
-}
-
-static FcBool
-FcConfigLexBinding (FcConfigParse *parse,
- const FcChar8 *binding_string,
- FcValueBinding *binding_ret)
-{
- FcValueBinding binding;
-
- if (!binding_string)
- binding = FcValueBindingWeak;
- else
- {
- if (!strcmp ((char *) binding_string, "weak"))
- binding = FcValueBindingWeak;
- else if (!strcmp ((char *) binding_string, "strong"))
- binding = FcValueBindingStrong;
- else if (!strcmp ((char *) binding_string, "same"))
- binding = FcValueBindingSame;
- else
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
- return FcFalse;
- }
- }
- *binding_ret = binding;
- return FcTrue;
-}
-
-static void
-FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
-{
- FcVStack *vstack;
- FcExpr *left, *expr = 0, *new;
-
- while ((vstack = FcVStackPeek (parse)))
- {
- if (vstack->tag != FcVStackFamily)
- {
- FcConfigMessage (parse, FcSevereWarning, "non-family");
- FcVStackPopAndDestroy (parse);
- continue;
- }
- left = vstack->u.expr;
- vstack->tag = FcVStackNone;
- FcVStackPopAndDestroy (parse);
- if (expr)
- {
- new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
- if (!new)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- FcExprDestroy (left);
- FcExprDestroy (expr);
- break;
- }
- expr = new;
- }
- else
- expr = left;
- }
- if (expr)
- {
- if (!FcVStackPushExpr (parse, tag, expr))
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- FcExprDestroy (expr);
- }
- }
-}
-
-static void
-FcParseFamily (FcConfigParse *parse)
-{
- FcChar8 *s;
- FcExpr *expr;
-
- if (!parse->pstack)
- return;
- s = FcStrBufDoneStatic (&parse->pstack->str);
- if (!s)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- expr = FcExprCreateString (parse->config, s);
- FcStrBufDestroy (&parse->pstack->str);
- if (expr)
- FcVStackPushExpr (parse, FcVStackFamily, expr);
-}
-
-static void
-FcParseAlias (FcConfigParse *parse)
-{
- FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
- FcEdit *edit = 0, *next;
- FcVStack *vstack;
- FcTest *test;
- FcValueBinding binding;
-
- if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
- return;
- while ((vstack = FcVStackPeek (parse)))
- {
- switch (vstack->tag) {
- case FcVStackFamily:
- if (family)
- {
- new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
- if (!new)
- FcConfigMessage (parse, FcSevereError, "out of memory");
- else
- family = new;
- }
- else
- new = vstack->u.expr;
- if (new)
- {
- family = new;
- vstack->tag = FcVStackNone;
- }
- break;
- case FcVStackPrefer:
- if (prefer)
- FcExprDestroy (prefer);
- prefer = vstack->u.expr;
- vstack->tag = FcVStackNone;
- break;
- case FcVStackAccept:
- if (accept)
- FcExprDestroy (accept);
- accept = vstack->u.expr;
- vstack->tag = FcVStackNone;
- break;
- case FcVStackDefault:
- if (def)
- FcExprDestroy (def);
- def = vstack->u.expr;
- vstack->tag = FcVStackNone;
- break;
- default:
- FcConfigMessage (parse, FcSevereWarning, "bad alias");
- break;
- }
- FcVStackPopAndDestroy (parse);
- }
- if (!family)
- {
- FcConfigMessage (parse, FcSevereError, "missing family in alias");
- if (prefer)
- FcExprDestroy (prefer);
- if (accept)
- FcExprDestroy (accept);
- if (def)
- FcExprDestroy (def);
- return;
- }
- if (prefer)
- {
- edit = FcEditCreate (parse,
- FC_FAMILY_OBJECT,
- FcOpPrepend,
- prefer,
- binding);
- if (edit)
- edit->next = 0;
- else
- FcExprDestroy (prefer);
- }
- if (accept)
- {
- next = edit;
- edit = FcEditCreate (parse,
- FC_FAMILY_OBJECT,
- FcOpAppend,
- accept,
- binding);
- if (edit)
- edit->next = next;
- else
- FcExprDestroy (accept);
- }
- if (def)
- {
- next = edit;
- edit = FcEditCreate (parse,
- FC_FAMILY_OBJECT,
- FcOpAppendLast,
- def,
- binding);
- if (edit)
- edit->next = next;
- else
- FcExprDestroy (def);
- }
- if (edit)
- {
- test = FcTestCreate (parse, FcMatchPattern,
- FcQualAny,
- (FcChar8 *) FC_FAMILY,
- FcOpEqual,
- family);
- if (test)
- if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
- FcTestDestroy (test);
- }
- else
- FcExprDestroy (family);
-}
-
-static FcExpr *
-FcPopExpr (FcConfigParse *parse)
-{
- FcVStack *vstack = FcVStackPeek (parse);
- FcExpr *expr = 0;
- if (!vstack)
- return 0;
- switch (vstack->tag) {
- case FcVStackNone:
- break;
- case FcVStackString:
- case FcVStackFamily:
- expr = FcExprCreateString (parse->config, vstack->u.string);
- break;
- case FcVStackField:
- expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
- break;
- case FcVStackConstant:
- expr = FcExprCreateConst (parse->config, vstack->u.string);
- break;
- case FcVStackGlob:
- /* XXX: What's the correct action here? (CDW) */
- break;
- case FcVStackPrefer:
- case FcVStackAccept:
- case FcVStackDefault:
- expr = vstack->u.expr;
- vstack->tag = FcVStackNone;
- break;
- case FcVStackInteger:
- expr = FcExprCreateInteger (parse->config, vstack->u.integer);
- break;
- case FcVStackDouble:
- expr = FcExprCreateDouble (parse->config, vstack->u._double);
- break;
- case FcVStackMatrix:
- expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
- break;
- case FcVStackRange:
- break;
- case FcVStackBool:
- expr = FcExprCreateBool (parse->config, vstack->u.bool_);
- break;
- case FcVStackCharSet:
- expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
- break;
- case FcVStackLangSet:
- expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
- break;
- case FcVStackTest:
- break;
- case FcVStackExpr:
- expr = vstack->u.expr;
- vstack->tag = FcVStackNone;
- break;
- case FcVStackEdit:
- break;
- default:
- break;
- }
- FcVStackPopAndDestroy (parse);
- return expr;
-}
-
-/*
- * This builds a tree of binary operations. Note
- * that every operator is defined so that if only
- * a single operand is contained, the value of the
- * whole expression is the value of the operand.
- *
- * This code reduces in that case to returning that
- * operand.
- */
-static FcExpr *
-FcPopBinary (FcConfigParse *parse, FcOp op)
-{
- FcExpr *left, *expr = 0, *new;
-
- while ((left = FcPopExpr (parse)))
- {
- if (expr)
- {
- new = FcExprCreateOp (parse->config, left, op, expr);
- if (!new)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- FcExprDestroy (left);
- FcExprDestroy (expr);
- return 0;
- }
- expr = new;
- }
- else
- expr = left;
- }
- return expr;
-}
-
-static void
-FcParseBinary (FcConfigParse *parse, FcOp op)
-{
- FcExpr *expr = FcPopBinary (parse, op);
- if (expr)
- FcVStackPushExpr (parse, FcVStackExpr, expr);
-}
-
-/*
- * This builds a a unary operator, it consumes only
- * a single operand
- */
-
-static FcExpr *
-FcPopUnary (FcConfigParse *parse, FcOp op)
-{
- FcExpr *operand, *new = 0;
-
- if ((operand = FcPopExpr (parse)))
- {
- new = FcExprCreateOp (parse->config, operand, op, 0);
- if (!new)
- {
- FcExprDestroy (operand);
- FcConfigMessage (parse, FcSevereError, "out of memory");
- }
- }
- return new;
-}
-
-static void
-FcParseUnary (FcConfigParse *parse, FcOp op)
-{
- FcExpr *expr = FcPopUnary (parse, op);
- if (expr)
- FcVStackPushExpr (parse, FcVStackExpr, expr);
-}
-
-static void
-FcParseInclude (FcConfigParse *parse)
-{
- FcChar8 *s;
- const FcChar8 *i;
- FcBool ignore_missing = FcFalse;
-
- s = FcStrBufDoneStatic (&parse->pstack->str);
- if (!s)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- i = FcConfigGetAttribute (parse, "ignore_missing");
- if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
- ignore_missing = FcTrue;
- if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
- parse->error = FcTrue;
- FcStrBufDestroy (&parse->pstack->str);
-}
-
-typedef struct _FcOpMap {
- char name[16];
- FcOp op;
-} FcOpMap;
-
-static FcOp
-FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
-{
- int i;
-
- for (i = 0; i < nmap; i++)
- if (!strcmp ((char *) op, map[i].name))
- return map[i].op;
- return FcOpInvalid;
-}
-
-static const FcOpMap fcCompareOps[] = {
- { "eq", FcOpEqual },
- { "not_eq", FcOpNotEqual },
- { "less", FcOpLess },
- { "less_eq", FcOpLessEqual },
- { "more", FcOpMore },
- { "more_eq", FcOpMoreEqual },
- { "contains", FcOpContains },
- { "not_contains", FcOpNotContains }
-};
-
-#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
-
-static FcOp
-FcConfigLexCompare (const FcChar8 *compare)
-{
- return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
-}
-
-static void
-FcParseTest (FcConfigParse *parse)
-{
- const FcChar8 *kind_string;
- FcMatchKind kind;
- const FcChar8 *qual_string;
- FcQual qual;
- const FcChar8 *name;
- const FcChar8 *compare_string;
- FcOp compare;
- FcExpr *expr;
- FcTest *test;
-
- kind_string = FcConfigGetAttribute (parse, "target");
- if (!kind_string)
- kind = FcMatchDefault;
- else
- {
- if (!strcmp ((char *) kind_string, "pattern"))
- kind = FcMatchPattern;
- else if (!strcmp ((char *) kind_string, "font"))
- kind = FcMatchFont;
- else if (!strcmp ((char *) kind_string, "scan"))
- kind = FcMatchScan;
- else if (!strcmp ((char *) kind_string, "default"))
- kind = FcMatchDefault;
- else
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
- return;
- }
- }
- qual_string = FcConfigGetAttribute (parse, "qual");
- if (!qual_string)
- qual = FcQualAny;
- else
- {
- if (!strcmp ((char *) qual_string, "any"))
- qual = FcQualAny;
- else if (!strcmp ((char *) qual_string, "all"))
- qual = FcQualAll;
- else if (!strcmp ((char *) qual_string, "first"))
- qual = FcQualFirst;
- else if (!strcmp ((char *) qual_string, "not_first"))
- qual = FcQualNotFirst;
- else
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
- return;
- }
- }
- name = FcConfigGetAttribute (parse, "name");
- if (!name)
- {
- FcConfigMessage (parse, FcSevereWarning, "missing test name");
- return;
- }
- compare_string = FcConfigGetAttribute (parse, "compare");
- if (!compare_string)
- compare = FcOpEqual;
- else
- {
- compare = FcConfigLexCompare (compare_string);
- if (compare == FcOpInvalid)
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
- return;
- }
- }
- expr = FcPopBinary (parse, FcOpComma);
- if (!expr)
- {
- FcConfigMessage (parse, FcSevereWarning, "missing test expression");
- return;
- }
- test = FcTestCreate (parse, kind, qual, name, compare, expr);
- if (!test)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
- FcVStackPushTest (parse, test);
-}
-
-static const FcOpMap fcModeOps[] = {
- { "assign", FcOpAssign },
- { "assign_replace", FcOpAssignReplace },
- { "prepend", FcOpPrepend },
- { "prepend_first", FcOpPrependFirst },
- { "append", FcOpAppend },
- { "append_last", FcOpAppendLast },
-};
-
-#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
-
-static FcOp
-FcConfigLexMode (const FcChar8 *mode)
-{
- return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
-}
-
-static void
-FcParseEdit (FcConfigParse *parse)
-{
- const FcChar8 *name;
- const FcChar8 *mode_string;
- FcOp mode;
- FcValueBinding binding;
- FcExpr *expr;
- FcEdit *edit;
-
- name = FcConfigGetAttribute (parse, "name");
- if (!name)
- {
- FcConfigMessage (parse, FcSevereWarning, "missing edit name");
- return;
- }
- mode_string = FcConfigGetAttribute (parse, "mode");
- if (!mode_string)
- mode = FcOpAssign;
- else
- {
- mode = FcConfigLexMode (mode_string);
- if (mode == FcOpInvalid)
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
- return;
- }
- }
- if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
- return;
-
- expr = FcPopBinary (parse, FcOpComma);
- edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
- mode, expr, binding);
- if (!edit)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- FcExprDestroy (expr);
- return;
- }
- if (!FcVStackPushEdit (parse, edit))
- FcEditDestroy (edit);
-}
-
-static void
-FcParseMatch (FcConfigParse *parse)
-{
- const FcChar8 *kind_name;
- FcMatchKind kind;
- FcTest *test = 0;
- FcEdit *edit = 0;
- FcVStack *vstack;
-
- kind_name = FcConfigGetAttribute (parse, "target");
- if (!kind_name)
- kind = FcMatchPattern;
- else
- {
- if (!strcmp ((char *) kind_name, "pattern"))
- kind = FcMatchPattern;
- else if (!strcmp ((char *) kind_name, "font"))
- kind = FcMatchFont;
- else if (!strcmp ((char *) kind_name, "scan"))
- kind = FcMatchScan;
- else
- {
- FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
- return;
- }
- }
- while ((vstack = FcVStackPeek (parse)))
- {
- switch (vstack->tag) {
- case FcVStackTest:
- vstack->u.test->next = test;
- test = vstack->u.test;
- vstack->tag = FcVStackNone;
- break;
- case FcVStackEdit:
- vstack->u.edit->next = edit;
- edit = vstack->u.edit;
- vstack->tag = FcVStackNone;
- if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
- {
- FcConfigMessage (parse, FcSevereError,
- "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
- FcObjectName(edit->object));
- }
- break;
- default:
- FcConfigMessage (parse, FcSevereWarning, "invalid match element");
- break;
- }
- FcVStackPopAndDestroy (parse);
- }
- if (!FcConfigAddEdit (parse->config, test, edit, kind))
- FcConfigMessage (parse, FcSevereError, "out of memory");
-}
-
-static void
-FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
-{
- FcVStack *vstack;
-
- while ((vstack = FcVStackPeek (parse)))
- {
- switch (vstack->tag) {
- case FcVStackGlob:
- if (!FcConfigGlobAdd (parse->config,
- vstack->u.string,
- element == FcElementAcceptfont))
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- }
- break;
- case FcVStackPattern:
- if (!FcConfigPatternsAdd (parse->config,
- vstack->u.pattern,
- element == FcElementAcceptfont))
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- }
- else
- vstack->tag = FcVStackNone;
- break;
- default:
- FcConfigMessage (parse, FcSevereWarning, "bad font selector");
- break;
- }
- FcVStackPopAndDestroy (parse);
- }
-}
-
-
-static FcValue
-FcPopValue (FcConfigParse *parse)
-{
- FcVStack *vstack = FcVStackPeek (parse);
- FcValue value;
-
- value.type = FcTypeVoid;
-
- if (!vstack)
- return value;
-
- switch (vstack->tag) {
- case FcVStackString:
- value.u.s = FcStrStaticName (vstack->u.string);
- if (value.u.s)
- value.type = FcTypeString;
- break;
- case FcVStackConstant:
- if (FcNameConstant (vstack->u.string, &value.u.i))
- value.type = FcTypeInteger;
- break;
- case FcVStackInteger:
- value.u.i = vstack->u.integer;
- value.type = FcTypeInteger;
- break;
- case FcVStackDouble:
- value.u.d = vstack->u._double;
- value.type = FcTypeInteger;
- break;
- case FcVStackMatrix:
- value.u.m = FcMatrixCopy (vstack->u.matrix);
- if (value.u.m)
- value.type = FcTypeMatrix;
- break;
- case FcVStackBool:
- value.u.b = vstack->u.bool_;
- value.type = FcTypeBool;
- break;
- case FcVStackCharSet:
- value.u.c = FcCharSetCopy (vstack->u.charset);
- if (value.u.c)
- value.type = FcTypeCharSet;
- break;
- case FcVStackLangSet:
- value.u.l = FcLangSetCopy (vstack->u.langset);
- if (value.u.l)
- value.type = FcTypeLangSet;
- break;
- default:
- FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
- vstack->tag);
- break;
- }
- FcVStackPopAndDestroy (parse);
-
- return value;
-}
-
-static void
-FcParsePatelt (FcConfigParse *parse)
-{
- FcValue value;
- FcPattern *pattern = FcPatternCreate ();
- const char *name;
-
- if (!pattern)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
-
- name = (char *) FcConfigGetAttribute (parse, "name");
- if (!name)
- {
- FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
- FcPatternDestroy (pattern);
- return;
- }
-
- for (;;)
- {
- value = FcPopValue (parse);
- if (value.type == FcTypeVoid)
- break;
- if (!FcPatternAdd (pattern, name, value, FcTrue))
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- FcValueDestroy(value);
- break;
- }
- FcValueDestroy(value);
- }
-
- FcVStackPushPattern (parse, pattern);
-}
-
-static void
-FcParsePattern (FcConfigParse *parse)
-{
- FcVStack *vstack;
- FcPattern *pattern = FcPatternCreate ();
-
- if (!pattern)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- return;
- }
-
- while ((vstack = FcVStackPeek (parse)))
- {
- switch (vstack->tag) {
- case FcVStackPattern:
- if (!FcPatternAppend (pattern, vstack->u.pattern))
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- FcPatternDestroy (pattern);
- return;
- }
- break;
- default:
- FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
- break;
- }
- FcVStackPopAndDestroy (parse);
- }
-
- FcVStackPushPattern (parse, pattern);
-}
-
-static void
-FcEndElement(void *userData, const XML_Char *name)
-{
- FcConfigParse *parse = userData;
- FcChar8 *data;
-#ifdef _WIN32
- FcChar8 buffer[1000];
-#endif
-
- if (!parse->pstack)
- return;
- switch (parse->pstack->element) {
- case FcElementNone:
- break;
- case FcElementFontconfig:
- break;
- case FcElementDir:
- data = FcStrBufDoneStatic (&parse->pstack->str);
- if (!data)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- break;
- }
-#ifdef _WIN32
- if (strcmp (data, "CUSTOMFONTDIR") == 0)
- {
- char *p;
- data = buffer;
- if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
- {
- FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
- break;
- }
- /*
- * Must use the multi-byte aware function to search
- * for backslash because East Asian double-byte code
- * pages have characters with backslash as the second
- * byte.
- */
- p = _mbsrchr (data, '\\');
- if (p) *p = '\0';
- strcat (data, "\\fonts");
- }
- else if (strcmp (data, "APPSHAREFONTDIR") == 0)
- {
- char *p;
- data = buffer;
- if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
- {
- FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
- break;
- }
- p = _mbsrchr (data, '\\');
- if (p) *p = '\0';
- strcat (data, "\\..\\share\\fonts");
- }
- else if (strcmp (data, "WINDOWSFONTDIR") == 0)
- {
- int rc;
- data = buffer;
-#if _WIN32_WINNT >= 0x0500
- rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20);
-#else
- rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20);
-#endif
- if (rc == 0 || rc > sizeof (buffer) - 20)
- {
- FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
- break;
- }
- if (data [strlen (data) - 1] != '\\')
- strcat (data, "\\");
- strcat (data, "fonts");
- }
-#endif
- if (strlen ((char *) data) == 0)
- FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
- else if (!FcStrUsesHome (data) || FcConfigHome ())
- {
- if (!FcConfigAddDir (parse->config, data))
- FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
- }
- FcStrBufDestroy (&parse->pstack->str);
- break;
- case FcElementCacheDir:
- data = FcStrBufDone (&parse->pstack->str);
- if (!data)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- break;
- }
-#ifdef _WIN32
- if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
- {
- int rc;
- FcStrFree (data);
- data = malloc (1000);
- if (!data)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- break;
- }
- FcMemAlloc (FC_MEM_STRING, 1000);
- rc = GetTempPath (800, data);
- if (rc == 0 || rc > 800)
- {
- FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
- FcStrFree (data);
- break;
- }
- if (data [strlen (data) - 1] != '\\')
- strcat (data, "\\");
- strcat (data, "fontconfig\\cache");
- }
-#endif
- if (!FcStrUsesHome (data) || FcConfigHome ())
- {
- if (!FcConfigAddCacheDir (parse->config, data))
- FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
- }
- FcStrFree (data);
- break;
-
- case FcElementCache:
- data = FcStrBufDoneStatic (&parse->pstack->str);
- if (!data)
- {
- FcConfigMessage (parse, FcSevereError, "out of memory");
- break;
- }
- /* discard this data; no longer used */
- FcStrBufDestroy (&parse->pstack->str);
- break;
- case FcElementInclude:
- FcParseInclude (parse);
- break;
- case FcElementConfig:
- break;
- case FcElementMatch:
- FcParseMatch (parse);
- break;
- case FcElementAlias:
- FcParseAlias (parse);
- break;
-
- case FcElementBlank:
- FcParseBlank (parse);
- break;
- case FcElementRescan:
- FcParseRescan (parse);
- break;
-
- case FcElementPrefer:
- FcParseFamilies (parse, FcVStackPrefer);
- break;
- case FcElementAccept:
- FcParseFamilies (parse, FcVStackAccept);
- break;
- case FcElementDefault:
- FcParseFamilies (parse, FcVStackDefault);
- break;
- case FcElementFamily:
- FcParseFamily (parse);
- break;
-
- case FcElementTest:
- FcParseTest (parse);
- break;
- case FcElementEdit:
- FcParseEdit (parse);
- break;
-
- case FcElementInt:
- FcParseInt (parse);
- break;
- case FcElementDouble:
- FcParseDouble (parse);
- break;
- case FcElementString:
- FcParseString (parse, FcVStackString);
- break;
- case FcElementMatrix:
- FcParseMatrix (parse);
- break;
- case FcElementRange:
- FcParseRange (parse);
- break;
- case FcElementBool:
- FcParseBool (parse);
- break;
- case FcElementCharSet:
- FcParseCharSet (parse);
- break;
- case FcElementLangSet:
- FcParseLangSet (parse);
- break;
- case FcElementSelectfont:
- break;
- case FcElementAcceptfont:
- case FcElementRejectfont:
- FcParseAcceptRejectFont (parse, parse->pstack->element);
- break;
- case FcElementGlob:
- FcParseString (parse, FcVStackGlob);
- break;
- case FcElementPattern:
- FcParsePattern (parse);
- break;
- case FcElementPatelt:
- FcParsePatelt (parse);
- break;
- case FcElementName:
- FcParseString (parse, FcVStackField);
- break;
- case FcElementConst:
- FcParseString (parse, FcVStackConstant);
- break;
- case FcElementOr:
- FcParseBinary (parse, FcOpOr);
- break;
- case FcElementAnd:
- FcParseBinary (parse, FcOpAnd);
- break;
- case FcElementEq:
- FcParseBinary (parse, FcOpEqual);
- break;
- case FcElementNotEq:
- FcParseBinary (parse, FcOpNotEqual);
- break;
- case FcElementLess:
- FcParseBinary (parse, FcOpLess);
- break;
- case FcElementLessEq:
- FcParseBinary (parse, FcOpLessEqual);
- break;
- case FcElementMore:
- FcParseBinary (parse, FcOpMore);
- break;
- case FcElementMoreEq:
- FcParseBinary (parse, FcOpMoreEqual);
- break;
- case FcElementContains:
- FcParseBinary (parse, FcOpContains);
- break;
- case FcElementNotContains:
- FcParseBinary (parse, FcOpNotContains);
- break;
- case FcElementPlus:
- FcParseBinary (parse, FcOpPlus);
- break;
- case FcElementMinus:
- FcParseBinary (parse, FcOpMinus);
- break;
- case FcElementTimes:
- FcParseBinary (parse, FcOpTimes);
- break;
- case FcElementDivide:
- FcParseBinary (parse, FcOpDivide);
- break;
- case FcElementNot:
- FcParseUnary (parse, FcOpNot);
- break;
- case FcElementIf:
- FcParseBinary (parse, FcOpQuest);
- break;
- case FcElementFloor:
- FcParseUnary (parse, FcOpFloor);
- break;
- case FcElementCeil:
- FcParseUnary (parse, FcOpCeil);
- break;
- case FcElementRound:
- FcParseUnary (parse, FcOpRound);
- break;
- case FcElementTrunc:
- FcParseUnary (parse, FcOpTrunc);
- break;
- case FcElementUnknown:
- break;
- }
- (void) FcPStackPop (parse);
-}
-
-static void
-FcCharacterData (void *userData, const XML_Char *s, int len)
-{
- FcConfigParse *parse = userData;
-
- if (!parse->pstack)
- return;
- if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
- FcConfigMessage (parse, FcSevereError, "out of memory");
-}
-
-static void
-FcStartDoctypeDecl (void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid,
- int has_internal_subset)
-{
- FcConfigParse *parse = userData;
-
- if (strcmp ((char *) doctypeName, "fontconfig") != 0)
- FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
-}
-
-#ifdef ENABLE_LIBXML2
-
-static void
-FcInternalSubsetDecl (void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid)
-{
- FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
-}
-
-static void
-FcExternalSubsetDecl (void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid)
-{
- FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
-}
-
-#else /* ENABLE_LIBXML2 */
-
-static void
-FcEndDoctypeDecl (void *userData)
-{
-}
-
-#endif /* ENABLE_LIBXML2 */
-
-static int
-FcSortCmpStr (const void *a, const void *b)
-{
- const FcChar8 *as = *((FcChar8 **) a);
- const FcChar8 *bs = *((FcChar8 **) b);
- return FcStrCmp (as, bs);
-}
-
-static FcBool
-FcConfigParseAndLoadDir (FcConfig *config,
- const FcChar8 *name,
- const FcChar8 *dir,
- FcBool complain)
-{
- DIR *d;
- struct dirent *e;
- FcBool ret = FcTrue;
- FcChar8 *file;
- FcChar8 *base;
- FcStrSet *files;
-
- d = opendir ((char *) dir);
- if (!d)
- {
- if (complain)
- FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
- name);
- ret = FcFalse;
- goto bail0;
- }
- /* freed below */
- file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
- if (!file)
- {
- ret = FcFalse;
- goto bail1;
- }
-
- strcpy ((char *) file, (char *) dir);
- strcat ((char *) file, "/");
- base = file + strlen ((char *) file);
-
- files = FcStrSetCreate ();
- if (!files)
- {
- ret = FcFalse;
- goto bail2;
- }
-
- if (FcDebug () & FC_DBG_CONFIG)
- printf ("\tScanning config dir %s\n", dir);
-
- while (ret && (e = readdir (d)))
- {
- int d_len;
-#define TAIL ".conf"
-#define TAIL_LEN 5
- /*
- * Add all files of the form [0-9]*.conf
- */
- if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
- (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
- d_len > TAIL_LEN &&
- strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
- {
- strcpy ((char *) base, (char *) e->d_name);
- if (!FcStrSetAdd (files, file))
- {
- ret = FcFalse;
- goto bail3;
- }
- }
- }
- if (ret)
- {
- int i;
- qsort (files->strs, files->num, sizeof (FcChar8 *),
- (int (*)(const void *, const void *)) FcSortCmpStr);
- for (i = 0; ret && i < files->num; i++)
- ret = FcConfigParseAndLoad (config, files->strs[i], complain);
- }
-bail3:
- FcStrSetDestroy (files);
-bail2:
- free (file);
-bail1:
- closedir (d);
-bail0:
- return ret || !complain;
-}
-
-FcBool
-FcConfigParseAndLoad (FcConfig *config,
- const FcChar8 *name,
- FcBool complain)
-{
-
- XML_Parser p;
- FcChar8 *filename;
- int fd;
- int len;
- FcConfigParse parse;
- FcBool error = FcTrue;
-
-#ifdef ENABLE_LIBXML2
- xmlSAXHandler sax;
- char buf[BUFSIZ];
-#else
- void *buf;
-#endif
-
- filename = FcConfigFilename (name);
- if (!filename)
- goto bail0;
-
- if (FcStrSetMember (config->configFiles, filename))
- {
- FcStrFree (filename);
- return FcTrue;
- }
-
- if (!FcStrSetAdd (config->configFiles, filename))
- {
- FcStrFree (filename);
- goto bail0;
- }
-
- if (FcFileIsDir (filename))
- {
- FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
- FcStrFree (filename);
- return ret;
- }
-
- if (FcDebug () & FC_DBG_CONFIG)
- printf ("\tLoading config file %s\n", filename);
-
- fd = open ((char *) filename, O_RDONLY);
- if (fd == -1) {
- FcStrFree (filename);
- goto bail0;
- }
-
-#ifdef ENABLE_LIBXML2
- memset(&sax, 0, sizeof(sax));
-
- sax.internalSubset = FcInternalSubsetDecl;
- sax.externalSubset = FcExternalSubsetDecl;
- sax.startElement = FcStartElement;
- sax.endElement = FcEndElement;
- sax.characters = FcCharacterData;
-
- p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
-#else
- p = XML_ParserCreate ("UTF-8");
-#endif
- FcStrFree (filename);
-
- if (!p)
- goto bail1;
-
- if (!FcConfigInit (&parse, name, config, p))
- goto bail2;
-
-#ifndef ENABLE_LIBXML2
-
- XML_SetUserData (p, &parse);
-
- XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
- XML_SetElementHandler (p, FcStartElement, FcEndElement);
- XML_SetCharacterDataHandler (p, FcCharacterData);
-
-#endif /* ENABLE_LIBXML2 */
-
- do {
-#ifndef ENABLE_LIBXML2
- buf = XML_GetBuffer (p, BUFSIZ);
- if (!buf)
- {
- FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
- goto bail3;
- }
-#endif
- len = read (fd, buf, BUFSIZ);
- if (len < 0)
- {
- FcConfigMessage (&parse, FcSevereError, "failed reading config file");
- goto bail3;
- }
-
-#ifdef ENABLE_LIBXML2
- if (xmlParseChunk (p, buf, len, len == 0))
-#else
- if (!XML_ParseBuffer (p, len, len == 0))
-#endif
- {
- FcConfigMessage (&parse, FcSevereError, "%s",
- XML_ErrorString (XML_GetErrorCode (p)));
- goto bail3;
- }
- } while (len != 0);
- error = parse.error;
-bail3:
- FcConfigCleanup (&parse);
-bail2:
- XML_ParserFree (p);
-bail1:
- close (fd);
- fd = -1;
-bail0:
- if (error && complain)
- {
- if (name)
- FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
- else
- FcConfigMessage (0, FcSevereError, "Cannot load default config file");
- return FcFalse;
- }
- return FcTrue;
-}
-#define __fcxml__
-#include "fcaliastail.h"
-#undef __fcxml__
+/* + * fontconfig/src/fcxml.c + * + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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" +#include <fcntl.h> +#include <stdarg.h> +#include <dirent.h> + +#ifdef ENABLE_LIBXML2 + +#include <libxml/parser.h> + +#define XML_Char xmlChar +#define XML_Parser xmlParserCtxtPtr +#define XML_ParserFree xmlFreeParserCtxt +#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber +#define XML_GetErrorCode xmlCtxtGetLastError +#define XML_ErrorString(Error) (Error)->message + +#else /* ENABLE_LIBXML2 */ + +#ifndef HAVE_XMLPARSE_H +#define HAVE_XMLPARSE_H 0 +#endif + +#if HAVE_XMLPARSE_H +#include <xmlparse.h> +#else +#include <expat.h> +#endif + +#endif /* ENABLE_LIBXML2 */ + +#ifdef _WIN32 +#include <mbstring.h> +#endif + +static void +FcExprDestroy (FcExpr *e); + +void +FcTestDestroy (FcTest *test) +{ + if (test->next) + FcTestDestroy (test->next); + FcExprDestroy (test->expr); + FcMemFree (FC_MEM_TEST, sizeof (FcTest)); + free (test); +} + +static FcExpr * +FcExprCreateInteger (FcConfig *config, int i) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpInteger; + e->u.ival = i; + } + return e; +} + +static FcExpr * +FcExprCreateDouble (FcConfig *config, double d) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpDouble; + e->u.dval = d; + } + return e; +} + +static FcExpr * +FcExprCreateString (FcConfig *config, const FcChar8 *s) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpString; + e->u.sval = FcStrStaticName (s); + } + return e; +} + +static FcExpr * +FcExprCreateMatrix (FcConfig *config, const FcMatrix *m) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpMatrix; + e->u.mval = FcMatrixCopy (m); + } + return e; +} + +static FcExpr * +FcExprCreateBool (FcConfig *config, FcBool b) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpBool; + e->u.bval = b; + } + return e; +} + +static FcExpr * +FcExprCreateCharSet (FcConfig *config, FcCharSet *charset) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpCharSet; + e->u.cval = FcCharSetCopy (charset); + } + return e; +} + +static FcExpr * +FcExprCreateLangSet (FcConfig *config, FcLangSet *langset) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpLangSet; + e->u.lval = FcLangSetCopy (langset); + } + return e; +} + +static FcExpr * +FcExprCreateField (FcConfig *config, const char *field) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpField; + e->u.object = FcObjectFromName (field); + } + return e; +} + +static FcExpr * +FcExprCreateConst (FcConfig *config, const FcChar8 *constant) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpConst; + e->u.constant = FcStrStaticName (constant); + } + return e; +} + +static FcExpr * +FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = op; + e->u.tree.left = left; + e->u.tree.right = right; + } + return e; +} + +static void +FcExprDestroy (FcExpr *e) +{ + if (!e) + return; + switch (e->op) { + case FcOpInteger: + break; + case FcOpDouble: + break; + case FcOpString: + break; + case FcOpMatrix: + FcMatrixFree (e->u.mval); + break; + case FcOpRange: + break; + case FcOpCharSet: + FcCharSetDestroy (e->u.cval); + break; + case FcOpLangSet: + FcLangSetDestroy (e->u.lval); + break; + case FcOpBool: + break; + case FcOpField: + break; + case FcOpConst: + break; + case FcOpAssign: + case FcOpAssignReplace: + case FcOpPrepend: + case FcOpPrependFirst: + case FcOpAppend: + case FcOpAppendLast: + break; + case FcOpOr: + case FcOpAnd: + case FcOpEqual: + case FcOpNotEqual: + case FcOpLess: + case FcOpLessEqual: + case FcOpMore: + case FcOpMoreEqual: + case FcOpContains: + case FcOpListing: + case FcOpNotContains: + case FcOpPlus: + case FcOpMinus: + case FcOpTimes: + case FcOpDivide: + case FcOpQuest: + case FcOpComma: + FcExprDestroy (e->u.tree.right); + /* fall through */ + case FcOpNot: + case FcOpFloor: + case FcOpCeil: + case FcOpRound: + case FcOpTrunc: + FcExprDestroy (e->u.tree.left); + break; + case FcOpNil: + case FcOpInvalid: + break; + } + + e->op = FcOpNil; +} + +void +FcEditDestroy (FcEdit *e) +{ + if (e->next) + FcEditDestroy (e->next); + if (e->expr) + FcExprDestroy (e->expr); + free (e); +} + +typedef enum _FcElement { + FcElementNone, + FcElementFontconfig, + FcElementDir, + FcElementCacheDir, + FcElementCache, + FcElementInclude, + FcElementConfig, + FcElementMatch, + FcElementAlias, + + FcElementBlank, + FcElementRescan, + + FcElementPrefer, + FcElementAccept, + FcElementDefault, + FcElementFamily, + + FcElementSelectfont, + FcElementAcceptfont, + FcElementRejectfont, + FcElementGlob, + FcElementPattern, + FcElementPatelt, + + FcElementTest, + FcElementEdit, + FcElementInt, + FcElementDouble, + FcElementString, + FcElementMatrix, + FcElementRange, + FcElementBool, + FcElementCharSet, + FcElementLangSet, + FcElementName, + FcElementConst, + FcElementOr, + FcElementAnd, + FcElementEq, + FcElementNotEq, + FcElementLess, + FcElementLessEq, + FcElementMore, + FcElementMoreEq, + FcElementContains, + FcElementNotContains, + FcElementPlus, + FcElementMinus, + FcElementTimes, + FcElementDivide, + FcElementNot, + FcElementIf, + FcElementFloor, + FcElementCeil, + FcElementRound, + FcElementTrunc, + FcElementUnknown +} FcElement; + +static const struct { + const char name[16]; + FcElement element; +} fcElementMap[] = { + { "fontconfig", FcElementFontconfig }, + { "dir", FcElementDir }, + { "cachedir", FcElementCacheDir }, + { "cache", FcElementCache }, + { "include", FcElementInclude }, + { "config", FcElementConfig }, + { "match", FcElementMatch }, + { "alias", FcElementAlias }, + + { "blank", FcElementBlank }, + { "rescan", FcElementRescan }, + + { "prefer", FcElementPrefer }, + { "accept", FcElementAccept }, + { "default", FcElementDefault }, + { "family", FcElementFamily }, + + { "selectfont", FcElementSelectfont }, + { "acceptfont", FcElementAcceptfont }, + { "rejectfont", FcElementRejectfont }, + { "glob", FcElementGlob }, + { "pattern", FcElementPattern }, + { "patelt", FcElementPatelt }, + + { "test", FcElementTest }, + { "edit", FcElementEdit }, + { "int", FcElementInt }, + { "double", FcElementDouble }, + { "string", FcElementString }, + { "matrix", FcElementMatrix }, + { "range", FcElementRange }, + { "bool", FcElementBool }, + { "charset", FcElementCharSet }, + { "langset", FcElementLangSet }, + { "name", FcElementName }, + { "const", FcElementConst }, + { "or", FcElementOr }, + { "and", FcElementAnd }, + { "eq", FcElementEq }, + { "not_eq", FcElementNotEq }, + { "less", FcElementLess }, + { "less_eq", FcElementLessEq }, + { "more", FcElementMore }, + { "more_eq", FcElementMoreEq }, + { "contains", FcElementContains }, + { "not_contains", FcElementNotContains }, + { "plus", FcElementPlus }, + { "minus", FcElementMinus }, + { "times", FcElementTimes }, + { "divide", FcElementDivide }, + { "not", FcElementNot }, + { "if", FcElementIf }, + { "floor", FcElementFloor }, + { "ceil", FcElementCeil }, + { "round", FcElementRound }, + { "trunc", FcElementTrunc }, +}; +#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0]) + +static FcElement +FcElementMap (const XML_Char *name) +{ + + int i; + for (i = 0; i < NUM_ELEMENT_MAPS; i++) + if (!strcmp ((char *) name, fcElementMap[i].name)) + return fcElementMap[i].element; + return FcElementUnknown; +} + +typedef struct _FcPStack { + struct _FcPStack *prev; + FcElement element; + FcChar8 **attr; + FcStrBuf str; + FcChar8 *attr_buf_static[16]; +} FcPStack; + +typedef enum _FcVStackTag { + FcVStackNone, + + FcVStackString, + FcVStackFamily, + FcVStackField, + FcVStackConstant, + FcVStackGlob, + FcVStackPattern, + + FcVStackPrefer, + FcVStackAccept, + FcVStackDefault, + + FcVStackInteger, + FcVStackDouble, + FcVStackMatrix, + FcVStackRange, + FcVStackBool, + FcVStackCharSet, + FcVStackLangSet, + + FcVStackTest, + FcVStackExpr, + FcVStackEdit +} FcVStackTag; + +typedef struct _FcVStack { + struct _FcVStack *prev; + FcPStack *pstack; /* related parse element */ + FcVStackTag tag; + union { + FcChar8 *string; + + int integer; + double _double; + FcMatrix *matrix; + FcRange range; + FcBool bool_; + FcCharSet *charset; + FcLangSet *langset; + + FcTest *test; + FcQual qual; + FcOp op; + FcExpr *expr; + FcEdit *edit; + + FcPattern *pattern; + } u; +} FcVStack; + +typedef struct _FcConfigParse { + FcPStack *pstack; + FcVStack *vstack; + FcBool error; + const FcChar8 *name; + FcConfig *config; + XML_Parser parser; + int pstack_static_used; + FcPStack pstack_static[8]; + int vstack_static_used; + FcVStack vstack_static[64]; +} FcConfigParse; + +typedef enum _FcConfigSeverity { + FcSevereInfo, FcSevereWarning, FcSevereError +} FcConfigSeverity; + +static void +FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...) +{ + const char *s = "unknown"; + va_list args; + + va_start (args, fmt); + + switch (severe) { + case FcSevereInfo: s = "info"; break; + case FcSevereWarning: s = "warning"; break; + case FcSevereError: s = "error"; break; + } + if (parse) + { + if (parse->name) + fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s, + parse->name, (int)XML_GetCurrentLineNumber (parse->parser)); + else + fprintf (stderr, "Fontconfig %s: line %d: ", s, + (int)XML_GetCurrentLineNumber (parse->parser)); + if (severe >= FcSevereError) + parse->error = FcTrue; + } + else + fprintf (stderr, "Fontconfig %s: ", s); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); +} + + +static const char * +FcTypeName (FcType type) +{ + switch (type) { + case FcTypeVoid: + return "void"; + case FcTypeInteger: + case FcTypeDouble: + return "number"; + case FcTypeString: + return "string"; + case FcTypeBool: + return "bool"; + case FcTypeMatrix: + return "matrix"; + case FcTypeCharSet: + return "charset"; + case FcTypeFTFace: + return "FT_Face"; + case FcTypeLangSet: + return "langset"; + default: + return "unknown"; + } +} + +static void +FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type) +{ + if (value == FcTypeInteger) + value = FcTypeDouble; + if (type == FcTypeInteger) + type = FcTypeDouble; + if (value != type) + { + if ((value == FcTypeLangSet && type == FcTypeString) || + (value == FcTypeString && type == FcTypeLangSet)) + return; + if (type == (FcType) -1) + return; + FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s", + FcTypeName (value), FcTypeName (type)); + } +} + +static void +FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type) +{ + const FcObjectType *o; + const FcConstant *c; + + /* If parsing the expression failed, some nodes may be NULL */ + if (!expr) + return; + + switch (expr->op) { + case FcOpInteger: + case FcOpDouble: + FcTypecheckValue (parse, FcTypeDouble, type); + break; + case FcOpString: + FcTypecheckValue (parse, FcTypeString, type); + break; + case FcOpMatrix: + FcTypecheckValue (parse, FcTypeMatrix, type); + break; + case FcOpBool: + FcTypecheckValue (parse, FcTypeBool, type); + break; + case FcOpCharSet: + FcTypecheckValue (parse, FcTypeCharSet, type); + break; + case FcOpLangSet: + FcTypecheckValue (parse, FcTypeLangSet, type); + break; + case FcOpNil: + break; + case FcOpField: + o = FcNameGetObjectType (FcObjectName (expr->u.object)); + if (o) + FcTypecheckValue (parse, o->type, type); + break; + case FcOpConst: + c = FcNameGetConstant (expr->u.constant); + if (c) + { + o = FcNameGetObjectType (c->object); + if (o) + FcTypecheckValue (parse, o->type, type); + } + else + FcConfigMessage (parse, FcSevereWarning, + "invalid constant used : %s", + expr->u.constant); + break; + case FcOpQuest: + FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); + FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type); + FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type); + break; + case FcOpAssign: + case FcOpAssignReplace: + break; + case FcOpEqual: + case FcOpNotEqual: + case FcOpLess: + case FcOpLessEqual: + case FcOpMore: + case FcOpMoreEqual: + case FcOpContains: + case FcOpNotContains: + case FcOpListing: + FcTypecheckValue (parse, FcTypeBool, type); + break; + case FcOpComma: + case FcOpOr: + case FcOpAnd: + case FcOpPlus: + case FcOpMinus: + case FcOpTimes: + case FcOpDivide: + FcTypecheckExpr (parse, expr->u.tree.left, type); + FcTypecheckExpr (parse, expr->u.tree.right, type); + break; + case FcOpNot: + FcTypecheckValue (parse, FcTypeBool, type); + FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); + break; + case FcOpFloor: + case FcOpCeil: + case FcOpRound: + case FcOpTrunc: + FcTypecheckValue (parse, FcTypeDouble, type); + FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble); + break; + default: + break; + } +} + +static FcTest * +FcTestCreate (FcConfigParse *parse, + FcMatchKind kind, + FcQual qual, + const FcChar8 *field, + FcOp compare, + FcExpr *expr) +{ + FcTest *test = (FcTest *) malloc (sizeof (FcTest)); + + if (test) + { + const FcObjectType *o; + + FcMemAlloc (FC_MEM_TEST, sizeof (FcTest)); + test->next = 0; + test->kind = kind; + test->qual = qual; + test->object = FcObjectFromName ((const char *) field); + test->op = compare; + test->expr = expr; + o = FcNameGetObjectType (FcObjectName (test->object)); + if (o) + FcTypecheckExpr (parse, expr, o->type); + } + return test; +} + +static FcEdit * +FcEditCreate (FcConfigParse *parse, + FcObject object, + FcOp op, + FcExpr *expr, + FcValueBinding binding) +{ + FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); + + if (e) + { + const FcObjectType *o; + + e->next = 0; + e->object = object; + e->op = op; + e->expr = expr; + e->binding = binding; + o = FcNameGetObjectType (FcObjectName (e->object)); + if (o) + FcTypecheckExpr (parse, expr, o->type); + } + return e; +} + +static FcVStack * +FcVStackCreateAndPush (FcConfigParse *parse) +{ + FcVStack *new; + + if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0])) + new = &parse->vstack_static[parse->vstack_static_used++]; + else + { + new = malloc (sizeof (FcVStack)); + if (!new) + return 0; + FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack)); + } + new->tag = FcVStackNone; + new->prev = 0; + + new->prev = parse->vstack; + new->pstack = parse->pstack ? parse->pstack->prev : 0; + parse->vstack = new; + + return new; +} + +static FcBool +FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.string = string; + vstack->tag = tag; + return FcTrue; +} + +static FcBool +FcVStackPushInteger (FcConfigParse *parse, int integer) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.integer = integer; + vstack->tag = FcVStackInteger; + return FcTrue; +} + +static FcBool +FcVStackPushDouble (FcConfigParse *parse, double _double) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u._double = _double; + vstack->tag = FcVStackDouble; + return FcTrue; +} + +static FcBool +FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix) +{ + FcVStack *vstack; + matrix = FcMatrixCopy (matrix); + if (!matrix) + return FcFalse; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.matrix = matrix; + vstack->tag = FcVStackMatrix; + return FcTrue; +} + +static FcBool +FcVStackPushRange (FcConfigParse *parse, FcRange *range) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.range.begin = range->begin; + vstack->u.range.end = range->end; + vstack->tag = FcVStackRange; + return FcTrue; +} + +static FcBool +FcVStackPushBool (FcConfigParse *parse, FcBool bool_) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.bool_ = bool_; + vstack->tag = FcVStackBool; + return FcTrue; +} + +static FcBool +FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset) +{ + FcVStack *vstack; + if (!charset) + return FcFalse; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.charset = charset; + vstack->tag = FcVStackCharSet; + return FcTrue; +} + +static FcBool +FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset) +{ + FcVStack *vstack; + if (!langset) + return FcFalse; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.langset = langset; + vstack->tag = FcVStackLangSet; + return FcTrue; +} + +static FcBool +FcVStackPushTest (FcConfigParse *parse, FcTest *test) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.test = test; + vstack->tag = FcVStackTest; + return FcTrue; +} + +static FcBool +FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.expr = expr; + vstack->tag = tag; + return FcTrue; +} + +static FcBool +FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.edit = edit; + vstack->tag = FcVStackEdit; + return FcTrue; +} + +static FcBool +FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.pattern = pattern; + vstack->tag = FcVStackPattern; + return FcTrue; +} + +static FcVStack * +FcVStackFetch (FcConfigParse *parse, int off) +{ + FcVStack *vstack; + + for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); + return vstack; +} + +static FcVStack * +FcVStackPeek (FcConfigParse *parse) +{ + FcVStack *vstack = parse->vstack; + + return vstack && vstack->pstack == parse->pstack ? vstack : 0; +} + +static void +FcVStackPopAndDestroy (FcConfigParse *parse) +{ + FcVStack *vstack = parse->vstack; + + if (!vstack || vstack->pstack != parse->pstack) + return; + + parse->vstack = vstack->prev; + + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackFamily: + break; + case FcVStackString: + case FcVStackField: + case FcVStackConstant: + case FcVStackGlob: + FcStrFree (vstack->u.string); + break; + case FcVStackPattern: + FcPatternDestroy (vstack->u.pattern); + break; + case FcVStackInteger: + case FcVStackDouble: + break; + case FcVStackMatrix: + FcMatrixFree (vstack->u.matrix); + break; + case FcVStackRange: + case FcVStackBool: + break; + case FcVStackCharSet: + FcCharSetDestroy (vstack->u.charset); + break; + case FcVStackLangSet: + FcLangSetDestroy (vstack->u.langset); + break; + case FcVStackTest: + FcTestDestroy (vstack->u.test); + break; + case FcVStackExpr: + case FcVStackPrefer: + case FcVStackAccept: + case FcVStackDefault: + FcExprDestroy (vstack->u.expr); + break; + case FcVStackEdit: + FcEditDestroy (vstack->u.edit); + break; + } + + if (vstack == &parse->vstack_static[parse->vstack_static_used - 1]) + parse->vstack_static_used--; + else + { + FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack)); + free (vstack); + } +} + +static void +FcVStackClear (FcConfigParse *parse) +{ + while (FcVStackPeek (parse)) + FcVStackPopAndDestroy (parse); +} + +static int +FcVStackElements (FcConfigParse *parse) +{ + int h = 0; + FcVStack *vstack = parse->vstack; + while (vstack && vstack->pstack == parse->pstack) + { + h++; + vstack = vstack->prev; + } + return h; +} + +static FcChar8 ** +FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes) +{ + int slen; + int i; + FcChar8 **new; + FcChar8 *s; + + if (!attr) + return 0; + slen = 0; + for (i = 0; attr[i]; i++) + slen += strlen ((char *) attr[i]) + 1; + if (i == 0) + return 0; + slen += (i + 1) * sizeof (FcChar8 *); + if (slen <= size_bytes) + new = buf; + else + { + new = malloc (slen); + if (!new) + { + FcConfigMessage (0, FcSevereError, "out of memory"); + return 0; + } + FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */ + } + s = (FcChar8 *) (new + (i + 1)); + for (i = 0; attr[i]; i++) + { + new[i] = s; + strcpy ((char *) s, (char *) attr[i]); + s += strlen ((char *) s) + 1; + } + new[i] = 0; + return new; +} + +static FcBool +FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) +{ + FcPStack *new; + + if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0])) + new = &parse->pstack_static[parse->pstack_static_used++]; + else + { + new = malloc (sizeof (FcPStack)); + if (!new) + return FcFalse; + FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack)); + } + + new->prev = parse->pstack; + new->element = element; + new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static)); + FcStrBufInit (&new->str, 0, 0); + parse->pstack = new; + return FcTrue; +} + +static FcBool +FcPStackPop (FcConfigParse *parse) +{ + FcPStack *old; + + if (!parse->pstack) + { + FcConfigMessage (parse, FcSevereError, "mismatching element"); + return FcFalse; + } + FcVStackClear (parse); + old = parse->pstack; + parse->pstack = old->prev; + FcStrBufDestroy (&old->str); + if (old->attr && old->attr != old->attr_buf_static) + { + FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */ + free (old->attr); + } + + if (old == &parse->pstack_static[parse->pstack_static_used - 1]) + parse->pstack_static_used--; + else + { + FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack)); + free (old); + } + return FcTrue; +} + +static FcBool +FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser) +{ + parse->pstack = 0; + parse->pstack_static_used = 0; + parse->vstack = 0; + parse->vstack_static_used = 0; + parse->error = FcFalse; + parse->name = name; + parse->config = config; + parse->parser = parser; + return FcTrue; +} + +static void +FcConfigCleanup (FcConfigParse *parse) +{ + while (parse->pstack) + FcPStackPop (parse); +} + +static const FcChar8 * +FcConfigGetAttribute (FcConfigParse *parse, const char *attr) +{ + FcChar8 **attrs; + if (!parse->pstack) + return 0; + + attrs = parse->pstack->attr; + if (!attrs) + return 0; + + while (*attrs) + { + if (!strcmp ((char *) *attrs, attr)) + return attrs[1]; + attrs += 2; + } + return 0; +} + +static void +FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) +{ + FcConfigParse *parse = userData; + FcElement element; + + element = FcElementMap (name); + if (element == FcElementUnknown) + FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name); + + if (!FcPStackPush (parse, element, attr)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + return; +} + +static void +FcParseBlank (FcConfigParse *parse) +{ + int n = FcVStackElements (parse); + FcChar32 i; + while (n-- > 0) + { + FcVStack *v = FcVStackFetch (parse, n); + if (!parse->config->blanks) + { + parse->config->blanks = FcBlanksCreate (); + if (!parse->config->blanks) + goto bail; + } + switch (v->tag) { + case FcVStackInteger: + if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) + goto bail; + break; + case FcVStackRange: + if (v->u.range.begin <= v->u.range.end) + { + for (i = v->u.range.begin; i <= v->u.range.end; i++) + { + if (!FcBlanksAdd (parse->config->blanks, i)) + goto bail; + } + } + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in blank"); + break; + } + } + return; + bail: + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcParseRescan (FcConfigParse *parse) +{ + int n = FcVStackElements (parse); + while (n-- > 0) + { + FcVStack *v = FcVStackFetch (parse, n); + if (v->tag != FcVStackInteger) + FcConfigMessage (parse, FcSevereWarning, "non-integer rescan"); + else + parse->config->rescanInterval = v->u.integer; + } +} + +static void +FcParseInt (FcConfigParse *parse) +{ + FcChar8 *s, *end; + int l; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + end = 0; + l = (int) strtol ((char *) s, (char **)&end, 0); + if (end != s + strlen ((char *) s)) + FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s); + else + FcVStackPushInteger (parse, l); + FcStrBufDestroy (&parse->pstack->str); +} + +/* + * idea copied from glib g_ascii_strtod with + * permission of the author (Alexander Larsson) + */ + +#include <locale.h> + +static double +FcStrtod (char *s, char **end) +{ + struct lconv *locale_data; + char *dot; + double v; + + /* + * Have to swap the decimal point to match the current locale + * if that locale doesn't use 0x2e + */ + if ((dot = strchr (s, 0x2e)) && + (locale_data = localeconv ()) && + (locale_data->decimal_point[0] != 0x2e || + locale_data->decimal_point[1] != 0)) + { + char buf[128]; + int slen = strlen (s); + int dlen = strlen (locale_data->decimal_point); + + if (slen + dlen > (int) sizeof (buf)) + { + if (end) + *end = s; + v = 0; + } + else + { + char *buf_end; + /* mantissa */ + strncpy (buf, s, dot - s); + /* decimal point */ + strcpy (buf + (dot - s), locale_data->decimal_point); + /* rest of number */ + strcpy (buf + (dot - s) + dlen, dot + 1); + buf_end = 0; + v = strtod (buf, &buf_end); + if (buf_end) { + buf_end = s + (buf_end - buf); + if (buf_end > dot) + buf_end -= dlen - 1; + } + if (end) + *end = buf_end; + } + } + else + v = strtod (s, end); + return v; +} + +static void +FcParseDouble (FcConfigParse *parse) +{ + FcChar8 *s, *end; + double d; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + end = 0; + d = FcStrtod ((char *) s, (char **)&end); + if (end != s + strlen ((char *) s)) + FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s); + else + FcVStackPushDouble (parse, d); + FcStrBufDestroy (&parse->pstack->str); +} + +static void +FcParseString (FcConfigParse *parse, FcVStackTag tag) +{ + FcChar8 *s; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + if (!FcVStackPushString (parse, tag, s)) + FcStrFree (s); +} + +static void +FcParseMatrix (FcConfigParse *parse) +{ + FcVStack *vstack; + enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy; + FcMatrix m; + + while ((vstack = FcVStackPeek (parse))) + { + double v; + switch (vstack->tag) { + case FcVStackInteger: + v = vstack->u.integer; + break; + case FcVStackDouble: + v = vstack->u._double; + break; + default: + FcConfigMessage (parse, FcSevereError, "non-double matrix element"); + v = 1.0; + break; + } + 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; + } + FcVStackPopAndDestroy (parse); + matrix_state--; + } + if (matrix_state != m_done) + FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); + else + FcVStackPushMatrix (parse, &m); +} + +static void +FcParseRange (FcConfigParse *parse) +{ + FcVStack *vstack; + FcRange r; + FcChar32 n; + int count = 1; + + while ((vstack = FcVStackPeek (parse))) + { + if (count < 0) + { + FcConfigMessage (parse, FcSevereError, "too many elements in range"); + return; + } + switch (vstack->tag) { + case FcVStackInteger: + n = vstack->u.integer; + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in range"); + break; + } + if (count == 1) + r.end = n; + else + r.begin = n; + count--; + FcVStackPopAndDestroy (parse); + } + if (count < 0) + { + if (r.begin > r.end) + { + FcConfigMessage (parse, FcSevereError, "invalid range"); + return; + } + FcVStackPushRange (parse, &r); + } + else + FcConfigMessage (parse, FcSevereError, "invalid range"); +} + +static FcBool +FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_) +{ + FcBool result = FcFalse; + + if (!FcNameBool (bool_, &result)) + FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean", + bool_); + return result; +} + +static void +FcParseBool (FcConfigParse *parse) +{ + FcChar8 *s; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + FcVStackPushBool (parse, FcConfigLexBool (parse, s)); + FcStrBufDestroy (&parse->pstack->str); +} + +static void +FcParseCharSet (FcConfigParse *parse) +{ + FcVStack *vstack; + FcCharSet *charset = FcCharSetCreate (); + FcChar32 i; + int n = 0; + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackInteger: + if (!FcCharSetAddChar (charset, vstack->u.integer)) + { + FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer); + } + else + n++; + break; + case FcVStackRange: + if (vstack->u.range.begin <= vstack->u.range.end) + { + for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++) + { + if (!FcCharSetAddChar (charset, i)) + { + FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i); + } + else + n++; + } + } + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in charset"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (n > 0) + FcVStackPushCharSet (parse, charset); + else + FcCharSetDestroy (charset); +} + +static void +FcParseLangSet (FcConfigParse *parse) +{ + FcVStack *vstack; + FcLangSet *langset = FcLangSetCreate (); + int n = 0; + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackString: + if (!FcLangSetAdd (langset, vstack->u.string)) + { + FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string); + } + else + n++; + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in langset"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (n > 0) + FcVStackPushLangSet (parse, langset); + else + FcLangSetDestroy (langset); +} + +static FcBool +FcConfigLexBinding (FcConfigParse *parse, + const FcChar8 *binding_string, + FcValueBinding *binding_ret) +{ + FcValueBinding binding; + + if (!binding_string) + binding = FcValueBindingWeak; + else + { + if (!strcmp ((char *) binding_string, "weak")) + binding = FcValueBindingWeak; + else if (!strcmp ((char *) binding_string, "strong")) + binding = FcValueBindingStrong; + else if (!strcmp ((char *) binding_string, "same")) + binding = FcValueBindingSame; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string); + return FcFalse; + } + } + *binding_ret = binding; + return FcTrue; +} + +static void +FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) +{ + FcVStack *vstack; + FcExpr *left, *expr = 0, *new; + + while ((vstack = FcVStackPeek (parse))) + { + if (vstack->tag != FcVStackFamily) + { + FcConfigMessage (parse, FcSevereWarning, "non-family"); + FcVStackPopAndDestroy (parse); + continue; + } + left = vstack->u.expr; + vstack->tag = FcVStackNone; + FcVStackPopAndDestroy (parse); + if (expr) + { + new = FcExprCreateOp (parse->config, left, FcOpComma, expr); + if (!new) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); + break; + } + expr = new; + } + else + expr = left; + } + if (expr) + { + if (!FcVStackPushExpr (parse, tag, expr)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (expr); + } + } +} + +static void +FcParseFamily (FcConfigParse *parse) +{ + FcChar8 *s; + FcExpr *expr; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + expr = FcExprCreateString (parse->config, s); + FcStrBufDestroy (&parse->pstack->str); + if (expr) + FcVStackPushExpr (parse, FcVStackFamily, expr); +} + +static void +FcParseAlias (FcConfigParse *parse) +{ + FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0; + FcEdit *edit = 0, *next; + FcVStack *vstack; + FcTest *test; + FcValueBinding binding; + + if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) + return; + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackFamily: + if (family) + { + new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family); + if (!new) + FcConfigMessage (parse, FcSevereError, "out of memory"); + else + family = new; + } + else + new = vstack->u.expr; + if (new) + { + family = new; + vstack->tag = FcVStackNone; + } + break; + case FcVStackPrefer: + if (prefer) + FcExprDestroy (prefer); + prefer = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackAccept: + if (accept) + FcExprDestroy (accept); + accept = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackDefault: + if (def) + FcExprDestroy (def); + def = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "bad alias"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (!family) + { + FcConfigMessage (parse, FcSevereError, "missing family in alias"); + if (prefer) + FcExprDestroy (prefer); + if (accept) + FcExprDestroy (accept); + if (def) + FcExprDestroy (def); + return; + } + if (prefer) + { + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpPrepend, + prefer, + binding); + if (edit) + edit->next = 0; + else + FcExprDestroy (prefer); + } + if (accept) + { + next = edit; + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppend, + accept, + binding); + if (edit) + edit->next = next; + else + FcExprDestroy (accept); + } + if (def) + { + next = edit; + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppendLast, + def, + binding); + if (edit) + edit->next = next; + else + FcExprDestroy (def); + } + if (edit) + { + test = FcTestCreate (parse, FcMatchPattern, + FcQualAny, + (FcChar8 *) FC_FAMILY, + FcOpEqual, + family); + if (test) + if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) + FcTestDestroy (test); + } + else + FcExprDestroy (family); +} + +static FcExpr * +FcPopExpr (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPeek (parse); + FcExpr *expr = 0; + if (!vstack) + return 0; + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + expr = FcExprCreateString (parse->config, vstack->u.string); + break; + case FcVStackField: + expr = FcExprCreateField (parse->config, (char *) vstack->u.string); + break; + case FcVStackConstant: + expr = FcExprCreateConst (parse->config, vstack->u.string); + break; + case FcVStackGlob: + /* XXX: What's the correct action here? (CDW) */ + break; + case FcVStackPrefer: + case FcVStackAccept: + case FcVStackDefault: + expr = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackInteger: + expr = FcExprCreateInteger (parse->config, vstack->u.integer); + break; + case FcVStackDouble: + expr = FcExprCreateDouble (parse->config, vstack->u._double); + break; + case FcVStackMatrix: + expr = FcExprCreateMatrix (parse->config, vstack->u.matrix); + break; + case FcVStackRange: + break; + case FcVStackBool: + expr = FcExprCreateBool (parse->config, vstack->u.bool_); + break; + case FcVStackCharSet: + expr = FcExprCreateCharSet (parse->config, vstack->u.charset); + break; + case FcVStackLangSet: + expr = FcExprCreateLangSet (parse->config, vstack->u.langset); + break; + case FcVStackTest: + break; + case FcVStackExpr: + expr = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + break; + default: + break; + } + FcVStackPopAndDestroy (parse); + return expr; +} + +/* + * This builds a tree of binary operations. Note + * that every operator is defined so that if only + * a single operand is contained, the value of the + * whole expression is the value of the operand. + * + * This code reduces in that case to returning that + * operand. + */ +static FcExpr * +FcPopBinary (FcConfigParse *parse, FcOp op) +{ + FcExpr *left, *expr = 0, *new; + + while ((left = FcPopExpr (parse))) + { + if (expr) + { + new = FcExprCreateOp (parse->config, left, op, expr); + if (!new) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); + return 0; + } + expr = new; + } + else + expr = left; + } + return expr; +} + +static void +FcParseBinary (FcConfigParse *parse, FcOp op) +{ + FcExpr *expr = FcPopBinary (parse, op); + if (expr) + FcVStackPushExpr (parse, FcVStackExpr, expr); +} + +/* + * This builds a a unary operator, it consumes only + * a single operand + */ + +static FcExpr * +FcPopUnary (FcConfigParse *parse, FcOp op) +{ + FcExpr *operand, *new = 0; + + if ((operand = FcPopExpr (parse))) + { + new = FcExprCreateOp (parse->config, operand, op, 0); + if (!new) + { + FcExprDestroy (operand); + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + } + return new; +} + +static void +FcParseUnary (FcConfigParse *parse, FcOp op) +{ + FcExpr *expr = FcPopUnary (parse, op); + if (expr) + FcVStackPushExpr (parse, FcVStackExpr, expr); +} + +static void +FcParseInclude (FcConfigParse *parse) +{ + FcChar8 *s; + const FcChar8 *i; + FcBool ignore_missing = FcFalse; + + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + i = FcConfigGetAttribute (parse, "ignore_missing"); + if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue) + ignore_missing = FcTrue; + if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) + parse->error = FcTrue; + FcStrBufDestroy (&parse->pstack->str); +} + +typedef struct _FcOpMap { + char name[16]; + FcOp op; +} FcOpMap; + +static FcOp +FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) +{ + int i; + + for (i = 0; i < nmap; i++) + if (!strcmp ((char *) op, map[i].name)) + return map[i].op; + return FcOpInvalid; +} + +static const FcOpMap fcCompareOps[] = { + { "eq", FcOpEqual }, + { "not_eq", FcOpNotEqual }, + { "less", FcOpLess }, + { "less_eq", FcOpLessEqual }, + { "more", FcOpMore }, + { "more_eq", FcOpMoreEqual }, + { "contains", FcOpContains }, + { "not_contains", FcOpNotContains } +}; + +#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0]) + +static FcOp +FcConfigLexCompare (const FcChar8 *compare) +{ + return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS); +} + +static void +FcParseTest (FcConfigParse *parse) +{ + const FcChar8 *kind_string; + FcMatchKind kind; + const FcChar8 *qual_string; + FcQual qual; + const FcChar8 *name; + const FcChar8 *compare_string; + FcOp compare; + FcExpr *expr; + FcTest *test; + + kind_string = FcConfigGetAttribute (parse, "target"); + if (!kind_string) + kind = FcMatchDefault; + else + { + if (!strcmp ((char *) kind_string, "pattern")) + kind = FcMatchPattern; + else if (!strcmp ((char *) kind_string, "font")) + kind = FcMatchFont; + else if (!strcmp ((char *) kind_string, "scan")) + kind = FcMatchScan; + else if (!strcmp ((char *) kind_string, "default")) + kind = FcMatchDefault; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string); + return; + } + } + qual_string = FcConfigGetAttribute (parse, "qual"); + if (!qual_string) + qual = FcQualAny; + else + { + if (!strcmp ((char *) qual_string, "any")) + qual = FcQualAny; + else if (!strcmp ((char *) qual_string, "all")) + qual = FcQualAll; + else if (!strcmp ((char *) qual_string, "first")) + qual = FcQualFirst; + else if (!strcmp ((char *) qual_string, "not_first")) + qual = FcQualNotFirst; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string); + return; + } + } + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing test name"); + return; + } + compare_string = FcConfigGetAttribute (parse, "compare"); + if (!compare_string) + compare = FcOpEqual; + else + { + compare = FcConfigLexCompare (compare_string); + if (compare == FcOpInvalid) + { + FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string); + return; + } + } + expr = FcPopBinary (parse, FcOpComma); + if (!expr) + { + FcConfigMessage (parse, FcSevereWarning, "missing test expression"); + return; + } + test = FcTestCreate (parse, kind, qual, name, compare, expr); + if (!test) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + FcVStackPushTest (parse, test); +} + +static const FcOpMap fcModeOps[] = { + { "assign", FcOpAssign }, + { "assign_replace", FcOpAssignReplace }, + { "prepend", FcOpPrepend }, + { "prepend_first", FcOpPrependFirst }, + { "append", FcOpAppend }, + { "append_last", FcOpAppendLast }, +}; + +#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0]) + +static FcOp +FcConfigLexMode (const FcChar8 *mode) +{ + return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS); +} + +static void +FcParseEdit (FcConfigParse *parse) +{ + const FcChar8 *name; + const FcChar8 *mode_string; + FcOp mode; + FcValueBinding binding; + FcExpr *expr; + FcEdit *edit; + + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing edit name"); + return; + } + mode_string = FcConfigGetAttribute (parse, "mode"); + if (!mode_string) + mode = FcOpAssign; + else + { + mode = FcConfigLexMode (mode_string); + if (mode == FcOpInvalid) + { + FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string); + return; + } + } + if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) + return; + + expr = FcPopBinary (parse, FcOpComma); + edit = FcEditCreate (parse, FcObjectFromName ((char *) name), + mode, expr, binding); + if (!edit) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (expr); + return; + } + if (!FcVStackPushEdit (parse, edit)) + FcEditDestroy (edit); +} + +static void +FcParseMatch (FcConfigParse *parse) +{ + const FcChar8 *kind_name; + FcMatchKind kind; + FcTest *test = 0; + FcEdit *edit = 0; + FcVStack *vstack; + + kind_name = FcConfigGetAttribute (parse, "target"); + if (!kind_name) + kind = FcMatchPattern; + else + { + if (!strcmp ((char *) kind_name, "pattern")) + kind = FcMatchPattern; + else if (!strcmp ((char *) kind_name, "font")) + kind = FcMatchFont; + else if (!strcmp ((char *) kind_name, "scan")) + kind = FcMatchScan; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name); + return; + } + } + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackTest: + vstack->u.test->next = test; + test = vstack->u.test; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + vstack->u.edit->next = edit; + edit = vstack->u.edit; + vstack->tag = FcVStackNone; + if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT) + { + FcConfigMessage (parse, FcSevereError, + "<match target=\"scan\"> cannot edit user-defined object \"%s\"", + FcObjectName(edit->object)); + } + break; + default: + FcConfigMessage (parse, FcSevereWarning, "invalid match element"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (!FcConfigAddEdit (parse->config, test, edit, kind)) + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) +{ + FcVStack *vstack; + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackGlob: + if (!FcConfigGlobAdd (parse->config, + vstack->u.string, + element == FcElementAcceptfont)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + break; + case FcVStackPattern: + if (!FcConfigPatternsAdd (parse->config, + vstack->u.pattern, + element == FcElementAcceptfont)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + else + vstack->tag = FcVStackNone; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "bad font selector"); + break; + } + FcVStackPopAndDestroy (parse); + } +} + + +static FcValue +FcPopValue (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPeek (parse); + FcValue value; + + value.type = FcTypeVoid; + + if (!vstack) + return value; + + switch (vstack->tag) { + case FcVStackString: + value.u.s = FcStrStaticName (vstack->u.string); + if (value.u.s) + value.type = FcTypeString; + break; + case FcVStackConstant: + if (FcNameConstant (vstack->u.string, &value.u.i)) + value.type = FcTypeInteger; + break; + case FcVStackInteger: + value.u.i = vstack->u.integer; + value.type = FcTypeInteger; + break; + case FcVStackDouble: + value.u.d = vstack->u._double; + value.type = FcTypeInteger; + break; + case FcVStackMatrix: + value.u.m = FcMatrixCopy (vstack->u.matrix); + if (value.u.m) + value.type = FcTypeMatrix; + break; + case FcVStackBool: + value.u.b = vstack->u.bool_; + value.type = FcTypeBool; + break; + case FcVStackCharSet: + value.u.c = FcCharSetCopy (vstack->u.charset); + if (value.u.c) + value.type = FcTypeCharSet; + break; + case FcVStackLangSet: + value.u.l = FcLangSetCopy (vstack->u.langset); + if (value.u.l) + value.type = FcTypeLangSet; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", + vstack->tag); + break; + } + FcVStackPopAndDestroy (parse); + + return value; +} + +static void +FcParsePatelt (FcConfigParse *parse) +{ + FcValue value; + FcPattern *pattern = FcPatternCreate (); + const char *name; + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + name = (char *) FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); + FcPatternDestroy (pattern); + return; + } + + for (;;) + { + value = FcPopValue (parse); + if (value.type == FcTypeVoid) + break; + if (!FcPatternAdd (pattern, name, value, FcTrue)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcValueDestroy(value); + break; + } + FcValueDestroy(value); + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcParsePattern (FcConfigParse *parse) +{ + FcVStack *vstack; + FcPattern *pattern = FcPatternCreate (); + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackPattern: + if (!FcPatternAppend (pattern, vstack->u.pattern)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcPatternDestroy (pattern); + return; + } + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); + break; + } + FcVStackPopAndDestroy (parse); + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcEndElement(void *userData, const XML_Char *name) +{ + FcConfigParse *parse = userData; + FcChar8 *data; +#ifdef _WIN32 + FcChar8 buffer[1000]; +#endif + + if (!parse->pstack) + return; + switch (parse->pstack->element) { + case FcElementNone: + break; + case FcElementFontconfig: + break; + case FcElementDir: + data = FcStrBufDoneStatic (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } +#ifdef _WIN32 + if (strcmp (data, "CUSTOMFONTDIR") == 0) + { + char *p; + data = buffer; + if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20)) + { + FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); + break; + } + /* + * Must use the multi-byte aware function to search + * for backslash because East Asian double-byte code + * pages have characters with backslash as the second + * byte. + */ + p = _mbsrchr (data, '\\'); + if (p) *p = '\0'; + strcat (data, "\\fonts"); + } + else if (strcmp (data, "APPSHAREFONTDIR") == 0) + { + char *p; + data = buffer; + if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20)) + { + FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); + break; + } + p = _mbsrchr (data, '\\'); + if (p) *p = '\0'; + strcat (data, "\\..\\share\\fonts"); + } + else if (strcmp (data, "WINDOWSFONTDIR") == 0) + { + int rc; + data = buffer; +#if _WIN32_WINNT >= 0x0500 + rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20); +#else + rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20); +#endif + if (rc == 0 || rc > sizeof (buffer) - 20) + { + FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed"); + break; + } + if (data [strlen (data) - 1] != '\\') + strcat (data, "\\"); + strcat (data, "fonts"); + } +#endif + if (strlen ((char *) data) == 0) + FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored"); + else if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigAddDir (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data); + } + FcStrBufDestroy (&parse->pstack->str); + break; + case FcElementCacheDir: + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } +#ifdef _WIN32 + if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) + { + int rc; + FcStrFree (data); + data = malloc (1000); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + FcMemAlloc (FC_MEM_STRING, 1000); + rc = GetTempPath (800, data); + if (rc == 0 || rc > 800) + { + FcConfigMessage (parse, FcSevereError, "GetTempPath failed"); + FcStrFree (data); + break; + } + if (data [strlen (data) - 1] != '\\') + strcat (data, "\\"); + strcat (data, "fontconfig\\cache"); + } +#endif + if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigAddCacheDir (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data); + } + FcStrFree (data); + break; + + case FcElementCache: + data = FcStrBufDoneStatic (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + /* discard this data; no longer used */ + FcStrBufDestroy (&parse->pstack->str); + break; + case FcElementInclude: + FcParseInclude (parse); + break; + case FcElementConfig: + break; + case FcElementMatch: + FcParseMatch (parse); + break; + case FcElementAlias: + FcParseAlias (parse); + break; + + case FcElementBlank: + FcParseBlank (parse); + break; + case FcElementRescan: + FcParseRescan (parse); + break; + + case FcElementPrefer: + FcParseFamilies (parse, FcVStackPrefer); + break; + case FcElementAccept: + FcParseFamilies (parse, FcVStackAccept); + break; + case FcElementDefault: + FcParseFamilies (parse, FcVStackDefault); + break; + case FcElementFamily: + FcParseFamily (parse); + break; + + case FcElementTest: + FcParseTest (parse); + break; + case FcElementEdit: + FcParseEdit (parse); + break; + + case FcElementInt: + FcParseInt (parse); + break; + case FcElementDouble: + FcParseDouble (parse); + break; + case FcElementString: + FcParseString (parse, FcVStackString); + break; + case FcElementMatrix: + FcParseMatrix (parse); + break; + case FcElementRange: + FcParseRange (parse); + break; + case FcElementBool: + FcParseBool (parse); + break; + case FcElementCharSet: + FcParseCharSet (parse); + break; + case FcElementLangSet: + FcParseLangSet (parse); + break; + case FcElementSelectfont: + break; + case FcElementAcceptfont: + case FcElementRejectfont: + FcParseAcceptRejectFont (parse, parse->pstack->element); + break; + case FcElementGlob: + FcParseString (parse, FcVStackGlob); + break; + case FcElementPattern: + FcParsePattern (parse); + break; + case FcElementPatelt: + FcParsePatelt (parse); + break; + case FcElementName: + FcParseString (parse, FcVStackField); + break; + case FcElementConst: + FcParseString (parse, FcVStackConstant); + break; + case FcElementOr: + FcParseBinary (parse, FcOpOr); + break; + case FcElementAnd: + FcParseBinary (parse, FcOpAnd); + break; + case FcElementEq: + FcParseBinary (parse, FcOpEqual); + break; + case FcElementNotEq: + FcParseBinary (parse, FcOpNotEqual); + break; + case FcElementLess: + FcParseBinary (parse, FcOpLess); + break; + case FcElementLessEq: + FcParseBinary (parse, FcOpLessEqual); + break; + case FcElementMore: + FcParseBinary (parse, FcOpMore); + break; + case FcElementMoreEq: + FcParseBinary (parse, FcOpMoreEqual); + break; + case FcElementContains: + FcParseBinary (parse, FcOpContains); + break; + case FcElementNotContains: + FcParseBinary (parse, FcOpNotContains); + break; + case FcElementPlus: + FcParseBinary (parse, FcOpPlus); + break; + case FcElementMinus: + FcParseBinary (parse, FcOpMinus); + break; + case FcElementTimes: + FcParseBinary (parse, FcOpTimes); + break; + case FcElementDivide: + FcParseBinary (parse, FcOpDivide); + break; + case FcElementNot: + FcParseUnary (parse, FcOpNot); + break; + case FcElementIf: + FcParseBinary (parse, FcOpQuest); + break; + case FcElementFloor: + FcParseUnary (parse, FcOpFloor); + break; + case FcElementCeil: + FcParseUnary (parse, FcOpCeil); + break; + case FcElementRound: + FcParseUnary (parse, FcOpRound); + break; + case FcElementTrunc: + FcParseUnary (parse, FcOpTrunc); + break; + case FcElementUnknown: + break; + } + (void) FcPStackPop (parse); +} + +static void +FcCharacterData (void *userData, const XML_Char *s, int len) +{ + FcConfigParse *parse = userData; + + if (!parse->pstack) + return; + if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len)) + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcStartDoctypeDecl (void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset) +{ + FcConfigParse *parse = userData; + + if (strcmp ((char *) doctypeName, "fontconfig") != 0) + FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName); +} + +#ifdef ENABLE_LIBXML2 + +static void +FcInternalSubsetDecl (void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid) +{ + FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1); +} + +static void +FcExternalSubsetDecl (void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid) +{ + FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0); +} + +#else /* ENABLE_LIBXML2 */ + +static void +FcEndDoctypeDecl (void *userData) +{ +} + +#endif /* ENABLE_LIBXML2 */ + +static int +FcSortCmpStr (const void *a, const void *b) +{ + const FcChar8 *as = *((FcChar8 **) a); + const FcChar8 *bs = *((FcChar8 **) b); + return FcStrCmp (as, bs); +} + +static FcBool +FcConfigParseAndLoadDir (FcConfig *config, + const FcChar8 *name, + const FcChar8 *dir, + FcBool complain) +{ + DIR *d; + struct dirent *e; + FcBool ret = FcTrue; + FcChar8 *file; + FcChar8 *base; + FcStrSet *files; + + d = opendir ((char *) dir); + if (!d) + { + if (complain) + FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"", + name); + ret = FcFalse; + goto bail0; + } + /* freed below */ + file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); + if (!file) + { + ret = FcFalse; + goto bail1; + } + + strcpy ((char *) file, (char *) dir); + strcat ((char *) file, "/"); + base = file + strlen ((char *) file); + + files = FcStrSetCreate (); + if (!files) + { + ret = FcFalse; + goto bail2; + } + + if (FcDebug () & FC_DBG_CONFIG) + printf ("\tScanning config dir %s\n", dir); + + while (ret && (e = readdir (d))) + { + int d_len; +#define TAIL ".conf" +#define TAIL_LEN 5 + /* + * Add all files of the form [0-9]*.conf + */ + if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && + (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN && + d_len > TAIL_LEN && + strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) + { + strcpy ((char *) base, (char *) e->d_name); + if (!FcStrSetAdd (files, file)) + { + ret = FcFalse; + goto bail3; + } + } + } + if (ret) + { + int i; + qsort (files->strs, files->num, sizeof (FcChar8 *), + (int (*)(const void *, const void *)) FcSortCmpStr); + for (i = 0; ret && i < files->num; i++) + ret = FcConfigParseAndLoad (config, files->strs[i], complain); + } +bail3: + FcStrSetDestroy (files); +bail2: + free (file); +bail1: + closedir (d); +bail0: + return ret || !complain; +} + +FcBool +FcConfigParseAndLoad (FcConfig *config, + const FcChar8 *name, + FcBool complain) +{ + + XML_Parser p; + FcChar8 *filename; + int fd; + int len; + FcConfigParse parse; + FcBool error = FcTrue; + +#ifdef ENABLE_LIBXML2 + xmlSAXHandler sax; + char buf[BUFSIZ]; +#else + void *buf; +#endif + + filename = FcConfigFilename (name); + if (!filename) + goto bail0; + + if (FcStrSetMember (config->configFiles, filename)) + { + FcStrFree (filename); + return FcTrue; + } + + if (!FcStrSetAdd (config->configFiles, filename)) + { + FcStrFree (filename); + goto bail0; + } + + if (FcFileIsDir (filename)) + { + FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain); + FcStrFree (filename); + return ret; + } + + if (FcDebug () & FC_DBG_CONFIG) + printf ("\tLoading config file %s\n", filename); + + fd = open ((char *) filename, O_RDONLY); + if (fd == -1) { + FcStrFree (filename); + goto bail0; + } + +#ifdef ENABLE_LIBXML2 + memset(&sax, 0, sizeof(sax)); + + sax.internalSubset = FcInternalSubsetDecl; + sax.externalSubset = FcExternalSubsetDecl; + sax.startElement = FcStartElement; + sax.endElement = FcEndElement; + sax.characters = FcCharacterData; + + p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename); +#else + p = XML_ParserCreate ("UTF-8"); +#endif + FcStrFree (filename); + + if (!p) + goto bail1; + + if (!FcConfigInit (&parse, name, config, p)) + goto bail2; + +#ifndef ENABLE_LIBXML2 + + XML_SetUserData (p, &parse); + + XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); + XML_SetElementHandler (p, FcStartElement, FcEndElement); + XML_SetCharacterDataHandler (p, FcCharacterData); + +#endif /* ENABLE_LIBXML2 */ + + do { +#ifndef ENABLE_LIBXML2 + buf = XML_GetBuffer (p, BUFSIZ); + if (!buf) + { + FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); + goto bail3; + } +#endif + len = read (fd, buf, BUFSIZ); + if (len < 0) + { + FcConfigMessage (&parse, FcSevereError, "failed reading config file"); + goto bail3; + } + +#ifdef ENABLE_LIBXML2 + if (xmlParseChunk (p, buf, len, len == 0)) +#else + if (!XML_ParseBuffer (p, len, len == 0)) +#endif + { + FcConfigMessage (&parse, FcSevereError, "%s", + XML_ErrorString (XML_GetErrorCode (p))); + goto bail3; + } + } while (len != 0); + error = parse.error; +bail3: + FcConfigCleanup (&parse); +bail2: + XML_ParserFree (p); +bail1: + close (fd); + fd = -1; +bail0: + if (error && complain) + { + if (name) + FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name); + else + FcConfigMessage (0, FcSevereError, "Cannot load default config file"); + return FcFalse; + } + return FcTrue; +} +#define __fcxml__ +#include "fcaliastail.h" +#undef __fcxml__ diff --git a/fontconfig/src/ftglue.c b/fontconfig/src/ftglue.c index 91cb532b9..d5af810b4 100644 --- a/fontconfig/src/ftglue.c +++ b/fontconfig/src/ftglue.c @@ -1,261 +1,261 @@ -/* ftglue.c: Glue code for compiling the OpenType code from
- * FreeType 1 using only the public API of FreeType 2
- *
- * By David Turner, The FreeType Project (www.freetype.org)
- *
- * This code is explicitely put in the public domain
- *
- * See ftglue.h for more information.
- */
-
-#include "ftglue.h"
-
-#if 0
-#include <stdio.h>
-#define LOG(x) ftglue_log x
-
-static void
-ftglue_log( const char* format, ... )
-{
- va_list ap;
-
- va_start( ap, format );
- vfprintf( stderr, format, ap );
- va_end( ap );
-}
-
-#else
-#define LOG(x) do {} while (0)
-#endif
-
-/* only used internally */
-static FT_Pointer
-ftglue_qalloc( FT_Memory memory,
- FT_ULong size,
- FT_Error *perror )
-{
- FT_Error error = 0;
- FT_Pointer block = NULL;
-
- if ( size > 0 )
- {
- block = memory->alloc( memory, size );
- if ( !block )
- error = FT_Err_Out_Of_Memory;
- }
-
- *perror = error;
- return block;
-}
-
-#undef QALLOC /* just in case */
-#define QALLOC(ptr,size) ( (ptr) = ftglue_qalloc( memory, (size), &error ), error != 0 )
-#define FREE(_ptr) \
- do { \
- if ( (_ptr) ) \
- { \
- ftglue_free( memory, _ptr ); \
- _ptr = NULL; \
- } \
- } while (0)
-
-
-static void
-ftglue_free( FT_Memory memory,
- FT_Pointer block )
-{
- if ( block )
- memory->free( memory, block );
-}
-
-FTGLUE_APIDEF( FT_Long )
-ftglue_stream_pos( FT_Stream stream )
-{
- LOG(( "ftglue:stream:pos() -> %ld\n", stream->pos ));
- return stream->pos;
-}
-
-
-FTGLUE_APIDEF( FT_Error )
-ftglue_stream_seek( FT_Stream stream,
- FT_Long pos )
-{
- FT_Error error = 0;
-
- stream->pos = pos;
- if ( stream->read )
- {
- if ( stream->read( stream, pos, 0, 0 ) )
- error = FT_Err_Invalid_Stream_Operation;
- }
- else if ( pos > stream->size )
- error = FT_Err_Invalid_Stream_Operation;
-
- LOG(( "ftglue:stream:seek(%ld) -> %d\n", pos, error ));
- return error;
-}
-
-
-FTGLUE_APIDEF( FT_Error )
-ftglue_stream_frame_enter( FT_Stream stream,
- FT_ULong count )
-{
- FT_Error error = FT_Err_Ok;
- FT_ULong read_bytes;
-
- if ( stream->read )
- {
- /* allocate the frame in memory */
- FT_Memory memory = stream->memory;
-
-
- if ( QALLOC( stream->base, count ) )
- goto Exit;
-
- /* read it */
- read_bytes = stream->read( stream, stream->pos,
- stream->base, count );
- if ( read_bytes < count )
- {
- FREE( stream->base );
- error = FT_Err_Invalid_Stream_Operation;
- }
- stream->cursor = stream->base;
- stream->limit = stream->cursor + count;
- stream->pos += read_bytes;
- }
- else
- {
- /* check current and new position */
- if ( stream->pos >= stream->size ||
- stream->pos + count > stream->size )
- {
- error = FT_Err_Invalid_Stream_Operation;
- goto Exit;
- }
-
- /* set cursor */
- stream->cursor = stream->base + stream->pos;
- stream->limit = stream->cursor + count;
- stream->pos += count;
- }
-
-Exit:
- LOG(( "ftglue:stream:frame_enter(%ld) -> %d\n", count, error ));
- return error;
-}
-
-
-FTGLUE_APIDEF( void )
-ftglue_stream_frame_exit( FT_Stream stream )
-{
- if ( stream->read )
- {
- FT_Memory memory = stream->memory;
-
- FREE( stream->base );
- }
- stream->cursor = 0;
- stream->limit = 0;
-
- LOG(( "ftglue:stream:frame_exit()\n" ));
-}
-
-
-FTGLUE_APIDEF( FT_Error )
-ftglue_face_goto_table( FT_Face face,
- FT_ULong the_tag,
- FT_Stream stream )
-{
- FT_Error error;
-
- LOG(( "ftglue_face_goto_table( %p, %c%c%c%c, %p )\n",
- face,
- (int)((the_tag >> 24) & 0xFF),
- (int)((the_tag >> 16) & 0xFF),
- (int)((the_tag >> 8) & 0xFF),
- (int)(the_tag & 0xFF),
- stream ));
-
- if ( !FT_IS_SFNT(face) )
- {
- LOG(( "not a SFNT face !!\n" ));
- error = FT_Err_Invalid_Face_Handle;
- }
- else
- {
- /* parse the directory table directly, without using
- * FreeType's built-in data structures
- */
- FT_ULong offset = 0, sig;
- FT_UInt count, nn;
-
- if ( FILE_Seek( 0 ) || ACCESS_Frame( 4 ) )
- goto Exit;
-
- sig = GET_Tag4();
-
- FORGET_Frame();
-
- if ( sig == FT_MAKE_TAG( 't', 't', 'c', 'f' ) )
- {
- /* deal with TrueType collections */
-
- LOG(( ">> This is a TrueType Collection\n" ));
-
- if ( FILE_Seek( 12 + face->face_index*4 ) ||
- ACCESS_Frame( 4 ) )
- goto Exit;
-
- offset = GET_ULong();
-
- FORGET_Frame();
- }
-
- LOG(( "TrueType offset = %ld\n", offset ));
-
- if ( FILE_Seek( offset+4 ) ||
- ACCESS_Frame( 2 ) )
- goto Exit;
-
- count = GET_UShort();
-
- FORGET_Frame();
-
- if ( FILE_Seek( offset+12 ) ||
- ACCESS_Frame( count*16 ) )
- goto Exit;
-
- for ( nn = 0; nn < count; nn++ )
- {
- FT_ULong tag = GET_ULong();
- FT_ULong checksum = GET_ULong();
- FT_ULong start = GET_ULong();
- FT_ULong size = GET_ULong();
-
- FT_UNUSED(checksum);
- FT_UNUSED(size);
-
- if ( tag == the_tag )
- {
- LOG(( "TrueType table (start: %ld) (size: %ld)\n", start, size ));
- error = ftglue_stream_seek( stream, start );
- goto FoundIt;
- }
- }
- error = FT_Err_Table_Missing;
-
- FoundIt:
- FORGET_Frame();
- }
-
-Exit:
- LOG(( "TrueType error=%d\n", error ));
-
- return error;
-}
-
-#undef QALLOC
-#define __ftglue__
-#include "fcaliastail.h"
-#undef __ftglue__
+/* ftglue.c: Glue code for compiling the OpenType code from + * FreeType 1 using only the public API of FreeType 2 + * + * By David Turner, The FreeType Project (www.freetype.org) + * + * This code is explicitely put in the public domain + * + * See ftglue.h for more information. + */ + +#include "ftglue.h" + +#if 0 +#include <stdio.h> +#define LOG(x) ftglue_log x + +static void +ftglue_log( const char* format, ... ) +{ + va_list ap; + + va_start( ap, format ); + vfprintf( stderr, format, ap ); + va_end( ap ); +} + +#else +#define LOG(x) do {} while (0) +#endif + +/* only used internally */ +static FT_Pointer +ftglue_qalloc( FT_Memory memory, + FT_ULong size, + FT_Error *perror ) +{ + FT_Error error = 0; + FT_Pointer block = NULL; + + if ( size > 0 ) + { + block = memory->alloc( memory, size ); + if ( !block ) + error = FT_Err_Out_Of_Memory; + } + + *perror = error; + return block; +} + +#undef QALLOC /* just in case */ +#define QALLOC(ptr,size) ( (ptr) = ftglue_qalloc( memory, (size), &error ), error != 0 ) +#define FREE(_ptr) \ + do { \ + if ( (_ptr) ) \ + { \ + ftglue_free( memory, _ptr ); \ + _ptr = NULL; \ + } \ + } while (0) + + +static void +ftglue_free( FT_Memory memory, + FT_Pointer block ) +{ + if ( block ) + memory->free( memory, block ); +} + +FTGLUE_APIDEF( FT_Long ) +ftglue_stream_pos( FT_Stream stream ) +{ + LOG(( "ftglue:stream:pos() -> %ld\n", stream->pos )); + return stream->pos; +} + + +FTGLUE_APIDEF( FT_Error ) +ftglue_stream_seek( FT_Stream stream, + FT_Long pos ) +{ + FT_Error error = 0; + + stream->pos = pos; + if ( stream->read ) + { + if ( stream->read( stream, pos, 0, 0 ) ) + error = FT_Err_Invalid_Stream_Operation; + } + else if ( pos > stream->size ) + error = FT_Err_Invalid_Stream_Operation; + + LOG(( "ftglue:stream:seek(%ld) -> %d\n", pos, error )); + return error; +} + + +FTGLUE_APIDEF( FT_Error ) +ftglue_stream_frame_enter( FT_Stream stream, + FT_ULong count ) +{ + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + if ( stream->read ) + { + /* allocate the frame in memory */ + FT_Memory memory = stream->memory; + + + if ( QALLOC( stream->base, count ) ) + goto Exit; + + /* read it */ + read_bytes = stream->read( stream, stream->pos, + stream->base, count ); + if ( read_bytes < count ) + { + FREE( stream->base ); + error = FT_Err_Invalid_Stream_Operation; + } + stream->cursor = stream->base; + stream->limit = stream->cursor + count; + stream->pos += read_bytes; + } + else + { + /* check current and new position */ + if ( stream->pos >= stream->size || + stream->pos + count > stream->size ) + { + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + + /* set cursor */ + stream->cursor = stream->base + stream->pos; + stream->limit = stream->cursor + count; + stream->pos += count; + } + +Exit: + LOG(( "ftglue:stream:frame_enter(%ld) -> %d\n", count, error )); + return error; +} + + +FTGLUE_APIDEF( void ) +ftglue_stream_frame_exit( FT_Stream stream ) +{ + if ( stream->read ) + { + FT_Memory memory = stream->memory; + + FREE( stream->base ); + } + stream->cursor = 0; + stream->limit = 0; + + LOG(( "ftglue:stream:frame_exit()\n" )); +} + + +FTGLUE_APIDEF( FT_Error ) +ftglue_face_goto_table( FT_Face face, + FT_ULong the_tag, + FT_Stream stream ) +{ + FT_Error error; + + LOG(( "ftglue_face_goto_table( %p, %c%c%c%c, %p )\n", + face, + (int)((the_tag >> 24) & 0xFF), + (int)((the_tag >> 16) & 0xFF), + (int)((the_tag >> 8) & 0xFF), + (int)(the_tag & 0xFF), + stream )); + + if ( !FT_IS_SFNT(face) ) + { + LOG(( "not a SFNT face !!\n" )); + error = FT_Err_Invalid_Face_Handle; + } + else + { + /* parse the directory table directly, without using + * FreeType's built-in data structures + */ + FT_ULong offset = 0, sig; + FT_UInt count, nn; + + if ( FILE_Seek( 0 ) || ACCESS_Frame( 4 ) ) + goto Exit; + + sig = GET_Tag4(); + + FORGET_Frame(); + + if ( sig == FT_MAKE_TAG( 't', 't', 'c', 'f' ) ) + { + /* deal with TrueType collections */ + + LOG(( ">> This is a TrueType Collection\n" )); + + if ( FILE_Seek( 12 + face->face_index*4 ) || + ACCESS_Frame( 4 ) ) + goto Exit; + + offset = GET_ULong(); + + FORGET_Frame(); + } + + LOG(( "TrueType offset = %ld\n", offset )); + + if ( FILE_Seek( offset+4 ) || + ACCESS_Frame( 2 ) ) + goto Exit; + + count = GET_UShort(); + + FORGET_Frame(); + + if ( FILE_Seek( offset+12 ) || + ACCESS_Frame( count*16 ) ) + goto Exit; + + for ( nn = 0; nn < count; nn++ ) + { + FT_ULong tag = GET_ULong(); + FT_ULong checksum = GET_ULong(); + FT_ULong start = GET_ULong(); + FT_ULong size = GET_ULong(); + + FT_UNUSED(checksum); + FT_UNUSED(size); + + if ( tag == the_tag ) + { + LOG(( "TrueType table (start: %ld) (size: %ld)\n", start, size )); + error = ftglue_stream_seek( stream, start ); + goto FoundIt; + } + } + error = FT_Err_Table_Missing; + + FoundIt: + FORGET_Frame(); + } + +Exit: + LOG(( "TrueType error=%d\n", error )); + + return error; +} + +#undef QALLOC +#define __ftglue__ +#include "fcaliastail.h" +#undef __ftglue__ |