diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/fontconfig/src/src | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/fontconfig/src/src')
39 files changed, 24029 insertions, 0 deletions
diff --git a/chromium/third_party/fontconfig/src/src/Makefile.am b/chromium/third_party/fontconfig/src/src/Makefile.am new file mode 100644 index 00000000000..066cc03e718 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/Makefile.am @@ -0,0 +1,213 @@ +# +# 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. + +EXTRA_DIST = + +if OS_WIN32 + +export_symbols = -export-symbols fontconfig.def + +fontconfig_def_dependency = fontconfig.def + +# gcc import library install/uninstall + +install-libtool-import-lib: libfontconfig.la + $(MKDIR_P) $(DESTDIR)$(libdir) + $(INSTALL) .libs/libfontconfig.dll.a $(DESTDIR)$(libdir)/libfontconfig.dll.a + $(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 + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + $(FREETYPE_CFLAGS) \ + $(ICONV_CFLAGS) \ + $(LIBXML2_CFLAGS) \ + $(EXPAT_CFLAGS) \ + $(WARN_CFLAGS) \ + -DFC_CACHEDIR='"$(FC_CACHEDIR)"' \ + -DFONTCONFIG_PATH='"$(BASECONFIGDIR)"' + +EXTRA_DIST += makealias + +noinst_HEADERS=fcint.h fcftint.h fcdeprecate.h fcstdint.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 \ + stamp-fcstdint \ + fcobjshash.h \ + fcobjshash.gperf + +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 + +fcobjshash.gperf: fcobjshash.gperf.h fcobjs.h + $(AM_V_GEN) $(CPP) -I$(top_srcdir) $< | \ + $(SED) 's/^ *//;s/ *, */,/' | \ + $(GREP) '^[^#]' | \ + awk ' \ + /CUT_OUT_BEGIN/ { no_write=1; next; }; \ + /CUT_OUT_END/ { no_write=0; next; }; \ + { if (!no_write) print; next; }; \ + ' - > $@.tmp && \ + mv -f $@.tmp $@ || ( $(RM) $@.tmp && false ) + +fcobjshash.h: fcobjshash.gperf + $(AM_V_GEN) $(GPERF) -m 100 $< > $@.tmp && \ + mv -f $@.tmp $@ || ( $(RM) $@.tmp && false ) + +EXTRA_DIST += \ + fcobjshash.gperf.h \ + fcobjshash.gperf \ + fcobjshash.h + +libfontconfig_la_SOURCES = \ + fcarch.h \ + fcatomic.c \ + fcatomic.h \ + fcblanks.c \ + fccache.c \ + fccfg.c \ + fccharset.c \ + fccompat.c \ + fcdbg.c \ + fcdefault.c \ + fcdir.c \ + fcformat.c \ + fcfreetype.c \ + fcfs.c \ + fchash.c \ + fcinit.c \ + fclang.c \ + fclist.c \ + fcmatch.c \ + fcmatrix.c \ + fcmutex.h \ + fcname.c \ + fcobjs.c \ + fcobjs.h \ + fcobjshash.h \ + fcpat.c \ + fcserialize.c \ + fcstat.c \ + fcstr.c \ + fcwindows.h \ + 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) + +if ENABLE_SHARED +install-data-local: install-ms-import-lib install-libtool-import-lib + +uninstall-local: uninstall-ms-import-lib uninstall-libtool-import-lib +endif + +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) + $(AM_V_GEN) 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) + $(AM_V_GEN) sh $(top_srcdir)/src/makealias "$(top_srcdir)/src" fcftalias.h fcftaliastail.h $(PUBLIC_FT_FILES) + +stamp-fcstdint: $(top_builddir)/config.status + $(AM_V_GEN) cd $(top_builddir) && \ + $(SHELL) ./config.status src/fcstdint.h + @touch $@ + +CLEANFILES = $(ALIAS_FILES) fontconfig.def +DISTCLEANFILES = stamp-fcstdint fcstdint.h + +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) + +-include $(top_srcdir)/git.mk diff --git a/chromium/third_party/fontconfig/src/src/fcarch.c b/chromium/third_party/fontconfig/src/src/fcarch.c new file mode 100644 index 00000000000..398f4bbfcd5 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcarch.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2002 Keith Packard + * Copyright © 2010 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 <stdio.h> + +#include "fcint.h" +#include "fcarch.h" + +FC_ASSERT_STATIC (1 == sizeof (char)); +FC_ASSERT_STATIC (2 == sizeof (FcChar16)); +FC_ASSERT_STATIC (4 == sizeof (int)); +FC_ASSERT_STATIC (4 == sizeof (FcChar32)); +FC_ASSERT_STATIC (4 == sizeof (FcObject)); +FC_ASSERT_STATIC (4 == sizeof (FcValueBinding)); +FC_ASSERT_STATIC (8 == sizeof (FcAlign)); +FC_ASSERT_STATIC (0x20 == sizeof (FcCharLeaf)); + +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (intptr_t)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (FcPatternEltPtr)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (FcValueListPtr)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (char *)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (struct FcPatternElt *)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (FcValueList *)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (FcStrSet *)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (FcCharLeaf **)); +FC_ASSERT_STATIC (SIZEOF_VOID_P == sizeof (FcChar16 *)); + +FC_ASSERT_STATIC (0x08 + 1*FC_MAX(SIZEOF_VOID_P,ALIGNOF_DOUBLE) == sizeof (FcValue)); +FC_ASSERT_STATIC (0x00 + 2*SIZEOF_VOID_P == sizeof (FcPatternElt)); +FC_ASSERT_STATIC (0x08 + 2*SIZEOF_VOID_P == sizeof (FcPattern)); +FC_ASSERT_STATIC (0x08 + 2*SIZEOF_VOID_P == sizeof (FcCharSet)); +FC_ASSERT_STATIC (0x08 + 6*SIZEOF_VOID_P == sizeof (FcCache)); + + +int +main (int argc FC_UNUSED, char **argv FC_UNUSED) +{ + printf ("%s\n", FC_ARCHITECTURE); + return 0; +} diff --git a/chromium/third_party/fontconfig/src/src/fcarch.h b/chromium/third_party/fontconfig/src/src/fcarch.h new file mode 100644 index 00000000000..049a5b02b93 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcarch.h @@ -0,0 +1,76 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2010 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. + */ +#ifndef _FCARCH_H_ +#define _FCARCH_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* + * Each unique machine architecture needs an entry in this file + * So far the differences boil down to: endianness, 32 vs 64 bit pointers, + * and on 32bit ones, whether double is aligned to one word or two words. + * Those result in the 6 formats listed below. + * + * If any of the assertion errors in fcarch.c fail, you need to add a new + * architecture. Contact the fontconfig mailing list in that case. + * + * name endianness pointer-size double-alignment + * + * le32d4 4321 4 4 + * le32d8 4321 4 8 + * le64 4321 8 8 + * be32d4 1234 4 4 + * be32d8 1234 4 8 + * be64 1234 8 8 + */ + +#if defined(__DARWIN_BYTE_ORDER) && __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN +# define FC_ARCH_ENDIAN "le" +#elif defined(__DARWIN_BYTE_ORDER) && __DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN +# define FC_ARCH_ENDIAN "be" +#elif defined(__DARWIN_BYTE_ORDER) && __DARWIN_BYTE_ORDER == __DARWIN_PDP_ENDIAN +# define FC_ARCH_ENDIAN "pe" +#elif defined(WORDS_BIGENDIAN) && WORDS_BIGENDIAN +# define FC_ARCH_ENDIAN "be" +#else +# define FC_ARCH_ENDIAN "le" +#endif + +#if SIZEOF_VOID_P == 4 +# if ALIGNOF_DOUBLE == 4 +# define FC_ARCH_SIZE_ALIGN "32d4" +# else /* ALIGNOF_DOUBLE != 4 */ +# define FC_ARCH_SIZE_ALIGN "32d8" +# endif +#else /* SIZEOF_VOID_P != 4 */ +# define FC_ARCH_SIZE_ALIGN "64" +#endif + +/* config.h might override this */ +#ifndef FC_ARCHITECTURE +# define FC_ARCHITECTURE FC_ARCH_ENDIAN FC_ARCH_SIZE_ALIGN +#endif + +#endif /* _FCARCH_H_ */ diff --git a/chromium/third_party/fontconfig/src/src/fcatomic.c b/chromium/third_party/fontconfig/src/src/fcatomic.c new file mode 100644 index 00000000000..c1daed938e5 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcatomic.c @@ -0,0 +1,229 @@ +/* + * 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 <unistd.h> +#include <stdlib.h> +#include <time.h> + +#ifdef _WIN32 +#include <direct.h> +#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; + + 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 ret; + struct stat lck_stat; + +#ifdef HAVE_LINK + int fd = -1; + FILE *f = 0; + FcBool no_link = FcFalse; + + strcpy ((char *) atomic->tmp, (char *) atomic->file); + strcat ((char *) atomic->tmp, TMP_NAME); + fd = FcMakeTempfile ((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); + if (ret < 0 && errno == EPERM) + { + /* the filesystem where atomic->lck points to may not supports + * the hard link. so better try to fallback + */ + ret = mkdir ((char *) atomic->lck, 0600); + no_link = FcTrue; + } + (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 (no_link) + { + if (rmdir ((char *) atomic->lck) == 0) + return FcAtomicLock (atomic); + } + else + { + 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 ((const char *) 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 + if (unlink ((char *) atomic->lck) == -1) + rmdir ((char *) atomic->lck); +#else + rmdir ((char *) atomic->lck); +#endif +} + +void +FcAtomicDestroy (FcAtomic *atomic) +{ + free (atomic); +} +#define __fcatomic__ +#include "fcaliastail.h" +#undef __fcatomic__ diff --git a/chromium/third_party/fontconfig/src/src/fcatomic.h b/chromium/third_party/fontconfig/src/src/fcatomic.h new file mode 100644 index 00000000000..362e52164b7 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcatomic.h @@ -0,0 +1,145 @@ +/* + * Mutex operations. Originally copied from HarfBuzz. + * + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012,2013 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef _FCATOMIC_H_ +#define _FCATOMIC_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +/* atomic_int */ + +/* We need external help for these */ + +#if 0 + + +#elif !defined(FC_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__) + +#include "fcwindows.h" + +/* mingw32 does not have MemoryBarrier. + * MemoryBarrier may be defined as a macro or a function. + * Just make a failsafe version for ourselves. */ +#ifdef MemoryBarrier +#define HBMemoryBarrier MemoryBarrier +#else +static inline void HBMemoryBarrier (void) { + long dummy = 0; + InterlockedExchange (&dummy, 1); +} +#endif + +typedef LONG fc_atomic_int_t; +#define fc_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) + +#define fc_atomic_ptr_get(P) (HBMemoryBarrier (), (void *) *(P)) +#define fc_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) + + +#elif !defined(FC_NO_MT) && defined(__APPLE__) + +#include <libkern/OSAtomic.h> +#ifdef __MAC_OS_X_MIN_REQUIRED +#include <AvailabilityMacros.h> +#elif defined(__IPHONE_OS_MIN_REQUIRED) +#include <Availability.h> +#endif + +typedef int fc_atomic_int_t; +#define fc_atomic_int_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) + +#define fc_atomic_ptr_get(P) (OSMemoryBarrier (), (void *) *(P)) +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) +#define fc_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) +#else +#if __ppc64__ || __x86_64__ +#define fc_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) +#else +#define fc_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) +#endif +#endif + +#elif !defined(FC_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) + +typedef int fc_atomic_int_t; +#define fc_atomic_int_add(AI, V) __sync_fetch_and_add (&(AI), (V)) + +#define fc_atomic_ptr_get(P) (void *) (__sync_synchronize (), *(P)) +#define fc_atomic_ptr_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) + + +#elif !defined(FC_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS) + +#include <atomic.h> +#include <mbarrier.h> + +typedef unsigned int fc_atomic_int_t; +#define fc_atomic_int_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V)) + +#define fc_atomic_ptr_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P)) +#define fc_atomic_ptr_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((P), (O), (N)) == (void *) (O) ? FcTrue : FcFalse) + + +#elif !defined(FC_NO_MT) + +#define FC_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */ +typedef volatile int fc_atomic_int_t; +#define fc_atomic_int_add(AI, V) (((AI) += (V)) - (V)) + +#define fc_atomic_ptr_get(P) ((void *) *(P)) +#define fc_atomic_ptr_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), FcTrue) : FcFalse) + + +#else /* FC_NO_MT */ + +typedef int fc_atomic_int_t; +#define fc_atomic_int_add(AI, V) (((AI) += (V)) - (V)) + +#define fc_atomic_ptr_get(P) ((void *) *(P)) +#define fc_atomic_ptr_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), FcTrue) : FcFalse) + +#endif + +/* reference count */ +#define FC_REF_CONSTANT_VALUE ((fc_atomic_int_t) -1) +#define FC_REF_CONSTANT {FC_REF_CONSTANT_VALUE} +typedef struct _FcRef { fc_atomic_int_t count; } FcRef; +static inline void FcRefInit (FcRef *r, int v) { r->count = v; } +static inline int FcRefInc (FcRef *r) { return fc_atomic_int_add (r->count, +1); } +static inline int FcRefDec (FcRef *r) { return fc_atomic_int_add (r->count, -1); } +static inline int FcRefAdd (FcRef *r, int v) { return fc_atomic_int_add (r->count, v); } +static inline void FcRefSetConst (FcRef *r) { r->count = FC_REF_CONSTANT_VALUE; } +static inline FcBool FcRefIsConst (const FcRef *r) { return r->count == FC_REF_CONSTANT_VALUE; } + +#endif /* _FCATOMIC_H_ */ diff --git a/chromium/third_party/fontconfig/src/src/fcblanks.c b/chromium/third_party/fontconfig/src/src/fcblanks.c new file mode 100644 index 00000000000..46698bcdac3 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcblanks.c @@ -0,0 +1,87 @@ +/* + * 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; + b->nblank = 0; + b->sblank = 0; + b->blanks = 0; + return b; +} + +void +FcBlanksDestroy (FcBlanks *b) +{ + if (b->blanks) + free (b->blanks); + free (b); +} + +FcBool +FcBlanksAdd (FcBlanks *b, FcChar32 ucs4) +{ + FcChar32 *c; + int sblank; + + for (sblank = 0; sblank < b->nblank; sblank++) + if (b->blanks[sblank] == ucs4) + return FcTrue; + + if (b->nblank == b->sblank) + { + sblank = b->sblank + 32; + if (b->blanks) + c = (FcChar32 *) realloc (b->blanks, sblank * sizeof (FcChar32)); + else + c = (FcChar32 *) malloc (sblank * sizeof (FcChar32)); + if (!c) + return FcFalse; + b->sblank = sblank; + b->blanks = c; + } + b->blanks[b->nblank++] = ucs4; + return FcTrue; +} + +FcBool +FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4) +{ + int i; + + for (i = 0; i < b->nblank; i++) + if (b->blanks[i] == ucs4) + return FcTrue; + return FcFalse; +} +#define __fcblanks__ +#include "fcaliastail.h" +#undef __fcblanks__ diff --git a/chromium/third_party/fontconfig/src/src/fccache.c b/chromium/third_party/fontconfig/src/src/fccache.c new file mode 100644 index 00000000000..3568595eda5 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fccache.c @@ -0,0 +1,1464 @@ +/* + * 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 <stdlib.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)) + +static FcBool +FcCacheIsMmapSafe (int fd) +{ + enum { + MMAP_NOT_INITIALIZED = 0, + MMAP_USE, + MMAP_DONT_USE, + MMAP_CHECK_FS, + } status; + static void *static_status; + + status = (intptr_t) fc_atomic_ptr_get (&static_status); + + if (status == MMAP_NOT_INITIALIZED) + { + const char *env = getenv ("FONTCONFIG_USE_MMAP"); + FcBool use; + if (env && FcNameBool ((const FcChar8 *) env, &use)) + status = use ? MMAP_USE : MMAP_DONT_USE; + else + status = MMAP_CHECK_FS; + (void) fc_atomic_ptr_cmpexch (&static_status, NULL, (void *) status); + } + + if (status == MMAP_CHECK_FS) + return FcIsFsMmapSafe (fd); + else + return status == MMAP_USE; + +} + +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; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + + FcDirCacheBasename (dir, cache_base); + + list = FcStrListCreate (config->cacheDirs); + if (!list) + return FcFalse; + + while ((cache_dir = FcStrListNext (list))) + { + if (sysroot) + cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL); + else + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); + 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 = FcOpen((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 (FcStatChecksum (dir, &dir_stat) < 0) + return FcFalse; + + FcDirCacheBasename (dir, cache_base); + + list = FcStrListCreate (config->cacheDirs); + if (!list) + return FcFalse; + + while ((cache_dir = FcStrListNext (list))) + { + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *cache_hashed; + + if (sysroot) + cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL); + else + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); + 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; + FcRef 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 + +/* Protected by cache_lock below */ +static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL]; +static int fcCacheMaxLevel; + + +static FcMutex *cache_lock; + +static void +lock_cache (void) +{ + FcMutex *lock; +retry: + lock = fc_atomic_ptr_get (&cache_lock); + if (!lock) { + lock = (FcMutex *) malloc (sizeof (FcMutex)); + FcMutexInit (lock); + if (!fc_atomic_ptr_cmpexch (&cache_lock, NULL, lock)) { + FcMutexFinish (lock); + goto retry; + } + + FcMutexLock (lock); + /* Initialize random state */ + FcRandom (); + return; + } + FcMutexLock (lock); +} + +static void +unlock_cache (void) +{ + FcMutexUnlock (cache_lock); +} + +static void +free_lock (void) +{ + FcMutex *lock; + lock = fc_atomic_ptr_get (&cache_lock); + if (lock && fc_atomic_ptr_cmpexch (&cache_lock, lock, NULL)) { + FcMutexFinish (lock); + free (lock); + } +} + + + +/* + * 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; + + lock_cache (); + + /* + * 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; + FcRefInit (&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; + } + + unlock_cache (); + return FcTrue; +} + +static FcCacheSkip * +FcCacheFindByAddrUnlocked (void *object) +{ + int i; + FcCacheSkip **next = fcCacheChains; + FcCacheSkip *s; + + if (!object) + return NULL; + + /* + * 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 FcCacheSkip * +FcCacheFindByAddr (void *object) +{ + FcCacheSkip *ret; + lock_cache (); + ret = FcCacheFindByAddrUnlocked (object); + unlock_cache (); + return ret; +} + +static void +FcCacheRemoveUnlocked (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; + + lock_cache (); + 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) + { + FcRefInc (&s->ref); + unlock_cache (); + return s->cache; + } + unlock_cache (); + return NULL; +} + +static void +FcDirCacheDisposeUnlocked (FcCache *cache) +{ + FcCacheRemoveUnlocked (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; + } +} + +void +FcCacheObjectReference (void *object) +{ + FcCacheSkip *skip = FcCacheFindByAddr (object); + + if (skip) + FcRefInc (&skip->ref); +} + +void +FcCacheObjectDereference (void *object) +{ + FcCacheSkip *skip; + + lock_cache (); + skip = FcCacheFindByAddrUnlocked (object); + if (skip) + { + if (FcRefDec (&skip->ref) == 1) + FcDirCacheDisposeUnlocked (skip->cache); + } + unlock_cache (); +} + +void +FcCacheFini (void) +{ + int i; + + for (i = 0; i < FC_CACHE_MAX_LEVEL; i++) + assert (fcCacheChains[i] == NULL); + assert (fcCacheMaxLevel == 0); + + free_lock (); +} + +static FcBool +FcCacheTimeValid (FcCache *cache, struct stat *dir_stat) +{ + struct stat dir_static; + + if (!dir_stat) + { + if (FcStatChecksum (FcCacheDir (cache), &dir_static) < 0) + return FcFalse; + dir_stat = &dir_static; + } + if (FcDebug () & FC_DBG_CACHE) + printf ("FcCacheTimeValid dir \"%s\" cache checksum %d dir checksum %d\n", + FcCacheDir (cache), cache->checksum, (int) dir_stat->st_mtime); + return cache->checksum == (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 < (int) sizeof (FcCache)) + return NULL; + cache = FcCacheFindByStat (fd_stat); + if (cache) + { + if (FcCacheTimeValid (cache, dir_stat)) + return cache; + FcDirCacheUnload (cache); + cache = NULL; + } + + /* + * Large cache files are mmap'ed, smaller cache files are read. This + * balances the system cost of mmap against per-process memory usage. + */ + if (FcCacheIsMmapSafe (fd) && 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); +#ifdef HAVE_POSIX_FADVISE + posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED); +#endif + 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 != (intptr_t) 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) + FcRefAdd (&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 FC_UNUSED) +{ + 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.checksum != (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; + FcChar8 *dir_serialize; + intptr_t *dirs_serialize; + FcFontSet *set_serialize; + + if (!serialize) + return NULL; + /* + * Space for cache structure + */ + FcSerializeReserve (serialize, sizeof (FcCache)); + /* + * Directory name + */ + if (!FcStrSerializeAlloc (serialize, dir)) + goto bail1; + /* + * Subdirs + */ + 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->checksum = (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; +} + +/* 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, *d = NULL; + FcCacheSkip *skip; + struct stat cache_stat; + unsigned int magic; + int written; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + + /* + * 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 (d) + FcStrFree (d); + if (sysroot) + d = FcStrBuildFilename (sysroot, test_dir, NULL); + else + d = FcStrCopyFilename (test_dir); + + if (access ((char *) d, W_OK) == 0) + { + cache_dir = FcStrCopyFilename (d); + break; + } + else + { + /* + * If the directory doesn't exist, try to create it + */ + if (access ((char *) d, F_OK) == -1) { + if (FcMakeDirectory (d)) + { + cache_dir = FcStrCopyFilename (d); + /* Create CACHEDIR.TAG */ + FcDirCacheCreateTagFile (d); + break; + } + } + /* + * Otherwise, try making it writable + */ + else if (chmod ((char *) d, 0755) == 0) + { + cache_dir = FcStrCopyFilename (d); + /* Try to create CACHEDIR.TAG too */ + FcDirCacheCreateTagFile (d); + break; + } + } + } + if (d) + FcStrFree (d); + FcStrListDone (list); + if (!cache_dir) + return FcFalse; + + FcDirCacheBasename (dir, cache_base); + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); + if (!cache_hashed) + return FcFalse; + FcStrFree (cache_dir); + + 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 = FcOpen((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 && FcStat (cache_hashed, &cache_stat)) + { + lock_cache (); + if ((skip = FcCacheFindByAddrUnlocked (cache))) + { + skip->cache_dev = cache_stat.st_dev; + skip->cache_ino = cache_stat.st_ino; + skip->cache_mtime = cache_stat.st_mtime; + } + unlock_cache (); + } + + FcStrFree (cache_hashed); + FcAtomicUnlock (atomic); + FcAtomicDestroy (atomic); + return FcTrue; + + bail5: + close (fd); + bail4: + FcAtomicUnlock (atomic); + bail3: + FcAtomicDestroy (atomic); + bail1: + FcStrFree (cache_hashed); + return FcFalse; +} + +FcBool +FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) +{ + DIR *d; + struct dirent *ent; + FcChar8 *dir; + FcBool ret = FcTrue; + FcBool remove; + FcCache *cache; + struct stat target_stat; + const FcChar8 *sysroot; + + /* FIXME: this API needs to support non-current FcConfig */ + sysroot = FcConfigGetSysRoot (NULL); + if (sysroot) + dir = FcStrBuildFilename (sysroot, cache_dir, NULL); + else + dir = FcStrCopyFilename (cache_dir); + if (!dir) + { + fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir); + return FcFalse; + } + if (access ((char *) dir, W_OK) != 0) + { + if (verbose || FcDebug () & FC_DBG_CACHE) + printf ("%s: not cleaning %s cache directory\n", dir, + access ((char *) dir, F_OK) == 0 ? "unwritable" : "non-existent"); + goto bail0; + } + if (verbose || FcDebug () & FC_DBG_CACHE) + printf ("%s: cleaning cache directory\n", dir); + d = opendir ((char *) dir); + if (!d) + { + perror ((char *) dir); + ret = FcFalse; + goto bail0; + } + while ((ent = readdir (d))) + { + FcChar8 *file_name; + const FcChar8 *target_dir; + + if (ent->d_name[0] == '.') + continue; + /* skip cache files for different architectures and */ + /* files which are not cache files at all */ + if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) || + strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX)) + continue; + + file_name = FcStrBuildFilename (dir, (FcChar8 *)ent->d_name, NULL); + if (!file_name) + { + fprintf (stderr, "Fontconfig error: %s: allocation failure\n", dir); + ret = FcFalse; + break; + } + remove = FcFalse; + cache = FcDirCacheLoadFile (file_name, NULL); + if (!cache) + { + if (verbose || FcDebug () & FC_DBG_CACHE) + printf ("%s: invalid cache file: %s\n", dir, ent->d_name); + remove = FcTrue; + } + else + { + target_dir = FcCacheDir (cache); + if (stat ((char *) target_dir, &target_stat) < 0) + { + if (verbose || FcDebug () & FC_DBG_CACHE) + printf ("%s: %s: missing directory: %s \n", + dir, ent->d_name, target_dir); + remove = FcTrue; + } + FcDirCacheUnload (cache); + } + if (remove) + { + if (unlink ((char *) file_name) < 0) + { + perror ((char *) file_name); + ret = FcFalse; + } + } + FcStrFree (file_name); + } + + closedir (d); + bail0: + FcStrFree (dir); + + return ret; +} + +/* + * 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; +} + +FcBool +FcDirCacheCreateTagFile (const FcChar8 *cache_dir) +{ + FcChar8 *cache_tag; + int fd; + FILE *fp; + FcAtomic *atomic; + static const FcChar8 cache_tag_contents[] = + "Signature: 8a477f597d28d172789f06886806bc55\n" + "# This file is a cache directory tag created by fontconfig.\n" + "# For information about cache directory tags, see:\n" + "# http://www.brynosaurus.com/cachedir/\n"; + static size_t cache_tag_contents_size = sizeof (cache_tag_contents) - 1; + FcBool ret = FcFalse; + + if (!cache_dir) + return FcFalse; + + if (access ((char *) cache_dir, W_OK) == 0) + { + /* Create CACHEDIR.TAG */ + cache_tag = FcStrBuildFilename (cache_dir, "CACHEDIR.TAG", NULL); + if (!cache_tag) + return FcFalse; + atomic = FcAtomicCreate ((FcChar8 *)cache_tag); + if (!atomic) + goto bail1; + if (!FcAtomicLock (atomic)) + goto bail2; + fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644); + if (fd == -1) + goto bail3; + fp = fdopen(fd, "wb"); + if (fp == NULL) + goto bail3; + + fwrite(cache_tag_contents, cache_tag_contents_size, sizeof (FcChar8), fp); + fclose(fp); + + if (!FcAtomicReplaceOrig(atomic)) + goto bail3; + + ret = FcTrue; + bail3: + FcAtomicUnlock (atomic); + bail2: + FcAtomicDestroy (atomic); + bail1: + FcStrFree (cache_tag); + } + + if (FcDebug () & FC_DBG_CACHE) + { + if (ret) + printf ("Created CACHEDIR.TAG at %s\n", cache_dir); + else + printf ("Unable to create CACHEDIR.TAG at %s\n", cache_dir); + } + + return ret; +} + +void +FcCacheCreateTagFile (const FcConfig *config) +{ + FcChar8 *cache_dir = NULL, *d = NULL; + FcStrList *list; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + + list = FcConfigGetCacheDirs (config); + if (!list) + return; + + while ((cache_dir = FcStrListNext (list))) + { + if (d) + FcStrFree (d); + if (sysroot) + d = FcStrBuildFilename (sysroot, cache_dir, NULL); + else + d = FcStrCopyFilename (cache_dir); + if (FcDirCacheCreateTagFile (d)) + break; + } + if (d) + FcStrFree (d); + FcStrListDone (list); +} + +#define __fccache__ +#include "fcaliastail.h" +#undef __fccache__ diff --git a/chromium/third_party/fontconfig/src/src/fccfg.c b/chromium/third_party/fontconfig/src/src/fccfg.c new file mode 100644 index 00000000000..6377fd7c6b1 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fccfg.c @@ -0,0 +1,2352 @@ +/* + * 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. + */ + +/* Objects MT-safe for readonly access. */ + +#include "fcint.h" +#include <dirent.h> +#include <sys/types.h> + +#if defined (_WIN32) && !defined (R_OK) +#define R_OK 4 +#endif + +static FcConfig *_fcConfig; /* MT-safe */ + +static FcConfig * +FcConfigEnsure (void) +{ + FcConfig *config; +retry: + config = fc_atomic_ptr_get (&_fcConfig); + if (!config) + { + config = FcInitLoadConfigAndFonts (); + + if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { + FcConfigDestroy (config); + goto retry; + } + } + return config; +} + +FcBool +FcConfigInit (void) +{ + return FcConfigEnsure () ? FcTrue : FcFalse; +} + +void +FcConfigFini (void) +{ + FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); + if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) + FcConfigDestroy (cfg); +} + + +FcConfig * +FcConfigCreate (void) +{ + FcSetName set; + FcConfig *config; + + config = malloc (sizeof (FcConfig)); + if (!config) + goto bail0; + + 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->sysRoot = NULL; + + FcRefInit (&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); +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->rule) + FcRuleDestroy (s->rule); + free (s); + 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; + + 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; + } + + FcRefInc (&config->ref); + + return config; +} + +void +FcConfigDestroy (FcConfig *config) +{ + FcSetName set; + FcExprPage *page; + + if (FcRefDec (&config->ref) != 1) + return; + + (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); + + 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; + free (page); + page = next; + } + if (config->sysRoot) + FcStrFree (config->sysRoot); + + free (config); +} + +/* + * 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; + + if (FcFontSetAdd (config->fonts[set], font)) + nref++; + } + 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) +{ + FcConfig *cfg; + +retry: + cfg = fc_atomic_ptr_get (&_fcConfig); + + if (config == cfg) + return FcTrue; + + if (config && !config->fonts[FcSetSystem]) + if (!FcConfigBuildFonts (config)) + return FcFalse; + + if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) + goto retry; + + if (cfg) + FcConfigDestroy (cfg); + + return FcTrue; +} + +FcConfig * +FcConfigGetCurrent (void) +{ + return FcConfigEnsure (); +} + +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 (const 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 FC_UNUSED) +{ + 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 +FcConfigAddRule (FcConfig *config, + FcRule *rule, + FcMatchKind kind) +{ + FcSubst *subst, **prev; + FcRule *r; + int n = 0; + + if (!rule) + return FcFalse; + 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; + for (; *prev; prev = &(*prev)->next); + *prev = subst; + subst->next = NULL; + subst->rule = rule; + for (r = rule; r; r = r->next) + { + switch (r->type) + { + case FcRuleTest: + if (r->u.test && + r->u.test->kind == FcMatchDefault) + r->u.test->kind = kind; + + if (n < r->u.test->object) + n = r->u.test->object; + break; + case FcRuleEdit: + if (n < r->u.edit->object) + n = r->u.edit->object; + break; + default: + break; + } + } + n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; + if (config->maxObjects < n) + config->maxObjects = n; + if (FcDebug () & FC_DBG_EDIT) + { + printf ("Add Subst "); + FcSubstPrint (subst); + } + return FcTrue; +} + +static FcValue +FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) +{ + 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 (buf && v.type == FcTypeString && u.type == FcTypeLangSet) + { + v.u.l = FcLangSetPromote (v.u.s, buf); + v.type = FcTypeLangSet; + } + return v; +} + +FcBool +FcConfigCompareValue (const FcValue *left_o, + unsigned int op_, + const FcValue *right_o) +{ + FcValue left = FcValueCanonicalize(left_o); + FcValue right = FcValueCanonicalize(right_o); + FcBool ret = FcFalse; + FcOp op = FC_OP_GET_OP (op_); + int flags = FC_OP_GET_FLAGS (op_); + FcValuePromotionBuffer buf1, buf2; + + left = FcConfigPromote (left, right, &buf1); + right = FcConfigPromote (right, left, &buf2); + if (left.type == right.type) + { + switch (left.type) { + case FcTypeUnknown: + break; /* No way to guess how to compare for this object */ + case FcTypeInteger: + break; /* FcConfigPromote prevents this from happening */ + case FcTypeDouble: + switch ((int) 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 ((int) 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 ((int) op) { + case FcOpEqual: + case FcOpListing: + if (flags & FcOpFlagIgnoreBlanks) + ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; + else + ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; + break; + case FcOpContains: + ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; + break; + case FcOpNotEqual: + if (flags & FcOpFlagIgnoreBlanks) + ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; + else + 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 ((int) 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 ((int) 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 ((int) 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 ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + ret = FcTrue; + break; + default: + break; + } + break; + case FcTypeFTFace: + switch ((int) op) { + case FcOpEqual: + case FcOpContains: + case FcOpListing: + 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, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) +{ + FcValue v, vl, vr; + FcMatrix *m; + FcChar8 *str; + FcOp op = FC_OP_GET_OP (e->op); + + switch ((int) 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: + { + FcMatrix m; + FcValue xx, xy, yx, yy; + v.type = FcTypeMatrix; + xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); + xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); + yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); + yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); + if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && + yx.type == FcTypeDouble && yy.type == FcTypeDouble) + { + m.xx = xx.u.d; + m.xy = xy.u.d; + m.yx = yx.u.d; + m.yy = yy.u.d; + v.u.m = &m; + } + else + v.type = FcTypeVoid; + v = FcValueSave (v); + } + 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: + if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) + { + if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) + v.type = FcTypeVoid; + } + else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) + { + fprintf (stderr, + "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); + v.type = FcTypeVoid; + } + else + { + if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) + 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, p_pat, kind, e->u.tree.left); + if (vl.type == FcTypeBool) + { + if (vl.u.b) + v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); + else + v = FcConfigEvaluate (p, p_pat, kind, 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, p_pat, kind, e->u.tree.left); + vr = FcConfigEvaluate (p, p_pat, kind, 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, p_pat, kind, e->u.tree.left); + vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); + vl = FcConfigPromote (vl, vr, NULL); + vr = FcConfigPromote (vr, vl, NULL); + if (vl.type == vr.type) + { + switch ((int) vl.type) { + case FcTypeDouble: + switch ((int) 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 ((int) 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 ((int) op) { + case FcOpPlus: + v.type = FcTypeString; + str = FcStrPlus (vl.u.s, vr.u.s); + v.u.s = FcStrdup (str); + FcStrFree (str); + + if (!v.u.s) + v.type = FcTypeVoid; + break; + default: + v.type = FcTypeVoid; + break; + } + break; + case FcTypeMatrix: + switch ((int) op) { + case FcOpTimes: + v.type = FcTypeMatrix; + m = malloc (sizeof (FcMatrix)); + if (m) + { + 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 ((int) 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 ((int) 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, p_pat, kind, e->u.tree.left); + switch ((int) 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, p_pat, kind, e->u.tree.left); + switch ((int) 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, p_pat, kind, e->u.tree.left); + switch ((int) 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, p_pat, kind, e->u.tree.left); + switch ((int) 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, p_pat, kind, e->u.tree.left); + switch ((int) 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, + FcPattern *p_pat, + FcMatchKind kind, + 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 (FC_OP_GET_OP (e->op) == FcOpComma) + { + value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); + e = e->u.tree.right; + } + else + { + value = FcConfigEvaluate (p, p_pat, kind, 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, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) +{ + FcValueList *l; + + if (!e) + return 0; + l = (FcValueList *) malloc (sizeof (FcValueList)); + if (!l) + return 0; + if (FC_OP_GET_OP (e->op) == FcOpComma) + { + l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); + l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); + } + else + { + l->value = FcConfigEvaluate (p, p_pat, kind, e); + l->next = NULL; + } + l->binding = binding; + if (l->value.type == FcTypeVoid) + { + FcValueList *next = FcValueListNext(l); + + free (l); + l = next; + } + + return l; +} + +static FcBool +FcConfigAdd (FcValueListPtr *head, + FcValueList *position, + FcBool append, + FcValueList *new, + FcObject object) +{ + FcValueListPtr *prev, l, last, v; + FcValueBinding sameBinding; + + /* + * Make sure the stored type is valid for built-in objects + */ + for (l = new; l != NULL; l = FcValueListNext (l)) + { + if (!FcObjectValidType (object, l->value.type)) + { + fprintf (stderr, + "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); + FcValuePrintFile (stderr, l->value); + fprintf (stderr, "\n"); + + if (FcDebug () & FC_DBG_EDIT) + { + printf ("Not adding\n"); + } + + return FcFalse; + } + } + + 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"); + FcValueListPrintWithPosition (*head, *prev); + 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, object); + } +} + +/* + * 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) +{ + FcValue v; + FcSubst *s; + FcRule *r; + FcValueList *l, **value = NULL, *vl; + FcPattern *m; + FcStrSet *strs; + FcObject object = FC_INVALID_OBJECT; + FcPatternElt **elt = NULL, *e; + int i, nobjs; + FcBool retval = FcTrue; + FcTest **tst = NULL; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + + switch (kind) { + case FcMatchPattern: + s = config->substPattern; + strs = FcGetDefaultLangs (); + if (strs) + { + FcStrList *l = FcStrListCreate (strs); + FcChar8 *lang; + FcValue v; + + FcStrSetDestroy (strs); + while (l && (lang = FcStrListNext (l))) + { + v.type = FcTypeString; + v.u.s = lang; + FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); + } + FcStrListDone (l); + } + if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) + { + FcChar8 *prgname = FcGetPrgname (); + if (prgname) + FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); + } + break; + case FcMatchFont: + s = config->substFont; + break; + case FcMatchScan: + s = config->substScan; + break; + default: + return FcFalse; + } + + nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; + value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs); + if (!value) + { + retval = FcFalse; + goto bail1; + } + elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs); + if (!elt) + { + retval = FcFalse; + goto bail1; + } + tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs); + if (!tst) + { + retval = FcFalse; + goto bail1; + } + + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute "); + FcPatternPrint (p); + } + for (; s; s = s->next) + { + r = s->rule; + for (i = 0; i < nobjs; i++) + { + elt[i] = NULL; + value[i] = NULL; + tst[i] = NULL; + } + for (; r; r = r->next) + { + switch (r->type) { + case FcRuleUnknown: + /* shouldn't be reached */ + break; + case FcRuleTest: + object = FC_OBJ_ID (r->u.test->object); + /* + * Check the tests to see if + * they all match the pattern + */ + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute test "); + FcTestPrint (r->u.test); + } + if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) + m = p_pat; + else + m = p; + if (m) + e = FcPatternObjectFindElt (m, r->u.test->object); + else + e = NULL; + /* different 'kind' won't be the target of edit */ + if (!elt[object] && kind == r->u.test->kind) + { + elt[object] = e; + tst[object] = r->u.test; + } + /* + * If there's no such field in the font, + * then FcQualAll matches while FcQualAny does not + */ + if (!e) + { + if (r->u.test->qual == FcQualAll) + { + value[object] = NULL; + continue; + } + else + { + if (FcDebug () & FC_DBG_EDIT) + printf ("No match\n"); + goto bail; + } + } + /* + * Check to see if there is a match, mark the location + * to apply match-relative edits + */ + vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); + /* different 'kind' won't be the target of edit */ + if (!value[object] && kind == r->u.test->kind) + value[object] = vl; + if (!vl || + (r->u.test->qual == FcQualFirst && vl != e->values) || + (r->u.test->qual == FcQualNotFirst && vl == e->values)) + { + if (FcDebug () & FC_DBG_EDIT) + printf ("No match\n"); + goto bail; + } + break; + case FcRuleEdit: + object = FC_OBJ_ID (r->u.edit->object); + if (FcDebug () & FC_DBG_EDIT) + { + printf ("Substitute "); + FcEditPrint (r->u.edit); + printf ("\n\n"); + } + /* + * Evaluate the list of expressions + */ + l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); + if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) + elt[object] = FcPatternObjectFindElt (p, tst[object]->object); + + switch (FC_OP_GET_OP (r->u.edit->op)) { + case FcOpAssign: + /* + * If there was a test, then replace the matched + * value with the new list of values + */ + if (value[object]) + { + FcValueList *thisValue = value[object]; + FcValueList *nextValue = l; + + /* + * Append the new list of values after the current value + */ + FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); + /* + * Delete the marked value + */ + if (thisValue) + FcConfigDel (&elt[object]->values, thisValue); + /* + * Adjust a pointer into the value list to ensure + * future edits occur at the same place + */ + value[object] = nextValue; + break; + } + /* fall through ... */ + case FcOpAssignReplace: + /* + * Delete all of the values and insert + * the new set + */ + FcConfigPatternDel (p, r->u.edit->object); + FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); + /* + * Adjust a pointer into the value list as they no + * longer point to anything valid + */ + value[object] = NULL; + break; + case FcOpPrepend: + if (value[object]) + { + FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); + break; + } + /* fall through ... */ + case FcOpPrependFirst: + FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); + break; + case FcOpAppend: + if (value[object]) + { + FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); + break; + } + /* fall through ... */ + case FcOpAppendLast: + FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); + break; + case FcOpDelete: + if (value[object]) + { + FcConfigDel (&elt[object]->values, value[object]); + break; + } + /* fall through ... */ + case FcOpDeleteAll: + FcConfigPatternDel (p, r->u.edit->object); + break; + default: + FcValueListDestroy (l); + break; + } + /* + * Now go through the pattern and eliminate + * any properties without data + */ + FcConfigPatternCanon (p, r->u.edit->object); + + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute edit"); + FcPatternPrint (p); + } + break; + } + } + bail:; + } + if (FcDebug () & FC_DBG_EDIT) + { + printf ("FcConfigSubstitute done"); + FcPatternPrint (p); + } +bail1: + if (elt) + free (elt); + if (value) + free (value); + if (tst) + free (tst); + + return retval; +} + +FcBool +FcConfigSubstitute (FcConfig *config, + FcPattern *p, + FcMatchKind kind) +{ + return FcConfigSubstituteWithPat (config, p, 0, kind); +} + +#if defined (_WIN32) + +static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ + +# if (defined (PIC) || defined (DLL_EXPORT)) + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved); + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + FcChar8 *p; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) 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 = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); + if (p) + { + *p = '\0'; + p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); + if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || + FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) + *p = '\0'; + strcat ((char *) 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, osize; + + if (!dir) + dir = (FcChar8 *) ""; + + osize = 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 = (osize + 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, "/"); + else + osize--; +#endif + strcat ((char *) path, (char *) file); + + 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, (LPCH) fontconfig_path, sizeof(fontconfig_path))) + goto bail1; + p = strrchr ((const char *) fontconfig_path, '\\'); + if (p) *p = '\0'; + strcat ((char *) 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; /* MT-goodenough */ + +FcChar8 * +FcConfigHome (void) +{ + if (_FcConfigHomeEnabled) + { + char *home = getenv ("HOME"); + +#ifdef _WIN32 + if (home == NULL) + home = getenv ("USERPROFILE"); +#endif + + return (FcChar8 *) home; + } + return 0; +} + +FcChar8 * +FcConfigXdgCacheHome (void) +{ + const char *env = getenv ("XDG_CACHE_HOME"); + FcChar8 *ret = NULL; + + if (env) + ret = FcStrCopy ((const FcChar8 *)env); + else + { + const FcChar8 *home = FcConfigHome (); + size_t len = home ? strlen ((const char *)home) : 0; + + ret = malloc (len + 7 + 1); + if (ret) + { + memcpy (ret, home, len); + memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); + ret[len + 7] = 0; + } + } + + return ret; +} + +FcChar8 * +FcConfigXdgConfigHome (void) +{ + const char *env = getenv ("XDG_CONFIG_HOME"); + FcChar8 *ret = NULL; + + if (env) + ret = FcStrCopy ((const FcChar8 *)env); + else + { + const FcChar8 *home = FcConfigHome (); + size_t len = home ? strlen ((const char *)home) : 0; + + ret = malloc (len + 8 + 1); + if (ret) + { + memcpy (ret, home, len); + memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); + ret[len + 8] = 0; + } + } + + return ret; +} + +FcChar8 * +FcConfigXdgDataHome (void) +{ + const char *env = getenv ("XDG_DATA_HOME"); + FcChar8 *ret = NULL; + + if (env) + ret = FcStrCopy ((const FcChar8 *)env); + else + { + const FcChar8 *home = FcConfigHome (); + size_t len = home ? strlen ((const char *)home) : 0; + + ret = malloc (len + 13 + 1); + if (ret) + { + memcpy (ret, home, len); + memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); + ret[len + 13] = 0; + } + } + + return ret; +} + +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 NULL; + 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 +FcConfigGlobsMatch (const FcStrSet *globs, + const FcChar8 *string) +{ + int i; + + for (i = 0; i < globs->num; i++) + if (FcStrGlobMatch (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; +} + +const FcChar8 * +FcConfigGetSysRoot (const FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return NULL; + } + + return config->sysRoot; +} + +void +FcConfigSetSysRoot (FcConfig *config, + const FcChar8 *sysroot) +{ + FcChar8 *s; + FcBool init = FcFalse; + + if (!config) + { + /* We can't use FcConfigGetCurrent() here to ensure + * the sysroot is set prior to initialize FcConfig, + * to avoid loading caches from non-sysroot dirs. + * So postpone the initialization later. + */ + config = fc_atomic_ptr_get (&_fcConfig); + if (!config) + { + config = FcConfigCreate (); + if (!config) + return; + init = FcTrue; + } + } + + s = FcStrCopyFilename (sysroot); + if (!s) + return; + + if (config->sysRoot) + FcStrFree (config->sysRoot); + + config->sysRoot = s; + if (init) + { + config = FcInitLoadOwnConfigAndFonts (config); + FcConfigSetCurrent (config); + } +} + +#define __fccfg__ +#include "fcaliastail.h" +#undef __fccfg__ diff --git a/chromium/third_party/fontconfig/src/src/fccharset.c b/chromium/third_party/fontconfig/src/src/fccharset.c new file mode 100644 index 00000000000..c9f928cd480 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fccharset.c @@ -0,0 +1,1434 @@ +/* + * 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; + FcRefInit (&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) + { + if (FcRefIsConst (&fcs->ref)) + { + FcCacheObjectDereference (fcs); + return; + } + if (FcRefDec (&fcs->ref) != 1) + return; + for (i = 0; i < fcs->num; i++) + free (FcCharSetLeaf (fcs, i)); + if (fcs->num) + { + free (FcCharSetLeaves (fcs)); + free (FcCharSetNumbers (fcs)); + } + 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)); + } + else + { + unsigned int alloced = fcs->num; + intptr_t *new_leaves, distance; + + alloced *= 2; + new_leaves = realloc (leaves, alloced * sizeof (*leaves)); + numbers = realloc (numbers, 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; + } + return leaf; +} + +static FcBool +FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf) +{ + int pos; + + pos = FcCharSetFindLeafPos (fcs, ucs4); + if (pos >= 0) + { + 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 == NULL || FcRefIsConst (&fcs->ref)) + 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 == NULL || FcRefIsConst (&fcs->ref)) + 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) + { + if (!FcRefIsConst (&src->ref)) + FcRefInc (&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; + if (!a || !b) + return FcFalse; + 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; + + if (!a || !b) + goto bail0; + 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 || !b) + return FcFalse; + + if (FcRefIsConst (&a->ref)) { + 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; + + if (!fcs) + return FcFalse; + 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; + + if (a && b) + { + 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; + + if (a) + { + 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; + + if (a && b) + { + 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; + if (!a || !b) + return FcFalse; + 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; + + if (!a) + return FC_CHARSET_DONE; + 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) + { + free (FcCharSetLeaves (c)); + } + if (c->num) + { + free (FcCharSetNumbers (c)); + } + 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; + 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) +{ + 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; + + freezer->charsets_allocated++; + + FcRefSetConst (&ent->set.ref); + 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); + if (!FcCharSetFreezeOrig (freezer, fcs, n)) + { + n = NULL; + goto bail1; + } + freezer->charsets_seen++; + freezer->leaves_seen += fcs->num; +bail1: + if (b->num) + free (FcCharSetLeaves (b)); + if (b->num) + free (FcCharSetNumbers (b)); + 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; + 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]); + + free (freezer->leaf_blocks); + free (freezer); +} + +FcBool +FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs) +{ + intptr_t *leaves; + FcChar16 *numbers; + int i; + + if (!FcRefIsConst (&cs->ref)) + { + 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 (!FcRefIsConst (&cs->ref) && serialize->cs_freezer) + { + cs = FcCharSetFindFrozen (serialize->cs_freezer, cs); + if (!cs) + return NULL; + } + + cs_serialized = FcSerializePtr (serialize, cs); + if (!cs_serialized) + return NULL; + + FcRefSetConst (&cs_serialized->ref); + 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/chromium/third_party/fontconfig/src/src/fccompat.c b/chromium/third_party/fontconfig/src/src/fccompat.c new file mode 100644 index 00000000000..1c2ba8bedde --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fccompat.c @@ -0,0 +1,244 @@ +/* + * fontconfig/src/fccompat.c + * + * Copyright © 2012 Red Hat, Inc. + * + * Author(s): + * Akira TAGOH + * + * 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 <errno.h> +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifdef O_CLOEXEC +#define FC_O_CLOEXEC O_CLOEXEC +#else +#define FC_O_CLOEXEC 0 +#endif +#ifdef O_LARGEFILE +#define FC_O_LARGEFILE O_LARGEFILE +#else +#define FC_O_LARGEFILE 0 +#endif +#ifdef O_BINARY +#define FC_O_BINARY O_BINARY +#else +#define FC_O_BINARY 0 +#endif +#ifdef O_TEMPORARY +#define FC_O_TEMPORARY O_TEMPORARY +#else +#define FC_O_TEMPORARY 0 +#endif +#ifdef O_NOINHERIT +#define FC_O_NOINHERIT O_NOINHERIT +#else +#define FC_O_NOINHERIT 0 +#endif + +#if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S) +static int +mkstemp (char *template) +{ + static const char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int fd, i; + size_t l; + + if (template == NULL) + { + errno = EINVAL; + return -1; + } + l = strlen (template); + if (l < 6 || strcmp (&template[l - 6], "XXXXXX") != 0) + { + errno = EINVAL; + return -1; + } + do + { + errno = 0; + for (i = l - 6; i < l; i++) + { + int r = FcRandom (); + template[i] = s[r % 62]; + } + fd = FcOpen (template, FC_O_BINARY | O_CREAT | O_EXCL | FC_O_TEMPORARY | FC_O_NOINHERIT | O_RDWR, 0600); + } while (fd < 0 && errno == EEXIST); + if (fd >= 0) + errno = 0; + + return fd; +} +#define HAVE_MKSTEMP 1 +#endif + +int +FcOpen(const char *pathname, int flags, ...) +{ + int fd = -1; + + if (flags & O_CREAT) + { + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = (mode_t) va_arg(ap, int); + va_end(ap); + + fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE, mode); + } + else + { + fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE); + } + + return fd; +} + +int +FcMakeTempfile (char *template) +{ + int fd = -1; + +#if HAVE_MKOSTEMP + fd = mkostemp (template, FC_O_CLOEXEC); +#elif HAVE_MKSTEMP + fd = mkstemp (template); +# ifdef F_DUPFD_CLOEXEC + if (fd != -1) + { + int newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDIN_FILENO); + + close(fd); + fd = newfd; + } +# elif defined(FD_CLOEXEC) + if (fd != -1) + { + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + } +# endif +#elif HAVE__MKTEMP_S + if (_mktemp_s(template, strlen(template) + 1) != 0) + return -1; + fd = FcOpen(template, O_RDWR | O_EXCL | O_CREAT, 0600); +#endif + + return fd; +} + +int32_t +FcRandom(void) +{ + int32_t result; + +#if HAVE_RANDOM_R + static struct random_data fcrandbuf; + static char statebuf[256]; + static FcBool initialized = FcFalse; + + if (initialized != FcTrue) + { + initstate_r(time(NULL), statebuf, 256, &fcrandbuf); + initialized = FcTrue; + } + + random_r(&fcrandbuf, &result); +#elif HAVE_RANDOM + static char statebuf[256]; + char *state; + static FcBool initialized = FcFalse; + + if (initialized != FcTrue) + { + state = initstate(time(NULL), statebuf, 256); + initialized = FcTrue; + } + else + state = setstate(statebuf); + + result = random(); + + setstate(state); +#elif HAVE_LRAND48 + result = lrand48(); +#elif HAVE_RAND_R + static unsigned int seed = time(NULL); + + result = rand_r(&seed); +#elif HAVE_RAND + static FcBool initialized = FcFalse; + + if (initialized != FcTrue) + { + srand(time(NULL)); + initialized = FcTrue; + } + result = rand(); +#else +# error no random number generator function available. +#endif + + return result; +} + +#ifdef _WIN32 +#include <direct.h> +#define mkdir(path,mode) _mkdir(path) +#endif + +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; +} diff --git a/chromium/third_party/fontconfig/src/src/fcdbg.c b/chromium/third_party/fontconfig/src/src/fcdbg.c new file mode 100644 index 00000000000..d74bc276940 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcdbg.c @@ -0,0 +1,499 @@ +/* + * 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> + +static void +_FcValuePrintFile (FILE *f, const FcValue v) +{ + switch (v.type) { + case FcTypeUnknown: + fprintf (f, "<unknown>"); + break; + case FcTypeVoid: + fprintf (f, "<void>"); + break; + case FcTypeInteger: + fprintf (f, "%d(i)", v.u.i); + break; + case FcTypeDouble: + fprintf (f, "%g(f)", v.u.d); + break; + case FcTypeString: + fprintf (f, "\"%s\"", v.u.s); + break; + case FcTypeBool: + fprintf (f, "%s", v.u.b ? "True" : "False"); + break; + case FcTypeMatrix: + fprintf (f, "[%g %g; %g %g]", v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy); + break; + case FcTypeCharSet: /* XXX */ + if (f == stdout) + FcCharSetPrint (v.u.c); + break; + case FcTypeLangSet: + FcLangSetPrint (v.u.l); + break; + case FcTypeFTFace: + fprintf (f, "face"); + break; + } +} + +void +FcValuePrintFile (FILE *f, const FcValue v) +{ + fprintf (f, " "); + _FcValuePrintFile (f, v); +} + +void +FcValuePrint (const FcValue v) +{ + printf (" "); + _FcValuePrintFile (stdout, v); +} + +void +FcValuePrintWithPosition (const FcValue v, FcBool show_pos_mark) +{ + if (show_pos_mark) + printf (" [marker] "); + else + printf (" "); + _FcValuePrintFile (stdout, v); +} + +static void +FcValueBindingPrint (const FcValueListPtr l) +{ + switch (l->binding) { + case FcValueBindingWeak: + printf ("(w)"); + break; + case FcValueBindingStrong: + printf ("(s)"); + break; + case FcValueBindingSame: + printf ("(=)"); + break; + default: + /* shouldn't be reached */ + printf ("(?)"); + break; + } +} + +void +FcValueListPrintWithPosition (FcValueListPtr l, const FcValueListPtr pos) +{ + for (; l != NULL; l = FcValueListNext(l)) + { + FcValuePrintWithPosition (FcValueCanonicalize (&l->value), pos != NULL && l == pos); + FcValueBindingPrint (l); + } + if (!pos) + printf (" [marker]"); +} + +void +FcValueListPrint (FcValueListPtr l) +{ + for (; l != NULL; l = FcValueListNext(l)) + { + FcValuePrint (FcValueCanonicalize (&l->value)); + FcValueBindingPrint (l); + } +} + +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"); +} + +#define FcOpFlagsPrint(_o_) \ + { \ + int f = FC_OP_GET_FLAGS (_o_); \ + if (f & FcOpFlagIgnoreBlanks) \ + printf ("(ignore blanks)"); \ + } + +void +FcOpPrint (FcOp op_) +{ + FcOp op = FC_OP_GET_OP (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 FcOpDelete: printf ("Delete"); break; + case FcOpDeleteAll: printf ("DeleteAll"); break; + case FcOpQuest: printf ("Quest"); break; + case FcOpOr: printf ("Or"); break; + case FcOpAnd: printf ("And"); break; + case FcOpEqual: printf ("Equal"); FcOpFlagsPrint (op_); break; + case FcOpNotEqual: printf ("NotEqual"); FcOpFlagsPrint (op_); 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"); FcOpFlagsPrint (op_); break; + case FcOpInvalid: printf ("Invalid"); break; + } +} + +void +FcExprPrint (const FcExpr *expr) +{ + if (!expr) printf ("none"); + else switch (FC_OP_GET_OP (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 ("["); + FcExprPrint (expr->u.mexpr->xx); + printf (" "); + FcExprPrint (expr->u.mexpr->xy); + printf ("; "); + FcExprPrint (expr->u.mexpr->yx); + printf (" "); + FcExprPrint (expr->u.mexpr->yy); + printf ("]"); + 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.name.object)); + switch ((int) expr->u.name.kind) { + case FcMatchPattern: + printf ("(pattern) "); + break; + case FcMatchFont: + printf ("(font) "); + break; + } + 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 (FC_OP_GET_OP (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"); FcOpFlagsPrint (expr->op); break; + case FcOpNotEqual: printf ("NotEqual"); FcOpFlagsPrint (expr->op); 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"); FcOpFlagsPrint (expr->op); 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) +{ + FcRule *r; + FcRuleType last_type = FcRuleUnknown; + + printf ("match\n"); + for (r = subst->rule; r; r = r->next) + { + if (last_type != r->type) + { + switch (r->type) { + case FcRuleTest: + printf ("[test]\n"); + break; + case FcRuleEdit: + printf ("[edit]\n"); + break; + default: + break; + } + last_type = r->type; + } + printf ("\t"); + switch (r->type) { + case FcRuleTest: + FcTestPrint (r->u.test); + break; + case FcRuleEdit: + FcEditPrint (r->u.edit); + printf (";\n"); + break; + default: + break; + } + } + 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) +{ + if (!FcDebugVal) { + 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/chromium/third_party/fontconfig/src/src/fcdefault.c b/chromium/third_party/fontconfig/src/src/fcdefault.c new file mode 100644 index 00000000000..d1b917fd9de --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcdefault.c @@ -0,0 +1,314 @@ +/* + * 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 <limits.h> +#include <string.h> + +/* MT-safe */ + +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]) + +FcStrSet *default_langs; + +FcStrSet * +FcGetDefaultLangs (void) +{ + FcStrSet *result; +retry: + result = (FcStrSet *) fc_atomic_ptr_get (&default_langs); + if (!result) + { + char *langs; + + result = FcStrSetCreate (); + + langs = getenv ("FC_LANG"); + if (!langs || !langs[0]) + langs = getenv ("LC_ALL"); + if (!langs || !langs[0]) + langs = getenv ("LC_CTYPE"); + if (!langs || !langs[0]) + langs = getenv ("LANG"); + if (langs && langs[0]) + { + if (!FcStrSetAddLangs (result, langs)) + FcStrSetAdd (result, (const FcChar8 *) "en"); + } + else + FcStrSetAdd (result, (const FcChar8 *) "en"); + + FcRefSetConst (&result->ref); + if (!fc_atomic_ptr_cmpexch (&default_langs, NULL, result)) { + FcRefInit (&result->ref, 1); + FcStrSetDestroy (result); + goto retry; + } + } + + return result; +} + +static FcChar8 *default_lang; /* MT-safe */ + +FcChar8 * +FcGetDefaultLang (void) +{ + FcChar8 *lang; +retry: + lang = fc_atomic_ptr_get (&default_lang); + if (!lang) + { + FcStrSet *langs = FcGetDefaultLangs (); + lang = FcStrdup (langs->strs[0]); + FcStrSetDestroy (langs); + + if (!fc_atomic_ptr_cmpexch (&default_lang, NULL, lang)) { + free (lang); + goto retry; + } + } + + return lang; +} + +static FcChar8 *default_prgname; + +FcChar8 * +FcGetPrgname (void) +{ + FcChar8 *prgname; +retry: + prgname = fc_atomic_ptr_get (&default_prgname); + if (!prgname) + { +#ifdef _WIN32 + char buf[MAX_PATH+1]; + + /* TODO This is ASCII-only; fix it. */ + if (GetModuleFileNameA (GetModuleHandle (NULL), buf, sizeof (buf) / sizeof (buf[0])) > 0) + { + char *p; + unsigned int len; + + p = strrchr (buf, '\\'); + if (p) + p++; + else + p = buf; + + len = strlen (p); + + if (len > 4 && 0 == strcmp (p + len - 4, ".exe")) + { + len -= 4; + buf[len] = '\0'; + } + + prgname = FcStrdup (p); + } +#elif defined (HAVE_GETPROGNAME) + const char *q = getprogname (); + if (q) + prgname = FcStrdup (q); + else + prgname = FcStrdup (""); +#else +# if defined (HAVE_GETEXECNAME) + const char *p = getexecname (); +# else + char buf[PATH_MAX + 1]; + int len; + char *p = NULL; + + len = readlink ("/proc/self/exe", buf, sizeof (buf) - 1); + if (len != -1) + { + buf[len] = '\0'; + p = buf; + } +# endif + if (p) + { + char *r = strrchr (p, '/'); + if (r) + r++; + else + r = p; + + prgname = FcStrdup (r); + } + + if (!prgname) + prgname = FcStrdup (""); +#endif + + if (!fc_atomic_ptr_cmpexch (&default_prgname, NULL, prgname)) { + free (prgname); + goto retry; + } + } + + if (prgname && !prgname[0]) + return NULL; + + return prgname; +} + +void +FcDefaultFini (void) +{ + FcChar8 *lang; + FcStrSet *langs; + FcChar8 *prgname; + + lang = fc_atomic_ptr_get (&default_lang); + if (lang && fc_atomic_ptr_cmpexch (&default_lang, lang, NULL)) { + free (lang); + } + + langs = fc_atomic_ptr_get (&default_langs); + if (langs && fc_atomic_ptr_cmpexch (&default_langs, langs, NULL)) { + FcRefInit (&langs->ref, 1); + FcStrSetDestroy (langs); + } + + prgname = fc_atomic_ptr_get (&default_prgname); + if (prgname && fc_atomic_ptr_cmpexch (&default_prgname, prgname, NULL)) { + free (prgname); + } +} + +void +FcDefaultSubstitute (FcPattern *pattern) +{ + FcValue v, namelang, v2; + 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_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); + } + if (FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAddString (pattern, FC_NAMELANG_OBJECT, FcGetDefaultLang ()); + } + /* shouldn't be failed. */ + FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &namelang); + /* Add a fallback to ensure the english name when the requested language + * isn't available. this would helps for the fonts that have non-English + * name at the beginning. + */ + /* Set "en-us" instead of "en" to avoid giving higher score to "en". + * This is a hack for the case that the orth is not like ll-cc, because, + * if no namelang isn't explicitly set, it will has something like ll-cc + * according to current locale. which may causes FcLangDifferentTerritory + * at FcLangCompare(). thus, the English name is selected so that + * exact matched "en" has higher score than ll-cc. + */ + v2.type = FcTypeString; + v2.u.s = (FcChar8 *) "en-us"; + if (FcPatternObjectGet (pattern, FC_FAMILYLANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAdd (pattern, FC_FAMILYLANG_OBJECT, namelang, FcTrue); + FcPatternObjectAddWithBinding (pattern, FC_FAMILYLANG_OBJECT, v2, FcValueBindingWeak, FcTrue); + } + if (FcPatternObjectGet (pattern, FC_STYLELANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAdd (pattern, FC_STYLELANG_OBJECT, namelang, FcTrue); + FcPatternObjectAddWithBinding (pattern, FC_STYLELANG_OBJECT, v2, FcValueBindingWeak, FcTrue); + } + if (FcPatternObjectGet (pattern, FC_FULLNAMELANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue); + FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue); + } + + if (FcPatternObjectGet (pattern, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) + { + FcChar8 *prgname = FcGetPrgname (); + if (prgname) + FcPatternObjectAddString (pattern, FC_PRGNAME_OBJECT, prgname); + } +} +#define __fcdefault__ +#include "fcaliastail.h" +#undef __fcdefault__ diff --git a/chromium/third_party/fontconfig/src/src/fcdeprecate.h b/chromium/third_party/fontconfig/src/src/fcdeprecate.h new file mode 100644 index 00000000000..214b684cfca --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcdeprecate.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* + * These APIs are deprecated; still exported by the library, but not + * declared in the public header file + */ +#ifndef _FCDEPRECATE_H_ +#define _FCDEPRECATE_H_ + +FcPublic int +FcConfigGetRescanInverval (FcConfig *config); + +FcPublic FcBool +FcConfigSetRescanInverval (FcConfig *config, int rescanInterval); + +#endif /* _FCDEPRECATE_H_ */ diff --git a/chromium/third_party/fontconfig/src/src/fcdir.c b/chromium/third_party/fontconfig/src/src/fcdir.c new file mode 100644 index 00000000000..b040a285ad6 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcdir.c @@ -0,0 +1,335 @@ +/* + * 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); +} + +FcBool +FcFileIsLink (const FcChar8 *file) +{ +#if HAVE_LSTAT + struct stat statb; + + if (lstat ((const char *)file, &statb) != 0) + return FcFalse; + return S_ISLNK (statb.st_mode); +#else + return FcFalse; +#endif +} + +FcBool +FcFileIsFile (const FcChar8 *file) +{ + struct stat statb; + + if (FcStat (file, &statb) != 0) + return FcFalse; + return S_ISREG (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 FC_UNUSED, + FcBlanks *blanks, + const FcChar8 *file, + FcBool force FC_UNUSED) +{ + 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: + if (file) + free (file); + + 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; + FcFontSet *set; + FcCache *cache = NULL; + struct stat dir_stat; + + if (FcDebug () & FC_DBG_FONTSET) + printf ("cache scan dir %s\n", dir); + + if (FcStatChecksum (dir, &dir_stat) < 0) + goto bail; + + set = FcFontSetCreate(); + if (!set) + goto bail; + + dirs = FcStrSetCreate (); + if (!dirs) + goto bail1; + + /* + * Scan the dir + */ + if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config)) + goto bail2; + + /* + * Build the cache object + */ + cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); + if (!cache) + 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 FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) +{ + return FcFalse; /* XXX deprecated */ +} +#define __fcdir__ +#include "fcaliastail.h" +#undef __fcdir__ diff --git a/chromium/third_party/fontconfig/src/src/fcformat.c b/chromium/third_party/fontconfig/src/src/fcformat.c new file mode 100644 index 00000000000..59f8681dff0 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcformat.c @@ -0,0 +1,1220 @@ +/* + * 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); + FcStrFree (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) +{ + if (!expect_char (c, '%')) + return FcFalse; + + /* skip an optional width specifier */ + if (strtol ((const char *) c->format, (char **) &c->format, 10)) + {/* don't care */} + + 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 FC_UNUSED, + 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 FC_UNUSED, + 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 FC_UNUSED, + 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); + FcStrFree (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]; + FcPattern *alloced = NULL; + FcBool ret; + + if (!pat) + alloced = pat = FcPatternCreate (); + + FcStrBufInit (&buf, buf_static, sizeof (buf_static)); + + ret = FcPatternFormatToBuf (pat, format, &buf); + + if (alloced) + FcPatternDestroy (alloced); + + if (ret) + return FcStrBufDone (&buf); + else + { + FcStrBufDestroy (&buf); + return NULL; + } +} + +#define __fcformat__ +#include "fcaliastail.h" +#undef __fcformat__ diff --git a/chromium/third_party/fontconfig/src/src/fcfreetype.c b/chromium/third_party/fontconfig/src/src/fcfreetype.c new file mode 100644 index 00000000000..e39430762c7 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcfreetype.c @@ -0,0 +1,2822 @@ +/* + * 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 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 *FcNoticeFoundries[][2] = + { + {"Adobe", "adobe"}, + {"Bigelow", "b&h"}, + {"Bitstream", "bitstream"}, + {"Gnat", "culmus"}, + {"Iorsh", "culmus"}, + {"HanYang System", "hanyang"}, + {"Font21", "hwan"}, + {"IBM", "ibm"}, + {"International Typeface Corporation", "itc"}, + {"Linotype", "linotype"}, + {"LINOTYPE-HELL", "linotype"}, + {"Microsoft", "microsoft"}, + {"Monotype", "monotype"}, + {"Omega", "omega"}, + {"Tiro Typeworks", "tiro"}, + {"URW", "urw"}, + {"XFree86", "xfree86"}, + {"Xorg", "xorg"}, +}; + +#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 char *n = FcNoticeFoundries[i][0]; + const char *f = FcNoticeFoundries[i][1]; + + 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"}, + { "CLM", "culmus"}, + { "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 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 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; + unsigned int p, n; + int platform, nameid; + + FcChar8 *style = 0; + int st; + char psname[256]; + const char *tmp; + + FcChar8 *hashstr = NULL; + FT_Error err; + FT_ULong len = 0, alen; + + 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, *pp; + const FcChar8 *lang; + const char *elt = 0, *eltlang = 0; + int *np = 0, *nlangp = 0; + size_t len; + + 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 + { + unsigned 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_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 (utf8) + { + pp = utf8; + while (*pp == ' ') + pp++; + len = strlen ((const char *) pp); + memmove (utf8, pp, len + 1); + pp = utf8 + len - 1; + while (*pp == ' ') + pp--; + *(pp + 1) = 0; + } + 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; + } + + /* Add the PostScript name into the cache */ + tmp = FT_Get_Postscript_Name (face); + if (!tmp) + { + FcChar8 *family, *familylang = NULL; + size_t len; + int n = 0; + + /* Workaround when FT_Get_Postscript_Name didn't give any name. + * try to find out the English family name and convert. + */ + while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch) + { + if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0) + break; + n++; + familylang = NULL; + } + if (!familylang) + n = 0; + + if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch) + goto bail1; + len = strlen ((const char *)family); + /* the literal name in PostScript Language is limited to 127 characters though, + * It is the architectural limit. so assuming 255 characters may works enough. + */ + for (i = 0; i < len && i < 255; i++) + { + /* those characters are not allowed to be the literal name in PostScript */ + static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n "; + + if (strchr(exclusive_chars, family[i]) != NULL) + psname[i] = '-'; + else + psname[i] = family[i]; + } + psname[i] = 0; + } + else + { + strcpy (psname, tmp); + } + if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname)) + goto bail1; + + 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; + + err = FT_Load_Sfnt_Table (face, 0, 0, NULL, &len); + if (err == FT_Err_Ok) + { + char *fontdata; + + alen = (len + 63) & ~63; + fontdata = malloc (alen); + if (!fontdata) + goto bail3; + err = FT_Load_Sfnt_Table (face, 0, 0, (FT_Byte *)fontdata, &len); + if (err != FT_Err_Ok) + { + free (fontdata); + goto bail3; + } + memset (&fontdata[len], 0, alen - len); + hashstr = FcHashGetSHA256DigestFromMemory (fontdata, len); + free (fontdata); + } + else if (err == FT_Err_Invalid_Face_Handle) + { + /* font may not support SFNT. falling back to + * read the font data from file directly + */ + hashstr = FcHashGetSHA256DigestFromFile (file); + } + else + { + goto bail3; + } + if (hashstr) + { + if (!FcPatternAddString (pat, FC_HASH, hashstr)) + { + free (hashstr); + goto bail1; + } + free (hashstr); + } +bail3: + + /* + * 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) + if (!FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format)) + goto bail2; + } +#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 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 }, +}; + +#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 ((int) 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; + + /* + * 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 (!(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; + } + cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index); + } + else + cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1); + 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 FcIsDigit(c) (('0' <= (c) && (c) <= '9')) +#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(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 alphanumeric, 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_HEAD); + 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; + int script_count; + + if (!stream) + return 0; + + 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/chromium/third_party/fontconfig/src/src/fcfs.c b/chromium/third_party/fontconfig/src/src/fcfs.c new file mode 100644 index 00000000000..941abba8f40 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcfs.c @@ -0,0 +1,127 @@ +/* + * 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; + 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) + free (s->fonts); + 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; + 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/chromium/third_party/fontconfig/src/src/fcftint.h b/chromium/third_party/fontconfig/src/src/fcftint.h new file mode 100644 index 00000000000..a317370e1fb --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcftint.h @@ -0,0 +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_ */ diff --git a/chromium/third_party/fontconfig/src/src/fchash.c b/chromium/third_party/fontconfig/src/src/fchash.c new file mode 100644 index 00000000000..38300028c8e --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fchash.c @@ -0,0 +1,317 @@ +/* + * fontconfig/src/fchash.c + * + * Copyright © 2003 Keith Packard + * Copyright © 2013 Red Hat, Inc. + * Red Hat Author(s): Akira TAGOH + * + * 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 <string.h> + +#define ROTRN(w, v, n) ((((FcChar32)v) >> n) | (((FcChar32)v) << (w - n))) +#define ROTR32(v, n) ROTRN(32, v, n) +#define SHR(v, n) (v >> n) +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define SS0(x) (ROTR32(x, 2) ^ ROTR32(x, 13) ^ ROTR32(x, 22)) +#define SS1(x) (ROTR32(x, 6) ^ ROTR32(x, 11) ^ ROTR32(x, 25)) +#define ss0(x) (ROTR32(x, 7) ^ ROTR32(x, 18) ^ SHR(x, 3)) +#define ss1(x) (ROTR32(x, 17) ^ ROTR32(x, 19) ^ SHR(x, 10)) + + +static FcChar32 * +FcHashInitSHA256Digest (void) +{ + int i; + static const FcChar32 h[] = { + 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, + 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL + }; + FcChar32 *ret = malloc (sizeof (FcChar32) * 8); + + if (!ret) + return NULL; + + for (i = 0; i < 8; i++) + ret[i] = h[i]; + + return ret; +} + +static void +FcHashComputeSHA256Digest (FcChar32 *hash, + const char *block) +{ + static const FcChar32 k[] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL + }; + FcChar32 w[64], i, j, t1, t2; + FcChar32 a, b, c, d, e, f, g, h; + +#define H(n) (hash[n]) + + a = H(0); + b = H(1); + c = H(2); + d = H(3); + e = H(4); + f = H(5); + g = H(6); + h = H(7); + + for (i = 0; i < 16; i++) + { + j = (block[(i * 4) + 0] & 0xff) << (8 * 3); + j |= (block[(i * 4) + 1] & 0xff) << (8 * 2); + j |= (block[(i * 4) + 2] & 0xff) << (8 * 1); + j |= (block[(i * 4) + 3] & 0xff); + w[i] = j; + } + for (i = 16; i < 64; i++) + w[i] = ss1(w[i - 2]) + w[i - 7] + ss0(w[i - 15]) + w[i - 16]; + + for (i = 0; i < 64; i++) + { + t1 = h + SS1(e) + Ch(e, f, g) + k[i] + w[i]; + t2 = SS0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + H(0) += a; + H(1) += b; + H(2) += c; + H(3) += d; + H(4) += e; + H(5) += f; + H(6) += g; + H(7) += h; + +#undef H +} + +static FcChar8 * +FcHashSHA256ToString (FcChar32 *hash) +{ + FcChar8 *ret = NULL; + static const char hex[] = "0123456789abcdef"; + int i, j; + + if (hash) + { + ret = malloc (sizeof (FcChar8) * (8 * 8 + 7 + 1)); + if (!ret) + return NULL; + memcpy (ret, "sha256:", 7); +#define H(n) hash[n] + for (i = 0; i < 8; i++) + { + FcChar32 v = H(i); + + for (j = 0; j < 8; j++) + ret[7 + (i * 8) + j] = hex[(v >> (28 - j * 4)) & 0xf]; + } + ret[7 + i * 8] = 0; +#undef H + free (hash); + } + + return ret; +} + +FcChar8 * +FcHashGetSHA256Digest (const FcChar8 *input_strings, + size_t len) +{ + size_t i, round_len = len / 64; + char block[64]; + FcChar32 *ret = FcHashInitSHA256Digest (); + + if (!ret) + return NULL; + + for (i = 0; i < round_len; i++) + { + FcHashComputeSHA256Digest (ret, (const char *)&input_strings[i * 64]); + } + /* padding */ + if ((len % 64) != 0) + memcpy (block, &input_strings[len / 64], len % 64); + memset (&block[len % 64], 0, 64 - (len % 64)); + block[len % 64] = 0x80; + if ((64 - (len % 64)) < 9) + { + /* process a block once */ + FcHashComputeSHA256Digest (ret, block); + memset (block, 0, 64); + } + /* set input size at the end */ + len *= 8; + block[63 - 0] = (uint64_t)len & 0xff; + block[63 - 1] = ((uint64_t)len >> 8) & 0xff; + block[63 - 2] = ((uint64_t)len >> 16) & 0xff; + block[63 - 3] = ((uint64_t)len >> 24) & 0xff; + block[63 - 4] = ((uint64_t)len >> 32) & 0xff; + block[63 - 5] = ((uint64_t)len >> 40) & 0xff; + block[63 - 6] = ((uint64_t)len >> 48) & 0xff; + block[63 - 7] = ((uint64_t)len >> 56) & 0xff; + FcHashComputeSHA256Digest (ret, block); + + return FcHashSHA256ToString (ret); +} + +FcChar8 * +FcHashGetSHA256DigestFromFile (const FcChar8 *filename) +{ + FILE *fp = fopen ((const char *)filename, "rb"); + char ibuf[64]; + FcChar32 *ret; + size_t len; + struct stat st; + + if (!fp) + return NULL; + + if (FcStat (filename, &st)) + goto bail0; + + ret = FcHashInitSHA256Digest (); + if (!ret) + goto bail0; + + while (!feof (fp)) + { + if ((len = fread (ibuf, sizeof (char), 64, fp)) < 64) + { + uint64_t v; + + /* add a padding */ + memset (&ibuf[len], 0, 64 - len); + ibuf[len] = 0x80; + if ((64 - len) < 9) + { + /* process a block once */ + FcHashComputeSHA256Digest (ret, ibuf); + memset (ibuf, 0, 64); + } + /* set input size at the end */ + v = (long)st.st_size * 8; + ibuf[63 - 0] = v & 0xff; + ibuf[63 - 1] = (v >> 8) & 0xff; + ibuf[63 - 2] = (v >> 16) & 0xff; + ibuf[63 - 3] = (v >> 24) & 0xff; + ibuf[63 - 4] = (v >> 32) & 0xff; + ibuf[63 - 5] = (v >> 40) & 0xff; + ibuf[63 - 6] = (v >> 48) & 0xff; + ibuf[63 - 7] = (v >> 56) & 0xff; + FcHashComputeSHA256Digest (ret, ibuf); + break; + } + else + { + FcHashComputeSHA256Digest (ret, ibuf); + } + } + fclose (fp); + + return FcHashSHA256ToString (ret); + +bail0: + fclose (fp); + + return NULL; +} + +FcChar8 * +FcHashGetSHA256DigestFromMemory (const char *fontdata, + size_t length) +{ + char ibuf[64]; + FcChar32 *ret; + size_t i = 0; + + ret = FcHashInitSHA256Digest (); + if (!ret) + return NULL; + + while (i <= length) + { + if ((length - i) < 64) + { + uint64_t v; + size_t n; + + /* add a padding */ + n = length - i; + if (n > 0) + memcpy (ibuf, &fontdata[i], n); + memset (&ibuf[n], 0, 64 - n); + ibuf[n] = 0x80; + if ((64 - n) < 9) + { + /* process a block once */ + FcHashComputeSHA256Digest (ret, ibuf); + memset (ibuf, 0, 64); + } + /* set input size at the end */ + v = length * 8; + ibuf[63 - 0] = v & 0xff; + ibuf[63 - 1] = (v >> 8) & 0xff; + ibuf[63 - 2] = (v >> 16) & 0xff; + ibuf[63 - 3] = (v >> 24) & 0xff; + ibuf[63 - 4] = (v >> 32) & 0xff; + ibuf[63 - 5] = (v >> 40) & 0xff; + ibuf[63 - 6] = (v >> 48) & 0xff; + ibuf[63 - 7] = (v >> 56) & 0xff; + FcHashComputeSHA256Digest (ret, ibuf); + break; + } + else + { + FcHashComputeSHA256Digest (ret, &fontdata[i]); + } + i += 64; + } + + return FcHashSHA256ToString (ret); +} diff --git a/chromium/third_party/fontconfig/src/src/fcinit.c b/chromium/third_party/fontconfig/src/src/fcinit.c new file mode 100644 index 00000000000..b8d5d060c71 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcinit.c @@ -0,0 +1,215 @@ +/* + * 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> + +#if defined(FC_ATOMIC_INT_NIL) +#pragma message("Could not find any system to define atomic_int macros, library may NOT be thread-safe.") +#endif +#if defined(FC_MUTEX_IMPL_NIL) +#pragma message("Could not find any system to define mutex macros, library may NOT be thread-safe.") +#endif +#if defined(FC_ATOMIC_INT_NIL) || defined(FC_MUTEX_IMPL_NIL) +#pragma message("To suppress these warnings, define FC_NO_MT.") +#endif + +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 * +FcInitLoadOwnConfig (FcConfig *config) +{ + if (!config) + { + config = FcConfigCreate (); + if (!config) + return NULL; + } + + FcInitDebug (); + + if (!FcConfigParseAndLoad (config, 0, FcTrue)) + { + FcConfigDestroy (config); + return FcInitFallbackConfig (); + } + + if (config->cacheDirs && config->cacheDirs->num == 0) + { + FcChar8 *prefix, *p; + size_t plen; + + fprintf (stderr, + "Fontconfig warning: no <cachedir> elements found. Check configuration.\n"); + fprintf (stderr, + "Fontconfig warning: adding <cachedir>%s</cachedir>\n", + FC_CACHEDIR); + prefix = FcConfigXdgCacheHome (); + if (!prefix) + goto bail; + plen = strlen ((const char *)prefix); + p = realloc (prefix, plen + 12); + if (!p) + goto bail; + prefix = p; + memcpy (&prefix[plen], FC_DIR_SEPARATOR_S "fontconfig", 11); + prefix[plen + 11] = 0; + fprintf (stderr, + "Fontconfig warning: adding <cachedir prefix=\"xdg\">fontconfig</cachedir>\n"); + + if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR) || + !FcConfigAddCacheDir (config, (FcChar8 *) prefix)) + { + bail: + fprintf (stderr, + "Fontconfig error: out of memory"); + if (prefix) + FcStrFree (prefix); + FcConfigDestroy (config); + return FcInitFallbackConfig (); + } + FcStrFree (prefix); + } + + return config; +} + +FcConfig * +FcInitLoadConfig (void) +{ + return FcInitLoadOwnConfig (NULL); +} + +/* + * Load the configuration files and scan for available fonts + */ +FcConfig * +FcInitLoadOwnConfigAndFonts (FcConfig *config) +{ + config = FcInitLoadOwnConfig (config); + if (!config) + return 0; + if (!FcConfigBuildFonts (config)) + { + FcConfigDestroy (config); + return 0; + } + return config; +} + +FcConfig * +FcInitLoadConfigAndFonts (void) +{ + return FcInitLoadOwnConfigAndFonts (NULL); +} + +/* + * Initialize the default library configuration + */ +FcBool +FcInit (void) +{ + return FcConfigInit (); +} + +/* + * Free all library-allocated data structures. + */ +void +FcFini (void) +{ + FcConfigFini (); + FcCacheFini (); + FcDefaultFini (); +} + +/* + * Reread the configuration and available font lists + */ +FcBool +FcInitReinitialize (void) +{ + FcConfig *config; + + config = FcInitLoadConfigAndFonts (); + if (!config) + return FcFalse; + return FcConfigSetCurrent (config); +} + +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 (); +} + +#define __fcinit__ +#include "fcaliastail.h" +#undef __fcinit__ diff --git a/chromium/third_party/fontconfig/src/src/fcint.h b/chromium/third_party/fontconfig/src/src/fcint.h new file mode 100644 index 00000000000..362ea6f99ad --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcint.h @@ -0,0 +1,1162 @@ +/* + * 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 "fcstdint.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <errno.h> +#include <limits.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" +#include "fcmutex.h" +#include "fcatomic.h" + +#ifndef FC_CONFIG_PATH +#define FC_CONFIG_PATH "fonts.conf" +#endif + +#ifdef _WIN32 +# include "fcwindows.h" +typedef UINT (WINAPI *pfnGetSystemWindowsDirectory)(LPSTR, UINT); +typedef HRESULT (WINAPI *pfnSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR); +extern pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory; +extern pfnSHGetFolderPathA pSHGetFolderPathA; +# define FC_SEARCH_PATH_SEPARATOR ';' +# define FC_DIR_SEPARATOR '\\' +# define FC_DIR_SEPARATOR_S "\\" +#else +# define FC_SEARCH_PATH_SEPARATOR ':' +# define FC_DIR_SEPARATOR '/' +# define FC_DIR_SEPARATOR_S "/" +#endif + +#if __GNUC__ >= 4 +#define FC_UNUSED __attribute__((unused)) +#else +#define FC_UNUSED +#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_CONFIG 1024 +#define FC_DBG_LANGSET 2048 + +#define _FC_ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] FC_UNUSED +#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 + +FC_ASSERT_STATIC (sizeof (FcRef) == sizeof (int)); + +typedef enum _FcValueBinding { + FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame, + /* to make sure sizeof (FcValueBinding) == 4 even with -fshort-enums */ + FcValueBindingEnd = INT_MAX +} FcValueBinding; + +#define FcStrdup(s) ((FcChar8 *) strdup ((const char *) (s))) +#define FcFree(s) (free ((FcChar8 *) (s))) + +/* + * 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; + +/* The 1024 is to leave some room for future added internal objects, such + * that caches from newer fontconfig can still be used with older fontconfig + * without getting confused. */ +#define FC_EXT_OBJ_INDEX 1024 +#define FC_OBJ_ID(_n_) ((_n_) & (~FC_EXT_OBJ_INDEX)) + +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; + FcRef 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, + FcOpDelete, FcOpDeleteAll, + 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 enum _FcOpFlags { + FcOpFlagIgnoreBlanks = 1 << 0 +} FcOpFlags; + +#define FC_OP_GET_OP(_x_) ((_x_) & 0xffff) +#define FC_OP_GET_FLAGS(_x_) (((_x_) & 0xffff0000) >> 16) +#define FC_OP(_x_,_f_) (FC_OP_GET_OP (_x_) | ((_f_) << 16)) + +typedef struct _FcExprMatrix { + struct _FcExpr *xx, *xy, *yx, *yy; +} FcExprMatrix; + +typedef struct _FcExprName { + FcObject object; + FcMatchKind kind; +} FcExprName; + + +typedef struct _FcExpr { + FcOp op; + union { + int ival; + double dval; + const FcChar8 *sval; + FcExprMatrix *mexpr; + FcBool bval; + FcCharSet *cval; + FcLangSet *lval; + + FcExprName name; + 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[FLEXIBLE_ARRAY_MEMBER]; +}; + +typedef enum _FcQual { + FcQualAny, FcQualAll, FcQualFirst, FcQualNotFirst +} FcQual; + +#define FcMatchDefault ((FcMatchKind) -1) + +typedef struct _FcTest { + FcMatchKind kind; + FcQual qual; + FcObject object; + FcOp op; + FcExpr *expr; +} FcTest; + +typedef struct _FcEdit { + FcObject object; + FcOp op; + FcExpr *expr; + FcValueBinding binding; +} FcEdit; + +typedef enum _FcRuleType { + FcRuleUnknown, FcRuleTest, FcRuleEdit +} FcRuleType; + +typedef struct _FcRule { + struct _FcRule *next; + FcRuleType type; + union { + FcTest *test; + FcEdit *edit; + } u; +} FcRule; + +typedef struct _FcSubst { + struct _FcSubst *next; + FcRule *rule; +} FcSubst; + +typedef struct _FcCharLeaf { + FcChar32 map[256/32]; +} FcCharLeaf; + +struct _FcCharSet { + FcRef 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 { + FcRef 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 { + unsigned 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 checksum; /* checksum of directory state */ +}; + +#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 4 + +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 */ + + FcRef ref; /* reference count */ + + FcExprPage *expr_pool; /* pool of FcExpr's */ + + FcChar8 *sysRoot; /* override the system root directory */ +}; + +typedef struct _FcFileTime { + time_t time; + FcBool set; +} FcFileTime; + +typedef struct _FcCharMap FcCharMap; + +typedef struct _FcRange FcRange; + +struct _FcRange { + FcChar32 begin; + FcChar32 end; +}; + +typedef struct _FcStatFS FcStatFS; + +struct _FcStatFS { + FcBool is_remote_fs; + FcBool is_mtime_broken; +}; + +typedef struct _FcValuePromotionBuffer FcValuePromotionBuffer; + +struct _FcValuePromotionBuffer { + union { + double d; + int i; + long l; + char c[256]; /* Enlarge as needed */ + } u; +}; + +/* 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 FcBool +FcDirCacheCreateTagFile (const FcChar8 *cache_dir); + +FcPrivate void +FcCacheObjectReference (void *object); + +FcPrivate void +FcCacheObjectDereference (void *object); + +FcPrivate void +FcCacheFini (void); + +FcPrivate void +FcDirCacheReference (FcCache *cache, int nref); + +/* fccfg.c */ + +FcPrivate FcBool +FcConfigInit (void); + +FcPrivate void +FcConfigFini (void); + +FcPrivate FcChar8 * +FcConfigXdgCacheHome (void); + +FcPrivate FcChar8 * +FcConfigXdgConfigHome (void); + +FcPrivate FcChar8 * +FcConfigXdgDataHome (void); + +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); + +FcBool +FcConfigAddRule (FcConfig *config, + FcRule *rule, + FcMatchKind kind); + +FcPrivate void +FcConfigSetFonts (FcConfig *config, + FcFontSet *fonts, + FcSetName set); + +FcPrivate FcBool +FcConfigCompareValue (const FcValue *m, + unsigned int 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); + +/* fccompat.c */ +FcPrivate int +FcOpen(const char *pathname, int flags, ...); + +FcPrivate int +FcMakeTempfile (char *template); + +FcPrivate int32_t +FcRandom (void); + +FcPrivate FcBool +FcMakeDirectory (const FcChar8 *dir); + +/* fcdbg.c */ + +FcPrivate void +FcValuePrintFile (FILE *f, const FcValue v); + +FcPrivate void +FcValuePrintWithPosition (const FcValue v, FcBool show_pos_mark); + +FcPrivate void +FcValueListPrintWithPosition (FcValueListPtr l, const FcValueListPtr pos); + +FcPrivate void +FcValueListPrint (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); + +FcPrivate FcChar8 * +FcGetPrgname (void); + +FcPrivate void +FcDefaultFini (void); + +/* fcdir.c */ + +FcPrivate FcBool +FcFileIsLink (const FcChar8 *file); + +FcPrivate FcBool +FcFileIsFile (const FcChar8 *file); + +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); + +/* fchash.c */ +FcPrivate FcChar8 * +FcHashGetSHA256Digest (const FcChar8 *input_strings, + size_t len); + +FcPrivate FcChar8 * +FcHashGetSHA256DigestFromFile (const FcChar8 *filename); + +FcPrivate FcChar8 * +FcHashGetSHA256DigestFromMemory (const char *fontdata, + size_t length); + +/* fcinit.c */ +FcPrivate FcConfig * +FcInitLoadOwnConfig (FcConfig *config); + +FcPrivate FcConfig * +FcInitLoadOwnConfigAndFonts (FcConfig *config); + +/* fcxml.c */ +FcPrivate void +FcTestDestroy (FcTest *test); + +FcPrivate void +FcEditDestroy (FcEdit *e); + +void +FcRuleDestroy (FcRule *rule); + +/* 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, FcValuePromotionBuffer *buf); + +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 */ + +enum { + FC_INVALID_OBJECT = 0, +#define FC_OBJECT(NAME, Type, Cmp) FC_##NAME##_OBJECT, +#include "fcobjs.h" +#undef FC_OBJECT + FC_ONE_AFTER_MAX_BASE_OBJECT +#define FC_MAX_BASE_OBJECT (FC_ONE_AFTER_MAX_BASE_OBJECT - 1) +}; + +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); + +#define FcObjectCompare(a, b) ((int) a - (int) b) + +/* fcpat.c */ + +FcPrivate FcValue +FcValueCanonicalize (const FcValue *v); + +FcPrivate FcValueListPtr +FcValueListCreate (void); + +FcPrivate void +FcValueListDestroy (FcValueListPtr l); + +FcPrivate FcValueListPtr +FcValueListPrepend (FcValueListPtr vallist, + FcValue value, + FcValueBinding binding); + +FcPrivate FcValueListPtr +FcValueListAppend (FcValueListPtr vallist, + FcValue value, + FcValueBinding binding); + +FcPrivate FcValueListPtr +FcValueListDuplicate(FcValueListPtr orig); + +FcPrivate FcPatternElt * +FcPatternObjectFindElt (const FcPattern *p, FcObject object); + +FcPrivate FcPatternElt * +FcPatternObjectInsertElt (FcPattern *p, FcObject object); + +FcPrivate FcBool +FcPatternObjectListAdd (FcPattern *p, + FcObject object, + FcValueListPtr list, + FcBool append); + +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 FcBool +FcPatternAppend (FcPattern *p, FcPattern *s); + +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); + +/* fcstat.c */ + +FcPrivate int +FcStat (const FcChar8 *file, struct stat *statb); + +FcPrivate int +FcStatChecksum (const FcChar8 *file, struct stat *statb); + +FcPrivate FcBool +FcIsFsMmapSafe (int fd); + +FcPrivate FcBool +FcIsFsMtimeBroken (const FcChar8 *dir); + +/* fcstr.c */ +FcPrivate FcBool +FcStrSetAddLangs (FcStrSet *strs, const char *languages); + +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 int +FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims); + +FcPrivate FcBool +FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex); + +FcPrivate FcBool +FcStrRegexCmpIgnoreCase (const FcChar8 *s, const FcChar8 *regex); + +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 int +FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims); + +FcPrivate FcBool +FcStrGlobMatch (const FcChar8 *glob, + const FcChar8 *string); + +FcPrivate FcBool +FcStrUsesHome (const FcChar8 *s); + +FcPrivate FcChar8 * +FcStrBuildFilename (const FcChar8 *path, + ...); + +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); + +/* fcobjs.c */ + +FcPrivate FcObject +FcObjectLookupIdByName (const char *str); + +FcPrivate FcObject +FcObjectLookupBuiltinIdByName (const char *str); + +FcPrivate const char * +FcObjectLookupOtherNameById (FcObject id); + +FcPrivate const FcObjectType * +FcObjectLookupOtherTypeById (FcObject id); + +FcPrivate const FcObjectType * +FcObjectLookupOtherTypeByName (const char *str); + +#endif /* _FC_INT_H_ */ diff --git a/chromium/third_party/fontconfig/src/src/fclang.c b/chromium/third_party/fontconfig/src/src/fclang.c new file mode 100644 index 00000000000..9f685f6fdff --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fclang.c @@ -0,0 +1,1059 @@ +/* + * 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" + +/* Objects MT-safe for readonly access. */ + +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 int FcLangSetIndex (const FcChar8 *lang); + + +static void +FcLangSetBitSet (FcLangSet *ls, + unsigned int id) +{ + unsigned 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) +{ + unsigned 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) +{ + unsigned 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; +} + +FcChar8 * +FcLangNormalize (const FcChar8 *lang) +{ + FcChar8 *result = NULL, *s, *orig; + char *territory, *encoding, *modifier; + size_t llen, tlen = 0, mlen = 0; + + if (!lang || !*lang) + return NULL; + + if (FcStrCmpIgnoreCase (lang, (const FcChar8 *)"C") == 0 || + FcStrCmpIgnoreCase (lang, (const FcChar8 *)"POSIX") == 0) + { + result = FcStrCopy ((const FcChar8 *)"en"); + goto bail; + } + + s = FcStrCopy (lang); + if (!s) + goto bail; + + /* from the comments in glibc: + * + * LOCALE can consist of up to four recognized parts for the XPG syntax: + * + * language[_territory[.codeset]][@modifier] + * + * Beside the first all of them are allowed to be missing. If the + * full specified locale is not found, the less specific one are + * looked for. The various part will be stripped off according to + * the following order: + * (1) codeset + * (2) normalized codeset + * (3) territory + * (4) modifier + * + * So since we don't take care of the codeset part here, what patterns + * we need to deal with is: + * + * 1. language_territory@modifier + * 2. language@modifier + * 3. language + * + * then. and maybe no need to try language_territory here. + */ + modifier = strchr ((const char *) s, '@'); + if (modifier) + { + *modifier = 0; + modifier++; + mlen = strlen (modifier); + } + encoding = strchr ((const char *) s, '.'); + if (encoding) + { + *encoding = 0; + encoding++; + if (modifier) + { + memmove (encoding, modifier, mlen + 1); + modifier = encoding; + } + } + territory = strchr ((const char *) s, '_'); + if (!territory) + territory = strchr ((const char *) s, '-'); + if (territory) + { + *territory = 0; + territory++; + tlen = strlen (territory); + } + llen = strlen ((const char *) s); + if (llen < 2 || llen > 3) + { + fprintf (stderr, "Fontconfig warning: ignoring %s: not a valid language tag\n", + lang); + goto bail0; + } + if (territory && (tlen < 2 || tlen > 3)) + { + fprintf (stderr, "Fontconfig warning: ignoring %s: not a valid region tag\n", + lang); + goto bail0; + } + if (territory) + territory[-1] = '-'; + if (modifier) + modifier[-1] = '@'; + orig = FcStrDowncase (s); + if (!orig) + goto bail0; + if (territory) + { + if (FcDebug () & FC_DBG_LANGSET) + printf("Checking the existence of %s.orth\n", s); + if (FcLangSetIndex (s) < 0) + { + memmove (territory - 1, territory + tlen, (mlen > 0 ? mlen + 1 : 0) + 1); + if (modifier) + modifier = territory; + } + else + { + result = s; + /* we'll miss the opportunity to reduce the correct size + * of the allocated memory for the string after that. + */ + s = NULL; + goto bail1; + } + } + if (modifier) + { + if (FcDebug () & FC_DBG_LANGSET) + printf("Checking the existence of %s.orth\n", s); + if (FcLangSetIndex (s) < 0) + modifier[-1] = 0; + else + { + result = s; + /* we'll miss the opportunity to reduce the correct size + * of the allocated memory for the string after that. + */ + s = NULL; + goto bail1; + } + } + if (FcDebug () & FC_DBG_LANGSET) + printf("Checking the existence of %s.orth\n", s); + if (FcLangSetIndex (s) < 0) + { + /* there seems no languages matched in orth. + * add the language as is for fallback. + */ + result = orig; + orig = NULL; + } + else + { + result = s; + /* we'll miss the opportunity to reduce the correct size + * of the allocated memory for the string after that. + */ + s = NULL; + } + bail1: + if (orig) + FcStrFree (orig); + bail0: + if (s) + free (s); + bail: + if (FcDebug () & FC_DBG_LANGSET) + { + if (result) + printf ("normalized: %s -> %s\n", lang, result); + else + printf ("Unable to normalize %s\n", lang); + } + + return result; +} + +#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; + 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); + 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 + */ +FcLangSet * +FcLangSetPromote (const FcChar8 *lang, FcValuePromotionBuffer *vbuf) +{ + int id; + typedef struct { + FcLangSet ls; + FcStrSet strs; + FcChar8 *str; + } FcLangSetPromotionBuffer; + FcLangSetPromotionBuffer *buf = (FcLangSetPromotionBuffer *) vbuf; + + FC_ASSERT_STATIC (sizeof (FcLangSetPromotionBuffer) <= sizeof (FcValuePromotionBuffer)); + + memset (buf->ls.map, '\0', sizeof (buf->ls.map)); + buf->ls.map_size = NUM_LANG_SET_MAP; + buf->ls.extra = 0; + id = FcLangSetIndex (lang); + if (id > 0) + { + FcLangSetBitSet (&buf->ls, id); + } + else + { + buf->ls.extra = &buf->strs; + buf->strs.num = 1; + buf->strs.size = 1; + buf->strs.strs = &buf->str; + FcRefInit (&buf->strs.ref, 1); + buf->str = (FcChar8 *) lang; + } + return &buf->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); + FcStrSet *set = FcLangSetGetLangs (b); + FcStrList *sl = FcStrListCreate (set); + FcChar8 *str; + + FcStrSetDestroy (set); + 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/chromium/third_party/fontconfig/src/src/fclist.c b/chromium/third_party/fontconfig/src/src/fclist.c new file mode 100644 index 00000000000..a365098a4d7 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fclist.c @@ -0,0 +1,607 @@ +/* + * 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; + 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; + os->objects = objects; + os->sobject = s; + } + high = os->nobject - 1; + low = 0; + mid = 0; + c = 1; + object = strdup (object); + while (low <= high) + { + mid = (low + high) >> 1; + c = os->objects[mid] - object; + if (c == 0) + { + FcFree (object); + 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) +{ + int i; + + if (os->objects) + { + for (i = 0; i < os->nobject; i++) + FcFree (os->objects[i]); + + free ((void *) os->objects); + } + 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, + FC_OP (FcOpListing, FcOpFlagIgnoreBlanks), + &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; + + if (!p) + return FcFalse; + for (i = 0; i < p->num; i++) + { + FcPatternElt *pe = &FcPatternElts(p)[i]; + FcPatternElt *fe; + + if (pe->object == FC_NAMELANG_OBJECT) + { + /* "namelang" object is the alias object to change "familylang", + * "stylelang" and "fullnamelang" object alltogether. it won't be + * available on the font pattern. so checking its availability + * causes no results. we should ignore it here. + */ + continue; + } + 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 FcTypeUnknown: + 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); + free (bucket); + } + table->buckets[i] = 0; + } + table->entries = 0; +} + +static int +FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object, const FcChar8 *lang) +{ + FcPatternElt *e = FcPatternObjectFindElt (font, object); + FcValueListPtr v; + FcValue value; + int idx = -1; + int defidx = -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; + if (defidx < 0) + { + /* workaround for fonts that has non-English value + * at the head of values. + */ + res = FcLangCompare (value.u.s, (FcChar8 *)"en"); + if (res == FcLangEqual) + defidx = i; + } + } + } + } + + return (idx > 0) ? idx : (defidx > 0) ? defidx : 0; +} + +static FcBool +FcListAppend (FcListHashTable *table, + FcPattern *font, + FcObjectSet *os, + const FcChar8 *lang) +{ + 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; + 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, lang); + 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, lang); + 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, lang); + 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: + 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 */ + { + FcChar8 *lang; + + if (FcPatternObjectGetString (p, FC_NAMELANG_OBJECT, 0, &lang) != FcResultMatch) + { + lang = FcGetDefaultLang (); + } + if (!FcListAppend (&table, s->fonts[f], os, lang)) + 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; + 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/chromium/third_party/fontconfig/src/src/fcmatch.c b/chromium/third_party/fontconfig/src/src/fcmatch.c new file mode 100644 index 00000000000..627aa1a1696 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcmatch.c @@ -0,0 +1,1025 @@ +/* + * 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" + +static double +FcCompareNumber (FcValue *value1, FcValue *value2) +{ + double v1, v2, v; + + switch ((int) value1->type) { + case FcTypeInteger: + v1 = (double) value1->u.i; + break; + case FcTypeDouble: + v1 = value1->u.d; + break; + default: + return -1.0; + } + switch ((int) 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 +FcComparePostScript (FcValue *v1, FcValue *v2) +{ + const FcChar8 *v1_string = FcValueString (v1); + const FcChar8 *v2_string = FcValueString (v2); + int n; + size_t len; + + if (FcToLower (*v1_string) != FcToLower (*v2_string) && + *v1_string != ' ' && *v2_string != ' ') + return 1.0; + + n = FcStrMatchIgnoreCaseAndDelims (v1_string, v2_string, (const FcChar8 *)" -"); + len = strlen ((const char *)v1_string); + + return (double)(len - n) / (double)len; +} + +static double +FcCompareLang (FcValue *v1, FcValue *v2) +{ + FcLangResult result; + FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2); + + switch ((int) value1.type) { + case FcTypeLangSet: + switch ((int) 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 ((int) 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 ((int) value1->type) { + case FcTypeInteger: + v1 = value1->u.i; + break; + case FcTypeDouble: + v1 = value1->u.d; + break; + default: + return -1; + } + switch ((int) 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; +} + +static double +FcCompareFilename (FcValue *v1, FcValue *v2) +{ + const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2); + if (FcStrCmp (s1, s2) == 0) + return 0.0; + else if (FcStrCmpIgnoreCase (s1, s2) == 0) + return 1.0; + else if (FcStrGlobMatch (s1, s2)) + return 2.0; + else + return 3.0; +} + +static double +FcCompareHash (FcValue *v1, FcValue *v2) +{ + const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2); + + /* Do not match an empty string */ + if (!s1 || !s2 || !s1[0] || !s2[0]) + return 1.0; + return FcCompareString (v1, v2); +} + +#define PRI_NULL(n) \ + PRI_ ## n ## _STRONG = -1, \ + PRI_ ## n ## _WEAK = -1, +#define PRI1(n) +#define PRI_FcCompareFamily(n) PRI1(n) +#define PRI_FcCompareString(n) PRI1(n) +#define PRI_FcCompareNumber(n) PRI1(n) +#define PRI_FcCompareSize(n) PRI1(n) +#define PRI_FcCompareBool(n) PRI1(n) +#define PRI_FcCompareFilename(n) PRI1(n) +#define PRI_FcCompareCharSet(n) PRI1(n) +#define PRI_FcCompareLang(n) PRI1(n) +#define PRI_FcComparePostScript(n) PRI1(n) +#define PRI_FcCompareHash(n) PRI1(n) + +#define FC_OBJECT(NAME, Type, Cmp) PRI_##Cmp(NAME) + +typedef enum _FcMatcherPriorityDummy { +#include "fcobjs.h" +} FcMatcherPriorityDummy; + +#undef FC_OBJECT + +#undef PRI1 +#define PRI1(n) \ + PRI_ ## n, \ + PRI_ ## n ## _STRONG = PRI_ ## n, \ + PRI_ ## n ## _WEAK = PRI_ ## n + +typedef enum _FcMatcherPriority { + PRI1(HASH), + PRI1(FILE), + PRI1(FONTFORMAT), + PRI1(SCALABLE), + PRI1(FOUNDRY), + PRI1(CHARSET), + PRI_FAMILY_STRONG, + PRI_POSTSCRIPT_NAME_STRONG, + PRI1(LANG), + PRI_FAMILY_WEAK, + PRI_POSTSCRIPT_NAME_WEAK, + PRI1(SPACING), + PRI1(PIXEL_SIZE), + PRI1(STYLE), + PRI1(SLANT), + PRI1(WEIGHT), + PRI1(WIDTH), + PRI1(DECORATIVE), + PRI1(ANTIALIAS), + PRI1(RASTERIZER), + PRI1(OUTLINE), + PRI1(FONTVERSION), + PRI_END +} FcMatcherPriority; + +#undef PRI1 + +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 + */ +#define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME##_OBJECT, Cmp, PRI_##NAME##_STRONG, PRI_##NAME##_WEAK }, +static const FcMatcher _FcMatchers [] = { + { FC_INVALID_OBJECT, NULL, -1, -1 }, +#include "fcobjs.h" +}; +#undef FC_OBJECT + +static const FcMatcher* +FcObjectToMatcher (FcObject object, + FcBool include_lang) +{ + if (include_lang) + { + switch (object) { + case FC_FAMILYLANG_OBJECT: + case FC_STYLELANG_OBJECT: + case FC_FULLNAMELANG_OBJECT: + object = FC_LANG_OBJECT; + break; + } + } + if (object > FC_MAX_BASE_OBJECT || + !_FcMatchers[object].compare || + _FcMatchers[object].strong == -1 || + _FcMatchers[object].weak == -1) + return NULL; + + return _FcMatchers + object; +} + +static FcBool +FcCompareValueList (FcObject object, + const FcMatcher *match, + FcValueListPtr v1orig, /* pattern */ + FcValueListPtr v2orig, /* target */ + FcValue *bestValue, + double *value, + int *n, + FcResult *result) +{ + FcValueListPtr v1, v2; + double v, best, bestStrong, bestWeak; + int j, k, pos = 0; + + if (!match) + { + if (bestValue) + *bestValue = FcValueCanonicalize(&v2orig->value); + if (n) + *n = 0; + return FcTrue; + } + + best = 1e99; + bestStrong = 1e99; + bestWeak = 1e99; + j = 1; + for (v1 = v1orig; v1; v1 = FcValueListNext(v1)) + { + for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++) + { + 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; + pos = k; + } + 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; + } + } + if (n) + *n = pos; + + 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 < PRI_END; 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 + { + const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse); + if (!FcCompareValueList (elt_i1->object, match, + FcPatternEltValues(elt_i1), + FcPatternEltValues(elt_i2), + NULL, value, NULL, result)) + return FcFalse; + i1++; + i2++; + } + } + return FcTrue; +} + +FcPattern * +FcFontRenderPrepare (FcConfig *config, + FcPattern *pat, + FcPattern *font) +{ + FcPattern *new; + int i; + FcPatternElt *fe, *pe, *fel, *pel; + FcValue v; + FcResult result; + + assert (pat != NULL); + assert (font != NULL); + + new = FcPatternCreate (); + if (!new) + return NULL; + for (i = 0; i < font->num; i++) + { + fe = &FcPatternElts(font)[i]; + if (fe->object == FC_FAMILYLANG_OBJECT || + fe->object == FC_STYLELANG_OBJECT || + fe->object == FC_FULLNAMELANG_OBJECT) + { + /* ignore those objects. we need to deal with them + * another way */ + continue; + } + if (fe->object == FC_FAMILY_OBJECT || + fe->object == FC_STYLE_OBJECT || + fe->object == FC_FULLNAME_OBJECT) + { + FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT); + FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT); + FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT); + + fel = FcPatternObjectFindElt (font, fe->object + 1); + pel = FcPatternObjectFindElt (pat, fe->object + 1); + } + else + { + fel = NULL; + pel = NULL; + } + pe = FcPatternObjectFindElt (pat, fe->object); + if (pe) + { + const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse); + + if (!FcCompareValueList (pe->object, match, + FcPatternEltValues(pe), + FcPatternEltValues(fe), &v, NULL, NULL, &result)) + { + FcPatternDestroy (new); + return NULL; + } + if (fel && pel) + { + int n = 1, j; + FcValueListPtr l1, l2, ln = NULL, ll = NULL; + + match = FcObjectToMatcher (pel->object, FcTrue); + if (!FcCompareValueList (pel->object, match, + FcPatternEltValues (pel), + FcPatternEltValues (fel), NULL, NULL, &n, &result)) + { + FcPatternDestroy (new); + return NULL; + } + + for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel); + l1 != NULL || l2 != NULL; + j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL) + { + if (j == n) + { + if (l1) + ln = FcValueListPrepend (ln, + FcValueCanonicalize (&l1->value), + FcValueBindingStrong); + if (l2) + ll = FcValueListPrepend (ll, + FcValueCanonicalize (&l2->value), + FcValueBindingStrong); + } + else + { + if (l1) + ln = FcValueListAppend (ln, + FcValueCanonicalize (&l1->value), + FcValueBindingStrong); + if (l2) + ll = FcValueListAppend (ll, + FcValueCanonicalize (&l2->value), + FcValueBindingStrong); + } + } + FcPatternObjectListAdd (new, fe->object, ln, FcFalse); + FcPatternObjectListAdd (new, fel->object, ll, FcFalse); + + continue; + } + else if (fel) + { + FcValueListPtr l1, l2; + + copy_lang: + l1 = FcValueListDuplicate (FcPatternEltValues (fe)); + l2 = FcValueListDuplicate (FcPatternEltValues (fel)); + FcPatternObjectListAdd (new, fe->object, l1, FcFalse); + FcPatternObjectListAdd (new, fel->object, l2, FcFalse); + + continue; + } + FcPatternObjectAdd (new, fe->object, v, FcFalse); + } + else + { + if (fel) + goto copy_lang; + FcPatternObjectListAdd (new, fe->object, + FcValueListDuplicate (FcPatternEltValues (fe)), + FcTrue); + } + } + for (i = 0; i < pat->num; i++) + { + pe = &FcPatternElts(pat)[i]; + fe = FcPatternObjectFindElt (font, pe->object); + if (!fe && + pe->object != FC_FAMILYLANG_OBJECT && + pe->object != FC_STYLELANG_OBJECT && + pe->object != FC_FULLNAMELANG_OBJECT) + { + FcPatternObjectListAdd (new, pe->object, + FcValueListDuplicate (FcPatternEltValues(pe)), + FcFalse); + } + } + + FcConfigSubstituteWithPat (config, new, pat, FcMatchFont); + return new; +} + +static FcPattern * +FcFontSetMatchInternal (FcFontSet **sets, + int nsets, + FcPattern *p, + FcResult *result) +{ + double score[PRI_END], bestscore[PRI_END]; + int f; + FcFontSet *s; + FcPattern *best; + int i; + int set; + + for (i = 0; i < PRI_END; 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 < PRI_END; i++) + { + printf (" %g", score[i]); + } + printf ("\n"); + } + for (i = 0; i < PRI_END; i++) + { + if (best && bestscore[i] < score[i]) + break; + if (!best || score[i] < bestscore[i]) + { + for (i = 0; i < PRI_END; i++) + bestscore[i] = score[i]; + best = s->fonts[f]; + break; + } + } + } + } + if (FcDebug () & FC_DBG_MATCH) + { + printf ("Best score"); + for (i = 0; i < PRI_END; i++) + printf (" %g", bestscore[i]); + printf ("\n"); + FcPatternPrint (best); + } + /* assuming that 'result' is initialized with FcResultNoMatch + * outside this function */ + if (best) + *result = FcResultMatch; + + return best; +} + +FcPattern * +FcFontSetMatch (FcConfig *config, + FcFontSet **sets, + int nsets, + FcPattern *p, + FcResult *result) +{ + FcPattern *best; + + assert (sets != NULL); + assert (p != NULL); + assert (result != NULL); + + *result = FcResultNoMatch; + + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return 0; + } + best = FcFontSetMatchInternal (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; + + assert (p != NULL); + assert (result != NULL); + + *result = FcResultNoMatch; + + 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 (sets, nsets, p, result); + if (best) + return FcFontRenderPrepare (config, p, best); + else + return NULL; +} + +typedef struct _FcSortNode { + FcPattern *pattern; + double score[PRI_END]; +} 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 = PRI_END; + 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 FC_UNUSED, + 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; + + assert (sets != NULL); + assert (p != NULL); + assert (result != NULL); + + /* There are some implementation that relying on the result of + * "result" to check if the return value of FcFontSetSort + * is valid or not. + * So we should initialize it to the conservative way since + * this function doesn't return NULL anymore. + */ + if (result) + *result = FcResultNoMatch; + + 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) + return FcFontSetCreate (); + + 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 < PRI_END; 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[PRI_LANG] < 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[PRI_LANG] = 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]); + } + if (ret->nfont > 0) + *result = FcResultMatch; + + 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; + + assert (p != NULL); + assert (result != NULL); + + *result = FcResultNoMatch; + + 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/chromium/third_party/fontconfig/src/src/fcmatrix.c b/chromium/third_party/fontconfig/src/src/fcmatrix.c new file mode 100644 index 00000000000..a6fbca2a05a --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcmatrix.c @@ -0,0 +1,116 @@ +/* + * 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; + *r = *mat; + return r; +} + +void +FcMatrixFree (FcMatrix *mat) +{ + if (mat != &FcIdentityMatrix) + 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/chromium/third_party/fontconfig/src/src/fcmutex.h b/chromium/third_party/fontconfig/src/src/fcmutex.h new file mode 100644 index 00000000000..556a05efcf3 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcmutex.h @@ -0,0 +1,127 @@ +/* + * Atomic int and pointer operations. Originally copied from HarfBuzz. + * + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012,2013 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef _FCMUTEX_H_ +#define _FCMUTEX_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define FC_STMT_START do +#define FC_STMT_END while (0) + +/* mutex */ + +/* We need external help for these */ + +#if 0 + + +#elif !defined(FC_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__) + +#include "fcwindows.h" +typedef CRITICAL_SECTION fc_mutex_impl_t; +#define FC_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 } +#define fc_mutex_impl_init(M) InitializeCriticalSection (M) +#define fc_mutex_impl_lock(M) EnterCriticalSection (M) +#define fc_mutex_impl_unlock(M) LeaveCriticalSection (M) +#define fc_mutex_impl_finish(M) DeleteCriticalSection (M) + + +#elif !defined(FC_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__)) + +#include <pthread.h> +typedef pthread_mutex_t fc_mutex_impl_t; +#define FC_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER +#define fc_mutex_impl_init(M) pthread_mutex_init (M, NULL) +#define fc_mutex_impl_lock(M) pthread_mutex_lock (M) +#define fc_mutex_impl_unlock(M) pthread_mutex_unlock (M) +#define fc_mutex_impl_finish(M) pthread_mutex_destroy (M) + + +#elif !defined(FC_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) + +#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) +# include <sched.h> +# define FC_SCHED_YIELD() sched_yield () +#else +# define FC_SCHED_YIELD() FC_STMT_START {} FC_STMT_END +#endif + +/* This actually is not a totally awful implementation. */ +typedef volatile int fc_mutex_impl_t; +#define FC_MUTEX_IMPL_INIT 0 +#define fc_mutex_impl_init(M) *(M) = 0 +#define fc_mutex_impl_lock(M) FC_STMT_START { while (__sync_lock_test_and_set((M), 1)) FC_SCHED_YIELD (); } FC_STMT_END +#define fc_mutex_impl_unlock(M) __sync_lock_release (M) +#define fc_mutex_impl_finish(M) FC_STMT_START {} FC_STMT_END + + +#elif !defined(FC_NO_MT) + +#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) +# include <sched.h> +# define FC_SCHED_YIELD() sched_yield () +#else +# define FC_SCHED_YIELD() FC_STMT_START {} FC_STMT_END +#endif + +#define FC_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */ +typedef volatile int fc_mutex_impl_t; +#define FC_MUTEX_IMPL_INIT 0 +#define fc_mutex_impl_init(M) *(M) = 0 +#define fc_mutex_impl_lock(M) FC_STMT_START { while (*(M)) FC_SCHED_YIELD (); (*(M))++; } FC_STMT_END +#define fc_mutex_impl_unlock(M) (*(M))--; +#define fc_mutex_impl_finish(M) FC_STMT_START {} FC_STMT_END + + +#else /* FC_NO_MT */ + +typedef int fc_mutex_impl_t; +#define FC_MUTEX_IMPL_INIT 0 +#define fc_mutex_impl_init(M) FC_STMT_START {} FC_STMT_END +#define fc_mutex_impl_lock(M) FC_STMT_START {} FC_STMT_END +#define fc_mutex_impl_unlock(M) FC_STMT_START {} FC_STMT_END +#define fc_mutex_impl_finish(M) FC_STMT_START {} FC_STMT_END + +#endif + + +#define FC_MUTEX_INIT {FC_MUTEX_IMPL_INIT} +typedef fc_mutex_impl_t FcMutex; +static inline void FcMutexInit (FcMutex *m) { fc_mutex_impl_init (m); } +static inline void FcMutexLock (FcMutex *m) { fc_mutex_impl_lock (m); } +static inline void FcMutexUnlock (FcMutex *m) { fc_mutex_impl_unlock (m); } +static inline void FcMutexFinish (FcMutex *m) { fc_mutex_impl_finish (m); } + + +#endif /* _FCMUTEX_H_ */ diff --git a/chromium/third_party/fontconfig/src/src/fcname.c b/chromium/third_party/fontconfig/src/src/fcname.c new file mode 100644 index 00000000000..712b2fad36c --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcname.c @@ -0,0 +1,584 @@ +/* + * 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> + +static const FcObjectType FcObjects[] = { +#define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME, Type }, +#include "fcobjs.h" +#undef FC_OBJECT +}; + +#define NUM_OBJECT_TYPES ((int) (sizeof FcObjects / sizeof FcObjects[0])) + +static const FcObjectType * +FcObjectFindById (FcObject object) +{ + if (1 <= object && object <= NUM_OBJECT_TYPES) + return &FcObjects[object - 1]; + return FcObjectLookupOtherTypeById (object); +} + +FcBool +FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes) +{ + /* Deprecated. */ + return FcFalse; +} + +FcBool +FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes) +{ + /* Deprecated. */ + return FcFalse; +} + +const FcObjectType * +FcNameGetObjectType (const char *object) +{ + int id = FcObjectLookupBuiltinIdByName (object); + + if (!id) + return FcObjectLookupOtherTypeByName (object); + + return &FcObjects[id - 1]; +} + +FcBool +FcObjectValidType (FcObject object, FcType type) +{ + const FcObjectType *t = FcObjectFindById (object); + + if (t) { + switch ((int) t->type) { + case FcTypeUnknown: + 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) +{ + return FcObjectLookupIdByName (name); +} + +FcObjectSet * +FcObjectGetSet (void) +{ + int i; + FcObjectSet *os = NULL; + + + os = FcObjectSetCreate (); + for (i = 0; i < NUM_OBJECT_TYPES; i++) + FcObjectSetAdd (os, FcObjects[i].object); + + return os; +} + +const char * +FcObjectName (FcObject object) +{ + const FcObjectType *o = FcObjectFindById (object); + + if (o) + return o->object; + + return FcObjectLookupOtherNameById (object); +} + +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 }, /* deprecated */ + { (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]) + +FcBool +FcNameRegisterConstants (const FcConstant *consts, int nconsts) +{ + /* Deprecated. */ + return FcFalse; +} + +FcBool +FcNameUnregisterConstants (const FcConstant *consts, int nconsts) +{ + /* Deprecated. */ + return FcFalse; +} + +const FcConstant * +FcNameGetConstant (const FcChar8 *string) +{ + unsigned int i; + + for (i = 0; i < NUM_FC_CONSTANTS; i++) + if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name)) + return &_FcBaseConstants[i]; + + return 0; +} + +FcBool +FcNameConstant (const 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) +{ + FcValue v; + FcMatrix m; + + v.type = type; + switch ((int) v.type) { + case FcTypeInteger: + if (!FcNameConstant (string, &v.u.i)) + v.u.i = atoi ((char *) string); + break; + case FcTypeString: + v.u.s = FcStrdup (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: + FcMatrixInit (&m); + sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy); + v.u.m = FcMatrixCopy (&m); + 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 (!isspace (c)) + break; + ++cur; + } + 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; + 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); + if (!FcPatternAdd (pat, t->object, v, FcTrue)) + { + FcValueDestroy (v); + goto bail2; + } + FcValueDestroy (v); + } + if (delim != ',') + break; + } + } + else + { + if ((c = FcNameGetConstant (save))) + { + t = FcNameGetObjectType ((char *) c->object); + switch ((int) 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 FcTypeUnknown: + 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; + + 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 (i = 0; i < NUM_OBJECT_TYPES; i++) + { + FcObject id = i + 1; + const FcObjectType *o; + o = &FcObjects[i]; + if (!strcmp (o->object, FC_FAMILY) || + !strcmp (o->object, FC_SIZE)) + continue; + + e = FcPatternObjectFindElt (pat, id); + 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/chromium/third_party/fontconfig/src/src/fcobjs.c b/chromium/third_party/fontconfig/src/src/fcobjs.c new file mode 100644 index 00000000000..bad9824d461 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcobjs.c @@ -0,0 +1,139 @@ +/* + * 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" + +static unsigned int +FcObjectTypeHash (register const char *str, register unsigned int len); + +static const struct FcObjectTypeInfo * +FcObjectTypeLookup (register const char *str, register unsigned int len); + +#include "fcobjshash.h" + +#include <string.h> + +/* The 1000 is to leave some room for future added internal objects, such + * that caches from newer fontconfig can still be used with older fontconfig + * without getting confused. */ +static fc_atomic_int_t next_id = FC_MAX_BASE_OBJECT + FC_EXT_OBJ_INDEX; +struct FcObjectOtherTypeInfo { + struct FcObjectOtherTypeInfo *next; + FcObjectType object; + FcObject id; +} *other_types; + +static FcObjectType * +_FcObjectLookupOtherTypeByName (const char *str, FcObject *id) +{ + struct FcObjectOtherTypeInfo *ots, *ot; + +retry: + ots = fc_atomic_ptr_get (&other_types); + + for (ot = ots; ot; ot = ot->next) + if (0 == strcmp (ot->object.object, str)) + break; + + if (!ot) + { + ot = malloc (sizeof (*ot)); + if (!ot) + return NULL; + + ot->object.object = (const char *) FcStrdup (str); + ot->object.type = FcTypeUnknown; + ot->id = fc_atomic_int_add (next_id, +1); + ot->next = ots; + + if (!fc_atomic_ptr_cmpexch (&other_types, ots, ot)) { + free (ot); + goto retry; + } + } + + if (id) + *id = ot->id; + + return &ot->object; +} + +FcObject +FcObjectLookupBuiltinIdByName (const char *str) +{ + const struct FcObjectTypeInfo *o = FcObjectTypeLookup (str, strlen (str)); + + if (o) + return o->id; + + return 0; +} + +FcObject +FcObjectLookupIdByName (const char *str) +{ + const struct FcObjectTypeInfo *o = FcObjectTypeLookup (str, strlen (str)); + FcObject id; + if (o) + return o->id; + + if (_FcObjectLookupOtherTypeByName (str, &id)) + return id; + + return 0; +} + +const char * +FcObjectLookupOtherNameById (FcObject id) +{ + struct FcObjectOtherTypeInfo *ot; + + for (ot = fc_atomic_ptr_get (&other_types); ot; ot = ot->next) + if (ot->id == id) + return ot->object.object; + + return NULL; +} + +const FcObjectType * +FcObjectLookupOtherTypeByName (const char *str) +{ + return _FcObjectLookupOtherTypeByName (str, NULL); +} + +FcPrivate const FcObjectType * +FcObjectLookupOtherTypeById (FcObject id) +{ + struct FcObjectOtherTypeInfo *ot; + + for (ot = fc_atomic_ptr_get (&other_types); ot; ot = ot->next) + if (ot->id == id) + return &ot->object; + + return NULL; +} + + +#include "fcaliastail.h" +#undef __fcobjs__ diff --git a/chromium/third_party/fontconfig/src/src/fcobjs.h b/chromium/third_party/fontconfig/src/src/fcobjs.h new file mode 100644 index 00000000000..87c7319e39a --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcobjs.h @@ -0,0 +1,48 @@ +/* DON'T REORDER! The order is part of the cache signature. */ +FC_OBJECT (FAMILY, FcTypeString, FcCompareFamily) +FC_OBJECT (FAMILYLANG, FcTypeString, NULL) +FC_OBJECT (STYLE, FcTypeString, FcCompareString) +FC_OBJECT (STYLELANG, FcTypeString, NULL) +FC_OBJECT (FULLNAME, FcTypeString, NULL) +FC_OBJECT (FULLNAMELANG, FcTypeString, NULL) +FC_OBJECT (SLANT, FcTypeInteger, FcCompareNumber) +FC_OBJECT (WEIGHT, FcTypeInteger, FcCompareNumber) +FC_OBJECT (WIDTH, FcTypeInteger, FcCompareNumber) +FC_OBJECT (SIZE, FcTypeDouble, NULL) +FC_OBJECT (ASPECT, FcTypeDouble, NULL) +FC_OBJECT (PIXEL_SIZE, FcTypeDouble, FcCompareSize) +FC_OBJECT (SPACING, FcTypeInteger, FcCompareNumber) +FC_OBJECT (FOUNDRY, FcTypeString, FcCompareString) +FC_OBJECT (ANTIALIAS, FcTypeBool, FcCompareBool) +FC_OBJECT (HINT_STYLE, FcTypeInteger, NULL) +FC_OBJECT (HINTING, FcTypeBool, NULL) +FC_OBJECT (VERTICAL_LAYOUT, FcTypeBool, NULL) +FC_OBJECT (AUTOHINT, FcTypeBool, NULL) +FC_OBJECT (GLOBAL_ADVANCE, FcTypeBool, NULL) /* deprecated */ +FC_OBJECT (FILE, FcTypeString, FcCompareFilename) +FC_OBJECT (INDEX, FcTypeInteger, NULL) +FC_OBJECT (RASTERIZER, FcTypeString, FcCompareString) +FC_OBJECT (OUTLINE, FcTypeBool, FcCompareBool) +FC_OBJECT (SCALABLE, FcTypeBool, FcCompareBool) +FC_OBJECT (DPI, FcTypeDouble, NULL) +FC_OBJECT (RGBA, FcTypeInteger, NULL) +FC_OBJECT (SCALE, FcTypeDouble, NULL) +FC_OBJECT (MINSPACE, FcTypeBool, NULL) +FC_OBJECT (CHAR_WIDTH, FcTypeInteger, NULL) +FC_OBJECT (CHAR_HEIGHT, FcTypeInteger, NULL) +FC_OBJECT (MATRIX, FcTypeMatrix, NULL) +FC_OBJECT (CHARSET, FcTypeCharSet, FcCompareCharSet) +FC_OBJECT (LANG, FcTypeLangSet, FcCompareLang) +FC_OBJECT (FONTVERSION, FcTypeInteger, FcCompareNumber) +FC_OBJECT (CAPABILITY, FcTypeString, NULL) +FC_OBJECT (FONTFORMAT, FcTypeString, FcCompareString) +FC_OBJECT (EMBOLDEN, FcTypeBool, NULL) +FC_OBJECT (EMBEDDED_BITMAP, FcTypeBool, NULL) +FC_OBJECT (DECORATIVE, FcTypeBool, FcCompareBool) +FC_OBJECT (LCD_FILTER, FcTypeInteger, NULL) +FC_OBJECT (NAMELANG, FcTypeString, NULL) +FC_OBJECT (FONT_FEATURES, FcTypeString, NULL) +FC_OBJECT (PRGNAME, FcTypeString, NULL) +FC_OBJECT (HASH, FcTypeString, FcCompareHash) +FC_OBJECT (POSTSCRIPT_NAME, FcTypeString, FcComparePostScript) +/* ^-------------- Add new objects here. */ diff --git a/chromium/third_party/fontconfig/src/src/fcobjshash.gperf.h b/chromium/third_party/fontconfig/src/src/fcobjshash.gperf.h new file mode 100644 index 00000000000..ca23c026116 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcobjshash.gperf.h @@ -0,0 +1,26 @@ +%{ +CUT_OUT_BEGIN +#include <fontconfig/fontconfig.h> +CUT_OUT_END +%} +%struct-type +%language=ANSI-C +%includes +%enum +%readonly-tables +%define slot-name name +%define hash-function-name FcObjectTypeHash +%define lookup-function-name FcObjectTypeLookup + +%pic +%define string-pool-name FcObjectTypeNamePool + +struct FcObjectTypeInfo { + int name; + int id; +}; + +%% +#define FC_OBJECT(NAME, Type, Cmp) FC_##NAME, FC_##NAME##_OBJECT +#include "fcobjs.h" +#undef FC_OBJECT diff --git a/chromium/third_party/fontconfig/src/src/fcpat.c b/chromium/third_party/fontconfig/src/src/fcpat.c new file mode 100644 index 00000000000..0614ac2c239 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcpat.c @@ -0,0 +1,1316 @@ +/* + * 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" + +/* Objects MT-safe for readonly access. */ + +FcPattern * +FcPatternCreate (void) +{ + FcPattern *p; + + p = (FcPattern *) malloc (sizeof (FcPattern)); + if (!p) + return 0; + p->num = 0; + p->size = 0; + p->elts_offset = FcPtrToOffset (p, NULL); + FcRefInit (&p->ref, 1); + return p; +} + +void +FcValueDestroy (FcValue v) +{ + switch ((int) v.type) { + case FcTypeString: + FcFree (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 ((int) 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 ((int) v.type) { + case FcTypeString: + v.u.s = FcStrdup (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; +} + +FcValueListPtr +FcValueListCreate (void) +{ + return calloc (1, sizeof (FcValueList)); +} + +void +FcValueListDestroy (FcValueListPtr l) +{ + FcValueListPtr next; + for (; l; l = next) + { + switch ((int) l->value.type) { + case FcTypeString: + FcFree (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); + free(l); + } +} + +FcValueListPtr +FcValueListPrepend (FcValueListPtr vallist, + FcValue value, + FcValueBinding binding) +{ + FcValueListPtr new; + + if (value.type == FcTypeVoid) + return vallist; + new = FcValueListCreate (); + if (!new) + return vallist; + + new->value = FcValueSave (value); + new->binding = binding; + new->next = vallist; + + return new; +} + +FcValueListPtr +FcValueListAppend (FcValueListPtr vallist, + FcValue value, + FcValueBinding binding) +{ + FcValueListPtr new, last; + + if (value.type == FcTypeVoid) + return vallist; + new = FcValueListCreate (); + if (!new) + return vallist; + + new->value = FcValueSave (value); + new->binding = binding; + new->next = NULL; + + if (vallist) + { + for (last = vallist; FcValueListNext (last); last = FcValueListNext (last)); + + last->next = new; + } + else + vallist = new; + + return vallist; +} + +FcValueListPtr +FcValueListDuplicate(FcValueListPtr orig) +{ + FcValueListPtr new = NULL, l, t = NULL; + FcValue v; + + for (l = orig; l != NULL; l = FcValueListNext (l)) + { + if (!new) + { + t = new = FcValueListCreate(); + } + else + { + t->next = FcValueListCreate(); + t = FcValueListNext (t); + } + v = FcValueCanonicalize (&l->value); + t->value = FcValueSave (v); + t->binding = l->binding; + t->next = NULL; + } + + return new; +} + +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 FcTypeUnknown: + return FcFalse; /* don't know how to compare this object */ + 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 FcTypeUnknown: + 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 0; +} + +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) + return; + + if (FcRefIsConst (&p->ref)) + { + FcCacheObjectDereference (p); + return; + } + + if (FcRefDec (&p->ref) != 1) + return; + + elts = FcPatternElts (p); + for (i = 0; i < p->num; i++) + FcValueListDestroy (FcPatternEltValues(&elts[i])); + + free (elts); + 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); + 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 +FcPatternObjectListAdd (FcPattern *p, + FcObject object, + FcValueListPtr list, + FcBool append) +{ + FcPatternElt *e; + FcValueListPtr l, *prev; + + if (FcRefIsConst (&p->ref)) + goto bail0; + + /* + * Make sure the stored type is valid for built-in objects + */ + for (l = list; l != NULL; l = FcValueListNext (l)) + { + if (!FcObjectValidType (object, l->value.type)) + { + fprintf (stderr, + "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); + FcValuePrintFile (stderr, l->value); + fprintf (stderr, "\n"); + goto bail0; + } + } + + e = FcPatternObjectInsertElt (p, object); + if (!e) + goto bail0; + + if (append) + { + for (prev = &e->values; *prev; prev = &(*prev)->next) + ; + *prev = list; + } + else + { + for (prev = &list; *prev; prev = &(*prev)->next) + ; + *prev = e->values; + e->values = list; + } + + return FcTrue; + +bail0: + return FcFalse; +} + +FcBool +FcPatternObjectAddWithBinding (FcPattern *p, + FcObject object, + FcValue value, + FcValueBinding binding, + FcBool append) +{ + FcPatternElt *e; + FcValueListPtr new, *prev; + + if (FcRefIsConst (&p->ref)) + goto bail0; + + new = FcValueListCreate (); + if (!new) + goto bail0; + + 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)) + { + fprintf (stderr, + "Fontconfig warning: FcPattern object %s does not accept value", + FcObjectName (object)); + FcValuePrintFile (stderr, value); + fprintf (stderr, "\n"); + 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: + 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 = 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; + + if (!p) + return FcResultNoMatch; + 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 ((int) 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 ((int) 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 (!FcRefIsConst (&p->ref)) + FcRefInc (&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; +} + + +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; + FcRefSetConst (&pat_serialized->ref); + + 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 ((int) 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 ((int) 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/chromium/third_party/fontconfig/src/src/fcserialize.c b/chromium/third_party/fontconfig/src/src/fcserialize.c new file mode 100644 index 00000000000..d2f221df82c --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcserialize.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2006 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. + */ + +#include "fcint.h" + +intptr_t +FcAlignSize (intptr_t size) +{ + intptr_t rem = size % sizeof (FcAlign); + if (rem) + size += sizeof (FcAlign) - rem; + return size; +} + +/* + * Serialization helper object -- allocate space in the + * yet-to-be-created linear array for a serialized font set + */ + +FcSerialize * +FcSerializeCreate (void) +{ + FcSerialize *serialize; + + serialize = malloc (sizeof (FcSerialize)); + if (!serialize) + return NULL; + serialize->size = 0; + serialize->linear = NULL; + serialize->cs_freezer = NULL; + memset (serialize->buckets, '\0', sizeof (serialize->buckets)); + return serialize; +} + +void +FcSerializeDestroy (FcSerialize *serialize) +{ + uintptr_t bucket; + + for (bucket = 0; bucket < FC_SERIALIZE_HASH_SIZE; bucket++) + { + FcSerializeBucket *buck, *next; + + for (buck = serialize->buckets[bucket]; buck; buck = next) { + next = buck->next; + free (buck); + } + } + if (serialize->cs_freezer) + FcCharSetFreezerDestroy (serialize->cs_freezer); + free (serialize); +} + +/* + * Allocate space for an object in the serialized array. Keep track + * of where the object is placed and only allocate one copy of each object + */ + +FcBool +FcSerializeAlloc (FcSerialize *serialize, const void *object, int size) +{ + uintptr_t bucket = ((uintptr_t) object) % FC_SERIALIZE_HASH_SIZE; + FcSerializeBucket *buck; + + for (buck = serialize->buckets[bucket]; buck; buck = buck->next) + if (buck->object == object) + return FcTrue; + buck = malloc (sizeof (FcSerializeBucket)); + if (!buck) + return FcFalse; + buck->object = object; + buck->offset = serialize->size; + buck->next = serialize->buckets[bucket]; + serialize->buckets[bucket] = buck; + serialize->size += FcAlignSize (size); + return FcTrue; +} + +/* + * Reserve space in the serialization array + */ +intptr_t +FcSerializeReserve (FcSerialize *serialize, int size) +{ + intptr_t offset = serialize->size; + serialize->size += FcAlignSize (size); + return offset; +} + +/* + * Given an object, return the offset in the serialized array where + * the serialized copy of the object is stored + */ +intptr_t +FcSerializeOffset (FcSerialize *serialize, const void *object) +{ + uintptr_t bucket = ((uintptr_t) object) % FC_SERIALIZE_HASH_SIZE; + FcSerializeBucket *buck; + + for (buck = serialize->buckets[bucket]; buck; buck = buck->next) + if (buck->object == object) + return buck->offset; + return 0; +} + +/* + * Given a cache and an object, return a pointer to where + * the serialized copy of the object is stored + */ +void * +FcSerializePtr (FcSerialize *serialize, const void *object) +{ + intptr_t offset = FcSerializeOffset (serialize, object); + + if (!offset) + return NULL; + return (void *) ((char *) serialize->linear + offset); +} + +FcBool +FcStrSerializeAlloc (FcSerialize *serialize, const FcChar8 *str) +{ + return FcSerializeAlloc (serialize, str, strlen ((const char *) str) + 1); +} + +FcChar8 * +FcStrSerialize (FcSerialize *serialize, const FcChar8 *str) +{ + FcChar8 *str_serialize = FcSerializePtr (serialize, str); + if (!str_serialize) + return NULL; + strcpy ((char *) str_serialize, (const char *) str); + return str_serialize; +} +#include "fcaliastail.h" +#undef __fcserialize__ diff --git a/chromium/third_party/fontconfig/src/src/fcstat.c b/chromium/third_party/fontconfig/src/src/fcstat.c new file mode 100644 index 00000000000..ff8e88455ef --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcstat.c @@ -0,0 +1,361 @@ +/* + * 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 <dirent.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifdef HAVE_SYS_VFS_H +#include <sys/vfs.h> +#endif +#ifdef HAVE_SYS_STATFS_H +#include <sys/statfs.h> +#endif +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#ifdef HAVE_SYS_MOUNT_H +#include <sys/mount.h> +#endif + +#ifdef _WIN32 +#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 FcChar8 *file, struct stat *statb) +{ + WIN32_FILE_ATTRIBUTE_DATA wfad; + char full_path_name[MAX_PATH]; + char *basename; + DWORD rc; + + if (!GetFileAttributesEx ((LPCSTR) 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 ((LPCSTR) 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 ((const FcChar8 *) 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 FcChar8 *file, struct stat *statb) +{ + return stat ((char *) file, statb); +} + +/* Adler-32 checksum implementation */ +struct Adler32 { + int a; + int b; +}; + +static void +Adler32Init (struct Adler32 *ctx) +{ + ctx->a = 1; + ctx->b = 0; +} + +static void +Adler32Update (struct Adler32 *ctx, const char *data, int data_len) +{ + while (data_len--) + { + ctx->a = (ctx->a + *data++) % 65521; + ctx->b = (ctx->b + ctx->a) % 65521; + } +} + +static int +Adler32Finish (struct Adler32 *ctx) +{ + return ctx->a + (ctx->b << 16); +} + +#ifdef HAVE_STRUCT_DIRENT_D_TYPE +/* dirent.d_type can be relied upon on FAT filesystem */ +static FcBool +FcDirChecksumScandirFilter(const struct dirent *entry) +{ + return entry->d_type != DT_DIR; +} +#endif + +#ifdef HAVE_SCANDIR +static int +FcDirChecksumScandirSorter(const struct dirent **lhs, const struct dirent **rhs) +{ + return strcmp((*lhs)->d_name, (*rhs)->d_name); +} +#elif HAVE_SCANDIR_VOID_P +static int +FcDirChecksumScandirSorter(const void *a, const void *b) +{ + const struct dirent *lhs = a, *rhs = b; + + return strcmp(lhs->d_name, rhs->d_name); +} +#endif + +static int +FcDirChecksum (const FcChar8 *dir, time_t *checksum) +{ + struct Adler32 ctx; + struct dirent **files; + int n; +#ifndef HAVE_STRUCT_DIRENT_D_TYPE + int ret = 0; + size_t len = strlen ((const char *)dir); +#endif + + Adler32Init (&ctx); + + n = scandir ((const char *)dir, &files, +#ifdef HAVE_STRUCT_DIRENT_D_TYPE + &FcDirChecksumScandirFilter, +#else + NULL, +#endif + &FcDirChecksumScandirSorter); + if (n == -1) + return -1; + + while (n--) + { + size_t dlen = strlen (files[n]->d_name); + int dtype; + +#ifdef HAVE_STRUCT_DIRENT_D_TYPE + dtype = files[n]->d_type; +#else + struct stat statb; + char f[PATH_MAX + 1]; + + memcpy (f, dir, len); + f[len] = FC_DIR_SEPARATOR; + memcpy (&f[len + 1], files[n]->d_name, dlen); + f[len + 1 + dlen] = 0; + if (lstat (f, &statb) < 0) + { + ret = -1; + goto bail; + } + if (S_ISDIR (statb.st_mode)) + goto bail; + + dtype = statb.st_mode; +#endif + Adler32Update (&ctx, files[n]->d_name, dlen + 1); + Adler32Update (&ctx, (char *)&dtype, sizeof (int)); + +#ifndef HAVE_STRUCT_DIRENT_D_TYPE + bail: +#endif + free (files[n]); + } + free (files); +#ifndef HAVE_STRUCT_DIRENT_D_TYPE + if (ret == -1) + return -1; +#endif + + *checksum = Adler32Finish (&ctx); + + return 0; +} +#endif /* _WIN32 */ + +int +FcStatChecksum (const FcChar8 *file, struct stat *statb) +{ + if (FcStat (file, statb) == -1) + return -1; + +#ifndef _WIN32 + /* We have a workaround of the broken stat() in FcStat() for Win32. + * No need to do something further more. + */ + if (FcIsFsMtimeBroken (file)) + { + if (FcDirChecksum (file, &statb->st_mtime) == -1) + return -1; + } +#endif + + return 0; +} + +static int +FcFStatFs (int fd, FcStatFS *statb) +{ + const char *p = NULL; + int ret = -1; + FcBool flag = FcFalse; + +#if defined(HAVE_FSTATVFS) && (defined(HAVE_STRUCT_STATVFS_F_BASETYPE) || defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)) + struct statvfs buf; + + memset (statb, 0, sizeof (FcStatFS)); + + if ((ret = fstatvfs (fd, &buf)) == 0) + { +# if defined(HAVE_STRUCT_STATVFS_F_BASETYPE) + p = buf.f_basetype; +# elif defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME) + p = buf.f_fstypename; +# endif + } +#elif defined(HAVE_FSTATFS) && (defined(HAVE_STRUCT_STATFS_F_FLAGS) || defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(__linux__)) + struct statfs buf; + + memset (statb, 0, sizeof (FcStatFS)); + + if ((ret = fstatfs (fd, &buf)) == 0) + { +# if defined(HAVE_STRUCT_STATFS_F_FLAGS) && defined(MNT_LOCAL) + statb->is_remote_fs = !(buf.f_flags & MNT_LOCAL); + flag = FcTrue; +# endif +# if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) + p = buf.f_fstypename; +# elif defined(__linux__) + switch (buf.f_type) + { + case 0x6969: /* nfs */ + statb->is_remote_fs = FcTrue; + break; + case 0x4d44: /* fat */ + statb->is_mtime_broken = FcTrue; + break; + default: + break; + } + + return ret; +# else +# error "BUG: No way to figure out with fstatfs()" +# endif + } +#endif + if (p) + { + if (!flag && strcmp (p, "nfs") == 0) + statb->is_remote_fs = FcTrue; + if (strcmp (p, "msdosfs") == 0 || + strcmp (p, "pcfs") == 0) + statb->is_mtime_broken = FcTrue; + } + + return ret; +} + +FcBool +FcIsFsMmapSafe (int fd) +{ + FcStatFS statb; + + if (FcFStatFs (fd, &statb) < 0) + return FcTrue; + + return !statb.is_remote_fs; +} + +FcBool +FcIsFsMtimeBroken (const FcChar8 *dir) +{ + int fd = FcOpen ((const char *) dir, O_RDONLY); + + if (fd != -1) + { + FcStatFS statb; + int ret = FcFStatFs (fd, &statb); + + close (fd); + if (ret < 0) + return FcFalse; + + return statb.is_mtime_broken; + } + + return FcFalse; +} diff --git a/chromium/third_party/fontconfig/src/src/fcstr.c b/chromium/third_party/fontconfig/src/src/fcstr.c new file mode 100644 index 00000000000..57071724315 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcstr.c @@ -0,0 +1,1400 @@ +/* + * 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 HAVE_REGEX_H +#include <regex.h> +#endif + + +/* Objects MT-safe for readonly access. */ + +FcChar8 * +FcStrCopy (const FcChar8 *s) +{ + return FcStrdup (s); +} + +FcChar8 * +FcStrPlus (const FcChar8 *s1, const FcChar8 *s2) +{ + int s1l = strlen ((char *) s1); + int s2l = strlen ((char *) s2); + int l = s1l + s2l + 1; + FcChar8 *s = malloc (l); + + if (!s) + return 0; + memcpy (s, s1, s1l); + memcpy (s + s1l, s2, s2l + 1); + return s; +} + +void +FcStrFree (FcChar8 *s) +{ + free (s); +} + + +#include "../fc-case/fccase.h" + +#define FcCaseFoldUpperCount(cf) \ + ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) + +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, const char *delims) +{ + FcChar8 r; + + if (w->read) + { + if ((r = *w->read++)) + return r; + w->read = 0; + } + do + { + r = *w->src++; + } while (r != 0 && delims && strchr (delims, 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, NULL)) + len++; + d = dst = malloc (len + 1); + if (!d) + return 0; + FcStrCaseWalkerInit (s, &w); + while ((*d++ = FcStrCaseWalkerNext (&w, NULL))); + 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, NULL); + c2 = FcStrCaseWalkerNext (&w2, NULL); + if (!c1 || (c1 != c2)) + break; + } + return (int) c1 - (int) c2; +} + +int +FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) +{ + return FcStrCmpIgnoreCaseAndDelims (s1, s2, (const FcChar8 *)" "); +} + +int +FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + if (s1 == s2) return 0; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); + c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); + 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; +} + +#ifdef USE_REGEX +static FcBool +_FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex, int cflags, int eflags) +{ + int ret = -1; + regex_t reg; + + if ((ret = regcomp (®, (const char *)regex, cflags)) != 0) + { + if (FcDebug () & FC_DBG_MATCHV) + { + char buf[512]; + + regerror (ret, ®, buf, 512); + printf("Regexp compile error: %s\n", buf); + } + return FcFalse; + } + ret = regexec (®, (const char *)s, 0, NULL, eflags); + if (ret != 0) + { + if (FcDebug () & FC_DBG_MATCHV) + { + char buf[512]; + + regerror (ret, ®, buf, 512); + printf("Regexp exec error: %s\n", buf); + } + } + regfree (®); + + return ret == 0 ? FcTrue : FcFalse; +} +#else +# define _FcStrRegexCmp(_s_, _regex_, _cflags_, _eflags_) (FcFalse) +#endif + +FcBool +FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex) +{ + return _FcStrRegexCmp (s, regex, REG_EXTENDED | REG_NOSUB, 0); +} + +FcBool +FcStrRegexCmpIgnoreCase (const FcChar8 *s, const FcChar8 *regex) +{ + return _FcStrRegexCmp (s, regex, REG_EXTENDED | REG_NOSUB | REG_ICASE, 0); +} + +/* + * 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, NULL))) + 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 = 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 * +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, NULL); + c2 = FcStrCaseWalkerNext (&w2, NULL); + 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; +} + +/* + * returns the number of strings (ignoring delimitors and case) being matched + */ + +int +FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + if (s1 == s2) return 0; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); + c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); + if (!c1 || (c1 != c2)) + break; + } + return w1.src - s1 - 1; +} + +FcBool +FcStrGlobMatch (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) + { + size_t l1, l2; + + l1 = strlen ((char *) string); + l2 = strlen ((char *) glob); + if (l1 < l2) + return FcFalse; + string += (l1 - l2); + } + while (*string) + { + if (FcStrGlobMatch (glob, string)) + return FcTrue; + string++; + } + return FcFalse; + case '?': + if (*string++ == '\0') + return FcFalse; + break; + default: + if (*string++ != c) + return FcFalse; + break; + } + } + return *string == '\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, NULL); + + for (;;) + { + cur = w1.src; + c1 = FcStrCaseWalkerNext (&w1, NULL); + if (!c1) + break; + if (c1 == c2) + { + FcCaseWalker w1t = w1; + FcCaseWalker w2t = w2; + FcChar8 c1t, c2t; + + for (;;) + { + c1t = FcStrCaseWalkerNext (&w1t, NULL); + c2t = FcStrCaseWalkerNext (&w2t, NULL); + + 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) + { + 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) + { + 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; + } + 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 * +FcStrBuildFilename (const FcChar8 *path, + ...) +{ + va_list ap; + FcStrSet *sset = FcStrSetCreate (); + FcStrList *list; + FcChar8 *s, *ret = NULL, *p; + size_t len = 0; + + if (!sset || !path) + return NULL; + + if (!FcStrSetAdd (sset, path)) + goto bail0; + + va_start (ap, path); + while (1) + { + s = (FcChar8 *)va_arg (ap, FcChar8 *); + if (!s) + break; + if (!FcStrSetAdd (sset, s)) + goto bail1; + } + list = FcStrListCreate (sset); + while ((s = FcStrListNext (list))) + { + len += strlen ((const char *)s) + 1; + } + list->n = 0; + ret = malloc (sizeof (FcChar8) * (len + 1)); + if (!ret) + goto bail2; + p = ret; + while ((s = FcStrListNext (list))) + { + if (p != ret) + { + p[0] = FC_DIR_SEPARATOR; + p++; + } + len = strlen ((const char *)s); + memcpy (p, s, len); + p += len; + } + *p = 0; + +bail2: + FcStrListDone (list); +bail1: + va_end (ap); +bail0: + FcStrSetDestroy (sset); + + return ret; +} + +FcChar8 * +FcStrCopyFilename (const FcChar8 *s) +{ + FcChar8 *new; + + if (*s == '~') + { + FcChar8 *home = FcConfigHome (); + FcChar8 *full; + int size; + if (!home) + return NULL; + size = strlen ((char *) home) + strlen ((char *) s); + full = (FcChar8 *) malloc (size); + if (!full) + return NULL; + 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; + 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; + slash = NULL; + f = file; +#ifdef _WIN32 + if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */ + *f++ = *s++; +#endif + 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 ((LPCSTR) s, sizeof (full) -1, + (LPSTR) full, NULL); + + if (size == 0) + perror ("GetFullPathName"); + + FcConvertDosPath ((char *) 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; + full = FcStrBuildFilename (cwd, s, NULL); + file = FcStrCanonAbsoluteFilename (full); + FcStrFree (full); + return file; + } +#endif +} + + +FcStrSet * +FcStrSetCreate (void) +{ + FcStrSet *set = malloc (sizeof (FcStrSet)); + if (!set) + return 0; + FcRefInit (&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; + if (set->num) + memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); + if (set->strs) + 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 +FcStrSetAddLangs (FcStrSet *strs, const char *languages) +{ + const char *p = languages, *next; + FcChar8 lang[128] = {0}, *normalized_lang; + size_t len; + FcBool ret = FcFalse; + + if (!languages) + return FcFalse; + + while ((next = strchr (p, ':'))) + { + len = next - p; + len = FC_MIN (len, 127); + strncpy ((char *) lang, p, len); + lang[len] = 0; + /* ignore an empty item */ + if (*lang) + { + normalized_lang = FcLangNormalize ((const FcChar8 *) lang); + if (normalized_lang) + { + FcStrSetAdd (strs, normalized_lang); + FcStrFree (normalized_lang); + ret = FcTrue; + } + } + p = next + 1; + } + if (*p) + { + normalized_lang = FcLangNormalize ((const FcChar8 *) p); + if (normalized_lang) + { + FcStrSetAdd (strs, normalized_lang); + FcStrFree (normalized_lang); + ret = FcTrue; + } + } + + return ret; +} + +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; +} + +/* TODO Make public */ +static FcStrSet * +FcStrSetReference (FcStrSet *set) +{ + if (FcRefIsConst (&set->ref)) + return set; + + FcRefInc (&set->ref); + return set; +} + +void +FcStrSetDestroy (FcStrSet *set) +{ + int i; + + /* We rely on this in FcGetDefaultLangs for caching. */ + if (FcRefIsConst (&set->ref)) + return; + + if (FcRefDec (&set->ref) != 1) + return; + + for (i = 0; i < set->num; i++) + FcStrFree (set->strs[i]); + if (set->strs) + free (set->strs); + free (set); +} + +FcStrList * +FcStrListCreate (FcStrSet *set) +{ + FcStrList *list; + + list = malloc (sizeof (FcStrList)); + if (!list) + return 0; + list->set = set; + FcStrSetReference (set); + list->n = 0; + return list; +} + +void +FcStrListFirst (FcStrList *list) +{ + list->n = 0; +} + +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); + free (list); +} + +#define __fcstr__ +#include "fcaliastail.h" +#undef __fcstr__ diff --git a/chromium/third_party/fontconfig/src/src/fcwindows.h b/chromium/third_party/fontconfig/src/src/fcwindows.h new file mode 100644 index 00000000000..02489d9dc1b --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcwindows.h @@ -0,0 +1,44 @@ +/* + * fontconfig/src/fcwindows.h + * + * Copyright © 2013 Google, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of 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. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef _FCWINDOWS_H_ +#define _FCWINDOWS_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef _WIN32 +# ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0500 +# endif +# define WIN32_LEAN_AND_MEAN +# define WIN32_EXTRA_LEAN +# define STRICT +# include <windows.h> +#endif + +#endif /* _FCWINDOWS_H_ */ diff --git a/chromium/third_party/fontconfig/src/src/fcxml.c b/chromium/third_party/fontconfig/src/src/fcxml.c new file mode 100644 index 00000000000..8ff10b6e63f --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/fcxml.c @@ -0,0 +1,3207 @@ +/* + * 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) +{ + FcExprDestroy (test->expr); + free (test); +} + +void +FcRuleDestroy (FcRule *rule) +{ + FcRule *n = rule->next; + + switch (rule->type) { + case FcRuleTest: + FcTestDestroy (rule->u.test); + break; + case FcRuleEdit: + FcEditDestroy (rule->u.edit); + break; + default: + break; + } + free (rule); + if (n) + FcRuleDestroy (n); +} + +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 = FcStrdup (s); + } + return e; +} + +static FcExprMatrix * +FcExprMatrixCopyShallow (const FcExprMatrix *matrix) +{ + FcExprMatrix *m = malloc (sizeof (FcExprMatrix)); + if (m) + { + *m = *matrix; + } + return m; +} + +static void +FcExprMatrixFreeShallow (FcExprMatrix *m) +{ + if (!m) + return; + + free (m); +} + +static void +FcExprMatrixFree (FcExprMatrix *m) +{ + if (!m) + return; + + FcExprDestroy (m->xx); + FcExprDestroy (m->xy); + FcExprDestroy (m->yx); + FcExprDestroy (m->yy); + + free (m); +} + +static FcExpr * +FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpMatrix; + e->u.mexpr = FcExprMatrixCopyShallow (matrix); + } + 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 * +FcExprCreateName (FcConfig *config, FcExprName name) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpField; + e->u.name = name; + } + return e; +} + +static FcExpr * +FcExprCreateConst (FcConfig *config, const FcChar8 *constant) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpConst; + e->u.constant = FcStrdup (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 (FC_OP_GET_OP (e->op)) { + case FcOpInteger: + break; + case FcOpDouble: + break; + case FcOpString: + FcFree (e->u.sval); + break; + case FcOpMatrix: + FcExprMatrixFree (e->u.mexpr); + 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: + FcFree (e->u.constant); + break; + case FcOpAssign: + case FcOpAssignReplace: + case FcOpPrepend: + case FcOpPrependFirst: + case FcOpAppend: + case FcOpAppendLast: + case FcOpDelete: + case FcOpDeleteAll: + 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->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, + FcVStackConstant, + FcVStackGlob, + FcVStackName, + 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; + FcExprMatrix *matrix; + FcRange range; + FcBool bool_; + FcCharSet *charset; + FcLangSet *langset; + FcExprName name; + + 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; + unsigned int pstack_static_used; + FcPStack pstack_static[8]; + unsigned 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 FcExpr * +FcPopExpr (FcConfigParse *parse); + + +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; + /* It's perfectly fine to use user-define elements in expressions, + * so don't warn in that case. */ + if (value == (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 (FC_OP_GET_OP (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.name.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, + unsigned int compare, + FcExpr *expr) +{ + FcTest *test = (FcTest *) malloc (sizeof (FcTest)); + + if (test) + { + const FcObjectType *o; + + 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->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 FcRule * +FcRuleCreate (FcRuleType type, + void *p) +{ + FcRule *r = (FcRule *) malloc (sizeof (FcRule)); + + if (!r) + return NULL; + + r->next = NULL; + r->type = type; + switch (type) + { + case FcRuleTest: + r->u.test = (FcTest *) p; + break; + case FcRuleEdit: + r->u.edit = (FcEdit *) p; + break; + default: + free (r); + r = NULL; + break; + } + + return r; +} + +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; + } + 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, FcExprMatrix *matrix) +{ + FcVStack *vstack; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.matrix = FcExprMatrixCopyShallow (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 +FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.name.object = object; + vstack->u.name.kind = kind; + vstack->tag = FcVStackName; + 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 FcVStackName: + break; + case FcVStackFamily: + break; + case FcVStackString: + case FcVStackConstant: + case FcVStackGlob: + FcStrFree (vstack->u.string); + break; + case FcVStackPattern: + FcPatternDestroy (vstack->u.pattern); + break; + case FcVStackInteger: + case FcVStackDouble: + break; + case FcVStackMatrix: + FcExprMatrixFreeShallow (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 + 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; + } + } + 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; + } + + 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; + } + + if (parse->pstack->attr) + { + /* Warn about unused attrs. */ + FcChar8 **attrs = parse->pstack->attr; + while (*attrs) + { + if (attrs[0][0]) + { + FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]); + } + attrs += 2; + } + } + + FcVStackClear (parse); + old = parse->pstack; + parse->pstack = old->prev; + FcStrBufDestroy (&old->str); + + if (old->attr && old->attr != old->attr_buf_static) + free (old->attr); + + if (old == &parse->pstack_static[parse->pstack_static_used - 1]) + parse->pstack_static_used--; + else + free (old); + return FcTrue; +} + +static FcBool +FcConfigParseInit (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)) + { + attrs[0][0] = '\0'; /* Mark as used. */ + 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 ((int) 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 +FcParseName (FcConfigParse *parse) +{ + const FcChar8 *kind_string; + FcMatchKind kind; + FcChar8 *s; + FcObject object; + + 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, "default")) + kind = FcMatchDefault; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string); + return; + } + } + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + object = FcObjectFromName ((const char *) s); + + FcVStackPushName (parse, kind, object); + + FcStrFree (s); +} + +static void +FcParseMatrix (FcConfigParse *parse) +{ + FcExprMatrix m; + + m.yy = FcPopExpr (parse); + m.yx = FcPopExpr (parse); + m.xy = FcPopExpr (parse); + m.xx = FcPopExpr (parse); + + if (FcPopExpr (parse)) + FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); + else + FcVStackPushMatrix (parse, &m); +} + +static void +FcParseRange (FcConfigParse *parse) +{ + FcVStack *vstack; + FcRange r = {0, 0}; + FcChar32 n; + int count = 1; + + while ((vstack = FcVStackPeek (parse))) + { + if (count < 0) + { + FcConfigMessage (parse, FcSevereError, "too many elements in range"); + return; + } + switch ((int) vstack->tag) { + case FcVStackInteger: + n = vstack->u.integer; + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in range"); + n = 0; + 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 ((int) 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 ((int) 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; + FcVStack *vstack; + FcRule *rule = NULL, *r; + FcValueBinding binding; + + if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) + return; + while ((vstack = FcVStackPeek (parse))) + { + switch ((int) vstack->tag) { + case FcVStackFamily: + if (family) + { + FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected"); + 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; + case FcVStackTest: + if (rule) + { + r = FcRuleCreate (FcRuleTest, vstack->u.test); + r->next = rule; + rule = r; + } + else + rule = FcRuleCreate (FcRuleTest, vstack->u.test); + 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); + if (rule) + FcRuleDestroy (rule); + return; + } + if (!prefer && + !accept && + !def) + { + FcExprDestroy (family); + return; + } + else + { + FcTest *t = FcTestCreate (parse, FcMatchPattern, + FcQualAny, + (FcChar8 *) FC_FAMILY, + FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks), + family); + if (rule) + { + for (r = rule; r->next; r = r->next); + r->next = FcRuleCreate (FcRuleTest, t); + r = r->next; + } + else + { + r = rule = FcRuleCreate (FcRuleTest, t); + } + } + if (prefer) + { + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpPrepend, + prefer, + binding); + if (!edit) + FcExprDestroy (prefer); + else + { + r->next = FcRuleCreate (FcRuleEdit, edit); + r = r->next; + } + } + if (accept) + { + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppend, + accept, + binding); + if (!edit) + FcExprDestroy (accept); + else + { + r->next = FcRuleCreate (FcRuleEdit, edit); + r = r->next; + } + } + if (def) + { + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppendLast, + def, + binding); + if (!edit) + FcExprDestroy (def); + else + { + r->next = FcRuleCreate (FcRuleEdit, edit); + r = r->next; + } + } + if (!FcConfigAddRule (parse->config, rule, FcMatchPattern)) + FcRuleDestroy (rule); +} + +static FcExpr * +FcPopExpr (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPeek (parse); + FcExpr *expr = 0; + if (!vstack) + return 0; + switch ((int) vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + expr = FcExprCreateString (parse->config, vstack->u.string); + break; + case FcVStackName: + expr = FcExprCreateName (parse->config, vstack->u.name); + 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 +FcParseDir (FcConfigParse *parse) +{ + const FcChar8 *attr, *data; + FcChar8 *prefix = NULL, *p; +#ifdef _WIN32 + FcChar8 buffer[1000]; +#endif + + attr = FcConfigGetAttribute (parse, "prefix"); + if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) + prefix = FcConfigXdgDataHome (); + data = FcStrBufDoneStatic (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + data = prefix; + goto bail; + } + if (prefix) + { + size_t plen = strlen ((const char *)prefix); + size_t dlen = strlen ((const char *)data); + + p = realloc (prefix, plen + 1 + dlen + 1); + if (!p) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + goto bail; + } + prefix = p; + prefix[plen] = FC_DIR_SEPARATOR; + memcpy (&prefix[plen + 1], data, dlen); + prefix[plen + 1 + dlen] = 0; + data = prefix; + } +#ifdef _WIN32 + if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0) + { + FcChar8 *p; + data = buffer; + if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20)) + { + FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); + goto bail; + } + /* + * 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 ((char *) data, "\\fonts"); + } + else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0) + { + FcChar8 *p; + data = buffer; + if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20)) + { + FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); + goto bail; + } + p = _mbsrchr (data, '\\'); + if (p) *p = '\0'; + strcat ((char *) data, "\\..\\share\\fonts"); + } + else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0) + { + int rc; + data = buffer; + rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20); + if (rc == 0 || rc > sizeof (buffer) - 20) + { + FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed"); + goto bail; + } + if (data [strlen ((const char *) data) - 1] != '\\') + strcat ((char *) data, "\\"); + strcat ((char *) 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); + + bail: + if (prefix) + FcStrFree (prefix); +} + +static void +FcParseCacheDir (FcConfigParse *parse) +{ + const FcChar8 *attr; + FcChar8 *prefix = NULL, *p, *data; + + attr = FcConfigGetAttribute (parse, "prefix"); + if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) + prefix = FcConfigXdgCacheHome (); + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + goto bail; + } + if (prefix) + { + size_t plen = strlen ((const char *)prefix); + size_t dlen = strlen ((const char *)data); + + p = realloc (prefix, plen + 1 + dlen + 1); + if (!p) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + data = prefix; + goto bail; + } + prefix = p; + prefix[plen] = FC_DIR_SEPARATOR; + memcpy (&prefix[plen + 1], data, dlen); + prefix[plen + 1 + dlen] = 0; + FcStrFree (data); + data = prefix; + } +#ifdef _WIN32 + if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) + { + int rc; + FcStrFree (data); + data = malloc (1000); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + goto bail; + } + rc = GetTempPath (800, (LPSTR) data); + if (rc == 0 || rc > 800) + { + FcConfigMessage (parse, FcSevereError, "GetTempPath failed"); + goto bail; + } + if (data [strlen ((const char *) data) - 1] != '\\') + strcat ((char *) data, "\\"); + strcat ((char *) data, "fontconfig\\cache"); + } + else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0) + { + char szFPath[MAX_PATH + 1]; + size_t len; + + if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath)))) + { + FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed"); + goto bail; + } + strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath)); + len = strlen(szFPath) + 1; + FcStrFree (data); + data = malloc(len); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + goto bail; + } + strncpy((char *) data, szFPath, len); + } +#endif + if (strlen ((char *) data) == 0) + FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored"); + else if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigAddCacheDir (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data); + } + FcStrBufDestroy (&parse->pstack->str); + + bail: + if (data) + FcStrFree (data); +} + +static void +FcParseInclude (FcConfigParse *parse) +{ + FcChar8 *s; + const FcChar8 *attr; + FcBool ignore_missing = FcFalse; + FcBool deprecated = FcFalse; + FcChar8 *prefix = NULL, *p; + static FcChar8 *userdir = NULL; + static FcChar8 *userconf = NULL; + + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + goto bail; + } + attr = FcConfigGetAttribute (parse, "ignore_missing"); + if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue) + ignore_missing = FcTrue; + attr = FcConfigGetAttribute (parse, "deprecated"); + if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue) + deprecated = FcTrue; + attr = FcConfigGetAttribute (parse, "prefix"); + if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) + prefix = FcConfigXdgConfigHome (); + if (prefix) + { + size_t plen = strlen ((const char *)prefix); + size_t dlen = strlen ((const char *)s); + + p = realloc (prefix, plen + 1 + dlen + 1); + if (!p) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + goto bail; + } + prefix = p; + prefix[plen] = FC_DIR_SEPARATOR; + memcpy (&prefix[plen + 1], s, dlen); + prefix[plen + 1 + dlen] = 0; + s = prefix; + if (FcFileIsDir (s)) + { + userdir: + if (!userdir) + userdir = FcStrdup (s); + } + else if (FcFileIsFile (s)) + { + userconf: + if (!userconf) + userconf = FcStrdup (s); + } + else + { + /* No config dir nor file on the XDG directory spec compliant place + * so need to guess what it is supposed to be. + */ + if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL) + goto userdir; + else + goto userconf; + } + } + if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) + parse->error = FcTrue; +#ifndef _WIN32 + else + { + FcChar8 *filename; + static FcBool warn_conf = FcFalse, warn_confd = FcFalse; + + filename = FcConfigFilename(s); + if (deprecated == FcTrue && + filename != NULL && + !FcFileIsLink (filename)) + { + if (FcFileIsDir (filename)) + { + FcChar8 *parent = FcStrDirname (userdir); + + if (!FcFileIsDir (parent)) + FcMakeDirectory (parent); + FcStrFree (parent); + if (FcFileIsDir (userdir) || + rename ((const char *)filename, (const char *)userdir) != 0 || + symlink ((const char *)userdir, (const char *)filename) != 0) + { + if (!warn_confd) + { + FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir); + warn_confd = FcTrue; + } + } + } + else + { + FcChar8 *parent = FcStrDirname (userconf); + + if (!FcFileIsDir (parent)) + FcMakeDirectory (parent); + FcStrFree (parent); + if (FcFileIsFile (userconf) || + rename ((const char *)filename, (const char *)userconf) != 0 || + symlink ((const char *)userconf, (const char *)filename) != 0) + { + if (!warn_conf) + { + FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf); + warn_conf = FcTrue; + } + } + } + } + if(filename) + FcStrFree(filename); + } +#endif + FcStrBufDestroy (&parse->pstack->str); + + bail: + if (prefix) + FcStrFree (prefix); +} + +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; + const FcChar8 *iblanks_string; + int flags = 0; + + 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; + } + } + iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks"); + if (iblanks_string) + { + FcBool f = FcFalse; + + if (!FcNameBool (iblanks_string, &f)) + { + FcConfigMessage (parse, + FcSevereWarning, + "invalid test ignore-blanks \"%s\"", iblanks_string); + } + if (f) + flags |= FcOpFlagIgnoreBlanks; + } + expr = FcPopBinary (parse, FcOpComma); + if (!expr) + { + FcConfigMessage (parse, FcSevereWarning, "missing test expression"); + return; + } + if (expr->op == FcOpComma) + { + FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected"); + } + test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), 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 }, + { "delete", FcOpDelete }, + { "delete_all", FcOpDeleteAll }, +}; + +#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); + if ((mode == FcOpDelete || mode == FcOpDeleteAll) && + expr != NULL) + { + FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all"); + FcExprDestroy (expr); + expr = NULL; + } + 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; + FcVStack *vstack; + FcRule *rule = NULL, *r; + + 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 ((int) vstack->tag) { + case FcVStackTest: + r = FcRuleCreate (FcRuleTest, vstack->u.test); + if (rule) + r->next = rule; + rule = r; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT) + { + FcConfigMessage (parse, FcSevereError, + "<match target=\"scan\"> cannot edit user-defined object \"%s\"", + FcObjectName(vstack->u.edit->object)); + if (rule) + FcRuleDestroy (rule); + return; + } + r = FcRuleCreate (FcRuleEdit, vstack->u.edit); + if (rule) + r->next = rule; + rule = r; + vstack->tag = FcVStackNone; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "invalid match element"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (!FcConfigAddRule (parse->config, rule, kind)) + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) +{ + FcVStack *vstack; + + while ((vstack = FcVStackPeek (parse))) + { + switch ((int) 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 ((int) vstack->tag) { + case FcVStackString: + value.u.s = FcStrdup (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 = FcTypeDouble; + 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 ((int) 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 FC_UNUSED) +{ + FcConfigParse *parse = userData; + FcChar8 *data; + + if (!parse->pstack) + return; + switch (parse->pstack->element) { + case FcElementNone: + break; + case FcElementFontconfig: + break; + case FcElementDir: + FcParseDir (parse); + break; + case FcElementCacheDir: + FcParseCacheDir (parse); + 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: + FcParseName (parse); + 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 FC_UNUSED, + const XML_Char *pubid FC_UNUSED, + int has_internal_subset FC_UNUSED) +{ + 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 FC_UNUSED) +{ +} + +#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; +} + +#ifdef _WIN32 +pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL; +pfnSHGetFolderPathA pSHGetFolderPathA = NULL; +#endif + +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 + +#ifdef _WIN32 + if (!pGetSystemWindowsDirectory) + { + HMODULE hk32 = GetModuleHandleA("kernel32.dll"); + if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA"))) + pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory; + } + if (!pSHGetFolderPathA) + { + HMODULE hSh = LoadLibraryA("shfolder.dll"); + /* the check is done later, because there is no provided fallback */ + if (hSh) + pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA"); + } +#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 = FcOpen ((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 (!FcConfigParseInit (&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/chromium/third_party/fontconfig/src/src/ftglue.c b/chromium/third_party/fontconfig/src/src/ftglue.c new file mode 100644 index 00000000000..0e02bd2df5d --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/ftglue.c @@ -0,0 +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; + + if ( stream->read ) + { + if ( stream->read( stream, pos, 0, 0 ) ) + error = FT_Err_Invalid_Stream_Operation; + } + else if ( pos < 0 || (FT_ULong) pos > stream->size ) + error = FT_Err_Invalid_Stream_Operation; + + if ( !error ) + stream->pos = pos; + 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 +#include "fcaliastail.h" +#undef __ftglue__ diff --git a/chromium/third_party/fontconfig/src/src/ftglue.h b/chromium/third_party/fontconfig/src/src/ftglue.h new file mode 100644 index 00000000000..e0fd1714e38 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/ftglue.h @@ -0,0 +1,111 @@ +/* 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 + * + * ========================================================================== + * + * the OpenType parser codes was originally written as an extension to + * FreeType 1.x. As such, its source code was embedded within the library, + * and used many internal FreeType functions to deal with memory and + * stream i/o. + * + * When it was 'salvaged' for Pango and Qt, the code was "ported" to FreeType 2, + * which basically means that some macro tricks were performed in order to + * directly access FT2 _internal_ functions. + * + * these functions were never part of FT2 public API, and _did_ change between + * various releases. This created chaos for many users: when they upgraded the + * FreeType library on their system, they couldn't run Gnome anymore since + * Pango refused to link. + * + * Very fortunately, it's possible to completely avoid this problem because + * the FT_StreamRec and FT_MemoryRec structure types, which describe how + * memory and stream implementations interface with the rest of the font + * library, have always been part of the public API, and never changed. + * + * What we do thus is re-implement, within the OpenType parser, the few + * functions that depend on them. This only adds one or two kilobytes of + * code, and ensures that the parser can work with _any_ version + * of FreeType installed on your system. How sweet... ! + * + * Note that we assume that Pango doesn't use any other internal functions + * from FreeType. It used to in old versions, but this should no longer + * be the case. (crossing my fingers). + * + * - David Turner + * - The FreeType Project (www.freetype.org) + * + * PS: This "glue" code is explicitely put in the public domain + */ +#ifndef __OPENTYPE_FTGLUE_H__ +#define __OPENTYPE_FTGLUE_H__ + +#include "fcint.h" + +#include <ft2build.h> +#include FT_FREETYPE_H + +FT_BEGIN_HEADER + + +#define SET_ERR(c) ( (error = (c)) != 0 ) + +#ifndef FTGLUE_API +#define FTGLUE_API(x) extern FcPrivate x +#endif + +#ifndef FTGLUE_APIDEF +#define FTGLUE_APIDEF(x) x +#endif + +/* stream macros used by the OpenType parser */ +#define FILE_Pos() ftglue_stream_pos( stream ) +#define FILE_Seek(pos) SET_ERR( ftglue_stream_seek( stream, pos ) ) +#define ACCESS_Frame(size) SET_ERR( ftglue_stream_frame_enter( stream, size ) ) +#define FORGET_Frame() ftglue_stream_frame_exit( stream ) + +#define GET_Byte() (*stream->cursor++) +#define GET_Short() (stream->cursor += 2, (FT_Short)( \ + (*(((FT_Byte*)stream->cursor)-2) << 8) | \ + *(((FT_Byte*)stream->cursor)-1) \ + )) +#define GET_Long() (stream->cursor += 4, (FT_Long)( \ + (*(((FT_Byte*)stream->cursor)-4) << 24) | \ + (*(((FT_Byte*)stream->cursor)-3) << 16) | \ + (*(((FT_Byte*)stream->cursor)-2) << 8) | \ + *(((FT_Byte*)stream->cursor)-1) \ + )) + +#define GET_Char() ((FT_Char)GET_Byte()) +#define GET_UShort() ((FT_UShort)GET_Short()) +#define GET_ULong() ((FT_ULong)GET_Long()) +#define GET_Tag4() GET_ULong() + +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) + +FTGLUE_API( FT_Long ) +ftglue_stream_pos( FT_Stream stream ); + +FTGLUE_API( FT_Error ) +ftglue_stream_seek( FT_Stream stream, + FT_Long pos ); + +FTGLUE_API( FT_Error ) +ftglue_stream_frame_enter( FT_Stream stream, + FT_ULong size ); + +FTGLUE_API( void ) +ftglue_stream_frame_exit( FT_Stream stream ); + +FTGLUE_API( FT_Error ) +ftglue_face_goto_table( FT_Face face, + FT_ULong tag, + FT_Stream stream ); + +FT_END_HEADER + +#endif /* __OPENTYPE_FTGLUE_H__ */ diff --git a/chromium/third_party/fontconfig/src/src/makealias b/chromium/third_party/fontconfig/src/src/makealias new file mode 100755 index 00000000000..e2f31c62125 --- /dev/null +++ b/chromium/third_party/fontconfig/src/src/makealias @@ -0,0 +1,38 @@ +#!/bin/sh +SRCDIR=$1 +shift +HEAD=$1 +shift +TAIL=$1 +shift +rm -f $HEAD $TAIL +echo "#if HAVE_GNUC_ATTRIBUTE" >> $TAIL +cat "$@" | grep '^Fc[^ ]* *(' | sed -e 's/ *(.*$//' | +while read name; do + case $name in + FcCacheDir|FcCacheSubdir) + ;; + *) + alias="IA__$name" + hattr='__attribute((visibility("hidden")))' + echo "extern __typeof ($name) $alias $hattr;" >> $HEAD + echo "#define $name $alias" >> $HEAD + ifdef=`grep -l '^'$name'[ (]' "$SRCDIR"/*.c | sed -n 1p | sed -e 's/^.*\/\([^.]*\)\.c/__\1__/'` + if [ -z "$ifdef" ] ; then + echo "error: could not locate $name in src/*.c" 1>&2 + exit 1 + fi + if [ "$ifdef" != "$last" ] ; then + [ -n "$last" ] && echo "#endif /* $last */" >> $TAIL + echo "#ifdef $ifdef" >> $TAIL + last=$ifdef + fi + echo "# undef $name" >> $TAIL + cattr='__attribute((alias("'$alias'"), visibility("default")))' + echo "extern __typeof ($name) $name $cattr;" >> $TAIL + ;; + esac +done +[ $? -ne 0 ] && exit 1 +echo "#endif /* $ifdef */" >> $TAIL +echo "#endif /* HAVE_GNUC_ATTRIBUTE */" >> $TAIL |