]> git.wh0rd.org Git - fontconfig.git/commitdiff
Move existing fonts.conf to fonts.conf.bak
authorKeith Packard <keithp@keithp.com>
Sat, 4 Dec 2004 19:41:10 +0000 (19:41 +0000)
committerKeith Packard <keithp@keithp.com>
Sat, 4 Dec 2004 19:41:10 +0000 (19:41 +0000)
Add detection of iconv
Document new selectfont elements
Switch to UTF-8 in comment
Add fullname, and family/style/fullname language entries
Respect selectfont/*/glob
Add support for selectfont
Add multi-lingual family/style/fullname support
Expose FcListPatternMatchAny (which selectfont/*/pattern uses)
Add new FcPatternRemove/FcPatternAppend. FcObjectStaticName stores computed
    pattern element names which are required to be static.

18 files changed:
ChangeLog
Makefile.am
configure.in
doc/fcpattern.fncs
doc/fontconfig-devel.sgml
doc/fontconfig-user.sgml
fc-lang/nb.orth
fontconfig/fontconfig.h
fonts.dtd
src/fccache.c
src/fccfg.c
src/fcdir.c
src/fcfreetype.c
src/fcint.h
src/fclist.c
src/fcname.c
src/fcpat.c
src/fcxml.c

index b9c22c22e330e078c3b4508ae14316e8d234fac8..3d98cab47f8c34153daa64afbbc945515d9c4e68 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,50 @@
+2004-12-04  Keith Packard  <keithp@keithp.com>
+
+       * Makefile.am:
+       Move existing fonts.conf to fonts.conf.bak
+       
+       * configure.in:
+       Add detection of iconv
+       
+       * doc/fcpattern.fncs:
+       * doc/fontconfig-devel.sgml:
+       * doc/fontconfig-user.sgml:
+       * fonts.dtd:
+       Document new selectfont elements
+       
+       * fc-lang/nb.orth:
+       Switch to UTF-8 in comment
+       
+       * fontconfig/fontconfig.h:
+       * src/fcname.c:
+       Add fullname, and family/style/fullname language entries
+       
+       * src/fccache.c: (FcCacheFontSetAdd):
+       * src/fcdir.c: (FcFileScanConfig):
+       Respect selectfont/*/glob
+       
+       * src/fcint.h:
+       * src/fccfg.c: (FcConfigCreate), (FcConfigDestroy),
+       (FcConfigCompareValue), (FcConfigPatternsAdd),
+       (FcConfigPatternsMatch), (FcConfigAcceptFont):
+       * src/fcxml.c: (FcElementMap), (FcVStackDestroy),
+       (FcVStackPushPattern), (FcPopExpr), (FcParseAcceptRejectFont),
+       (FcPopValue), (FcParsePatelt), (FcParsePattern), (FcEndElement):
+       Add support for selectfont
+       
+       * src/fcfreetype.c: (FcSfntNameTranscode), (FcSfntNameLanguage),
+       (FcStringInPatternElement), (FcFreeTypeQuery):
+       Add multi-lingual family/style/fullname support
+       
+       * src/fclist.c: (FcListPatternMatchAny):
+       Expose FcListPatternMatchAny (which selectfont/*/pattern uses)
+       
+       * src/fcpat.c: (FcPatternRemove), (FcPatternAppend),
+       (FcObjectStaticName):
+       Add new FcPatternRemove/FcPatternAppend.
+       FcObjectStaticName stores computed pattern element names which
+       are required to be static.
+       
 2004-09-09 "NAKAMURA Ken'ichi" <nakamura@sbp.fp.a.u-tokyo.ac.jp>
 
        reviewed by: keithp
index 8de50699262dc93411271895e8fff861cd137b16..c1e48a1bc990ab31d2baabf4136191961a1b5986 100644 (file)
@@ -37,10 +37,21 @@ pkgconfigdir=$(libdir)/pkgconfig
 pkgconfig_DATA = fontconfig.pc
 
 configdir=$(CONFDIR)
-config_DATA=fonts.conf fonts.dtd
+config_DATA=fonts.dtd
 
 install-data-local:
        $(mkinstalldirs) $(DESTDIR)$(configdir)
+       if [ -f $(DESTDIR)$(configdir)/fonts.conf ]; then \
+         echo "backing up existing $(DESTDIR)$(configdir)/fonts.conf"; \
+         mv $(DESTDIR)$(configdir)/fonts.conf $(DESTDIR)$(configdir)/fonts.conf.bak; \
+       fi
+       if [ -f $(srcdir)/fonts.conf ]; then \
+         echo " $(INSTALL_DATA) $(srcdir)/fonts.conf $(DESTDIR)$(configdir)/fonts.conf"; \
+         $(INSTALL_DATA) $(srcdir)/fonts.conf $(DESTDIR)$(configdir)/fonts.conf; \
+       else if [ -f fonts.conf ]; then \
+         echo " $(INSTALL_DATA) fonts.conf $(DESTDIR)$(configdir)/fonts.conf"; \
+         $(INSTALL_DATA) fonts.conf $(DESTDIR)$(configdir)/fonts.conf; \
+       fi; fi
        if [ -f $(DESTDIR)$(configdir)/local.conf ]; then \
          echo "not overwriting existing $(DESTDIR)$(configdir)/local.conf"; \
        else if [ -f $(srcdir)/local.conf ]; then \
index 604d56ee5d74836f0fbc504b4abb535c58549157..71f67421e85d004061d9125fe8ede5b99bdd004f 100644 (file)
@@ -91,7 +91,7 @@ dnl ==========================================================================
 # Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h iconv.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -99,7 +99,7 @@ AC_TYPE_PID_T
 
 # Checks for library functions.
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr strtol getopt getopt_long])
+AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr strtol getopt getopt_long iconv])
 
 #
 # Checks for FreeType
@@ -324,7 +324,7 @@ esac
 
 AC_SUBST(FC_FONTPATH)
 
-FC_FONTDATE=`date`
+FC_FONTDATE=`LC_ALL=C date`
 
 AC_SUBST(FC_FONTDATE)
 
index 4011a2633f7dca49f2837a66b0c4faab70629d3b..177bd9b1b3990c46d7a6d3fda37a4e5625e7524a 100644 (file)
@@ -262,6 +262,17 @@ Deletes all values associated with the property `object', returning
 whether the property existed or not.
 @@
 
+@RET@          FcBool
+@FUNC@         FcPatternRemove
+@TYPE1@                FcPattern *                     @ARG1@          p
+@TYPE2@                const char *                    @ARG2@          object 
+@TYPE3@                int                             @ARG3@          id
+@PURPOSE@      Remove one object of the specified type from the pattern
+@DESC@
+Removes the value associated with the property `object' at position `id', returning 
+whether the property existed and had a value at that position or not.
+@@
+               
 @RET@          void
 @FUNC@         FcPatternPrint
 @TYPE1@                const FcPattern *               @ARG1@          p 
index b2fd21c573382cd79a8d0a51b2531ad7865fc92e..a9893882d1c6643b0c2a592cbb7a87489f4081e4 100644 (file)
@@ -127,11 +127,20 @@ convenience for the applications rendering mechanism.
     <programlisting>
                  Property Definitions
 
-    Property    CPP Symbol      Type    Description
+    Property       CPP Symbol           Type    Description
     ----------------------------------------------------
-    family         FC_FAMILY            String  Font family name
+    family         FC_FAMILY            String  Font family names
+    familylang     FC_FAMILYLANG        String  Language cooresponding to
+                                                each family name
     style          FC_STYLE             String  Font style. Overrides weight
                                                 and slant
+    stylelang      FC_STYLELANG         String  Language cooresponding to
+                                                each style name
+    fullname       FC_FULLNAME          String  Font face full name where
+                                                different from family and
+                                               family + style
+    fullnamelang   FC_FULLNAMELANG      String  Language cooresponding to
+                                                each fullname
     slant          FC_SLANT             Int     Italic, oblique or roman
     weight         FC_WEIGHT            Int     Light, medium, demibold,
                                                 bold or black
index 60dc31d4d18cec77fe5a7bdc7bfabb5de6818b64..ca0f9b79620e9e38b6909b6831d3ca1da4fed98f 100644 (file)
@@ -91,8 +91,12 @@ convenience for the applications rendering mechanism.
     <programlisting>
   Property        Type    Description
   --------------------------------------------------------------
-  family          String  Font family name
+  family          String  Font family names
+  familylang      String  Languages cooresponding to each family
   style           String  Font style. Overrides weight and slant
+  stylelang       String  Languages cooresponding to each style
+  fullname        String  Font full names (often includes style)
+  fullnamelang    String  Languages cooresponding to each fullname
   slant           Int     Italic, oblique or roman
   weight          Int     Light, medium, demibold, bold or black
   size            Double  Point size
@@ -283,6 +287,43 @@ The <sgmltag>rescan</> element holds an <sgmltag>int</> element which indicates
 interval between automatic checks for font configuration changes.
 Fontconfig will validate all of the configuration files and directories and
 automatically rebuild the internal datastructures when this interval passes.
+  </para></refsect2>
+  <refsect2><title><sgmltag>selectfont</></title><para>
+This element is used to black/white list fonts from being listed or matched
+against.  It holds acceptfont and rejectfont elements.
+  </para></refsect2>
+  <refsect2><title><sgmltag>acceptfont</></title><para>
+Fonts matched by an acceptfont element are "whitelisted"; such fonts are
+explicitly included in the set of fonts used to resolve list and match
+requests; including them in this list protects them from being "blacklisted"
+by a rejectfont element.  Acceptfont elements include glob and pattern
+elements which are used to match fonts.
+  </para></refsect2>
+  <refsect2><title><sgmltag>rejectfont</></title><para>
+Fonts matched by an rejectfont element are "blacklisted"; such fonts are
+excluded from the set of fonts used to resolve list and match requests as if
+they didn't exist in the system.  Rejectfont elements include glob and
+pattern elements which are used to match fonts.
+  </para></refsect2>
+  <refsect2><title><sgmltag>glob</></title><para>
+Glob elements hold shell-style filename matching patterns (including ? and
+*) which match fonts based on their complete pathnames.  This can be used to
+exclude a set of directories (/usr/share/fonts/uglyfont*), or particular
+font file types (*.pcf.gz), but the latter mechanism relies rather heavily
+on filenaming conventions which can't be relied upon.
+  </para></refsect2>
+  <refsect2><title><sgmltag>pattern</></title><para>
+Pattern elements perform list-style matching on incoming fonts; that is,
+they hold a list of elements and associated values.  If all of those
+elements have a matching value, then the pattern matches the font.  This can
+be used to select fonts based on attributes of the font (scalable, bold,
+etc), which is a more reliable mechanism than using file extensions.
+Pattern elements include patelt elements.
+  <refsect2><title><sgmltag>patelt name="property"</></title><para>
+Patelt elements hold a single pattern element and list of values.  They must
+have a 'name' attribute which indicates the pattern element name.  Patelt
+elements include int, double, string, matrix, bool, charset and const
+elements.
   </para></refsect2>
   <refsect2><title><sgmltag>match target="pattern"</></title><para>
 This element holds first a (possibly empty) list of <sgmltag>test</> elements and then
index 72d6d05891de9a73a11e721d340b4d8260699357..d867b817be8c68106379ab1fb1eca8567b9ced80 100644 (file)
@@ -21,5 +21,5 @@
 # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 #
-# Norwegian Bokmål (NB)
+# Norwegian Bokmäl (NB)
 include no.orth
index 2e667cb14bac1171c24bbe4b4023cca71fcb4934..645aebb72956370f423aaa43e3790558445d4052 100644 (file)
@@ -89,6 +89,10 @@ typedef int          FcBool;
 #define FC_CHARSET         "charset"           /* CharSet */
 #define FC_LANG                    "lang"              /* String RFC 3066 langs */
 #define FC_FONTVERSION     "fontversion"       /* Int from 'head' table */
+#define FC_FULLNAME        "fullname"          /* String */
+#define FC_FAMILYLANG      "familylang"        /* String RFC 3066 langs */
+#define FC_STYLELANG       "stylelang"         /* String RFC 3066 langs */
+#define FC_FULLNAMELANG            "fullnamelang"      /* String RFC 3066 langs */
 
 #define FC_DIR_CACHE_FILE          "fonts.cache-"FC_CACHE_VERSION
 #define FC_USER_CACHE_FILE         ".fonts.cache-"FC_CACHE_VERSION
@@ -683,6 +687,9 @@ FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v);
 FcBool
 FcPatternDel (FcPattern *p, const char *object);
 
+FcBool
+FcPatternRemove (FcPattern *p, const char *object, int id);
+
 FcBool
 FcPatternAddInteger (FcPattern *p, const char *object, int i);
 
index 6fcfe096917b9a93be7354779b3926d91fa22fe3..6c9a33df41560db3f87efe68e81a0047cf5df4eb 100644 (file)
--- a/fonts.dtd
+++ b/fonts.dtd
@@ -3,6 +3,7 @@
                      cache | 
                      include | 
                      config |
+                     selectfont |
                      match | 
                      alias)* >
 
  -->
 <!ELEMENT rescan (int)>
 
+<!--
+    Edit list of available fonts at startup/reload time
+ -->
+<!ELEMENT selectfont (rejectfont | acceptfont)* >
+
+<!ELEMENT rejectfont (glob | pattern)*>
+
+<!ELEMENT acceptfont (glob | pattern)*>
+
+<!ELEMENT glob (#PCDATA)>
+
+<!ELEMENT pattern (patelt)*>
+
+<!ELEMENT patelt (constant)*>
+<!ATTLIST patelt
+         name CDATA    #REQUIRED>
+
+<!ELEMENT constant (int|double|string|matrix|bool|charset|const)>
 
 <!ELEMENT alias (family*, prefer?, accept?, default?)>
 <!ELEMENT prefer (family)*>
index beb9ae573727dc6138764ae51a0f7d6f2b48c124..ab6bec0ffbcfac8ea3a852880ffbdd7b0525b60a 100644 (file)
@@ -297,7 +297,7 @@ FcCacheFontSetAdd (FcFontSet            *set,
            if (FcDebug () & FC_DBG_CACHEV)
                printf (" dir cache file \"%s\"\n", file);
            ret = FcPatternAddString (font, FC_FILE, path);
-           if (ret)
+           if (ret && (!config || FcConfigAcceptFont (config, font)))
            {
                frozen = FcPatternFreeze (font);
                ret = (frozen != 0);
index 561294974092b03a9a8d5a2ddf3c279d8e68efb4..b0bc06ed06a42a412796cd14fdff202dd4ec1faa 100644 (file)
@@ -67,10 +67,18 @@ FcConfigCreate (void)
     if (!config->rejectGlobs)
        goto bail5;
 
+    config->acceptPatterns = FcFontSetCreate ();
+    if (!config->acceptPatterns)
+       goto bail6;
+    
+    config->rejectPatterns = FcFontSetCreate ();
+    if (!config->rejectPatterns)
+       goto bail7;
+
     config->cache = 0;
     if (FcConfigHome())
        if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE)))
-           goto bail6;
+           goto bail8;
 
 #ifdef _WIN32
     if (config->cache == 0)
@@ -110,6 +118,10 @@ FcConfigCreate (void)
     
     return config;
 
+bail8:
+    FcFontSetDestroy (config->rejectPatterns);
+bail7:
+    FcFontSetDestroy (config->acceptPatterns);
 bail6:
     FcStrSetDestroy (config->rejectGlobs);
 bail5:
@@ -207,6 +219,8 @@ FcConfigDestroy (FcConfig *config)
     FcStrSetDestroy (config->configFiles);
     FcStrSetDestroy (config->acceptGlobs);
     FcStrSetDestroy (config->rejectGlobs);
+    FcFontSetDestroy (config->acceptPatterns);
+    FcFontSetDestroy (config->rejectPatterns);
 
     if (config->blanks)
        FcBlanksDestroy (config->blanks);
@@ -665,7 +679,7 @@ FcConfigCompareValue (const FcValue left_o,
                ret = FcLangSetContains (left.u.l, right.u.l);
                break;
            case FcOpNotContains:
-               ret = FcLangSetContains (left.u.l, right.u.l);
+               ret = !FcLangSetContains (left.u.l, right.u.l);
                break;
            case FcOpEqual:
                ret = FcLangSetEqual (left.u.l, right.u.l);
@@ -1837,3 +1851,40 @@ FcConfigAcceptFilename (FcConfig *config,
        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;
+}
index 6ae7052e2b69eec4e798d2a15f6b57efa1bc3ef0..9ce22daf660884af223ed91df92bac740ea687c0 100644 (file)
@@ -141,7 +141,7 @@ FcFileScanConfig (FcFontSet *set,
        /*
         * Add the font
         */
-       if (font)
+       if (font && (!config || FcConfigAcceptFont (config, font)))
        {
            if (!FcFontSetAdd (set, font))
            {
index daaba28bbb4ff8ee9ead029c7641632e39a14329..9c2c385fcaafea0941257a067af0024dde4ae8b2 100644 (file)
@@ -104,54 +104,639 @@ FcFreeTypeIsExclusiveLang (const FcChar8  *lang)
     return FcFalse;
 }
 
-#define FC_NAME_PRIO_LANG          0x0f00
-#define FC_NAME_PRIO_LANG_ENGLISH   0x0200
-#define FC_NAME_PRIO_LANG_LATIN            0x0100
-#define FC_NAME_PRIO_LANG_NONE     0x0000
+typedef struct {
+    FT_UShort  platform_id;
+    FT_UShort  encoding_id;
+    char       *fromcode;
+} 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,  "UCS-2BE" },
+ {  TT_PLATFORM_MACINTOSH,     TT_MAC_ID_ROMAN,        "MACINTOSH" },
+ {  TT_PLATFORM_MACINTOSH,     TT_MAC_ID_JAPANESE,     "SJIS" },
+ {  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,        "GB3212" },
+ {  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,         "Johap" },
+ {  TT_PLATFORM_MICROSOFT,     TT_MS_ID_UCS_4,         "UCS4" },
+ {  TT_PLATFORM_ISO,           TT_ISO_ID_7BIT_ASCII,   "ASCII" },
+ {  TT_PLATFORM_ISO,           TT_ISO_ID_10646,        "UCS-2BE" },
+ {  TT_PLATFORM_ISO,           TT_ISO_ID_8859_1,       "ISO-8859-1" },
+};
 
-#define FC_NAME_PRIO_ENC           0x00f0
-#define FC_NAME_PRIO_ENC_UNICODE    0x0010
-#define FC_NAME_PRIO_ENC_NONE      0x0000
+#define NUM_FC_FT_ENCODING  (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
+
+typedef struct {
+    FT_UShort  platform_id;
+    FT_UShort  language_id;
+    char       *lang;
+} FcFtLanguage;
+
+#define TT_LANGUAGE_DONT_CARE  0xffff
+
+static const FcFtLanguage   fcFtLanguage[] = {
+ {  TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE,              0 },
+ {  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 */
 
-#define FC_NAME_PRIO_NAME          0x000f
-#define FC_NAME_PRIO_NAME_FAMILY    0x0002
-#define FC_NAME_PRIO_NAME_PS       0x0001
-#define FC_NAME_PRIO_NAME_NONE     0x0000
+ {  TT_PLATFORM_MACINTOSH,     TT_MAC_LANGID_SCOTTISH_GAELIC },
+ {  TT_PLATFORM_MACINTOSH,     TT_MAC_LANGID_IRISH_GAELIC },
 
-static FcBool
-FcUcs4IsLatin (FcChar32 ucs4)
-{
-    FcChar32   page = ucs4 >> 8;
+#endif
     
-    if (page <= 2)
-       return FcTrue;
-    if (page == 0x1e)
-       return FcTrue;
-    if (0x20 <= page && page <= 0x23)
-       return FcTrue;
-    if (page == 0xfb)
-       return FcTrue;
-    /* halfwidth forms, don't include kana or white parens */
-    if (0xff01 <= ucs4 && ucs4 <= 0xff5e)
-       return FcTrue;
-    return FcFalse;
-}
+  /* 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
 
-static FcBool
-FcUtf8IsLatin (FcChar8 *str, int len)
+ {  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  (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
+
+typedef struct {
+    FT_UShort  language_id;
+    char       *fromcode;
+} FcMacRomanFake;
+
+static const FcMacRomanFake fcMacRomanFake[] = {
+ {  TT_MS_LANGID_JAPANESE_JAPAN,       "SJIS-WIN" },
+ {  TT_MS_LANGID_ENGLISH_UNITED_STATES,        "ASCII" },
+};
+
+#define NUM_FC_MAC_ROMAN_FAKE  (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
+
+#if HAVE_ICONV && HAVE_ICONV_H
+#define USE_ICONV 1
+#include <iconv.h>
+#endif
+
+static FcChar8 *
+FcSfntNameTranscode (FT_SfntName *sname)
 {
-    while (len)
+    int            i;
+    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;
+
+    /*
+     * "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)
+     */
+    if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN) &&
+       sname->language_id >= 0x100)
+    {
+       int     f;
+
+       fromcode = 0;
+       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 USE_ICONV
+    cd = iconv_open ("UTF-8", fromcode);
+    if (cd)
+    {
+       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)
+           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))
+           {
+               free (utf8);
+               return 0;
+           }
+       }
+       *outbuf = '\0';
+       goto done;
+    }
+#endif
+    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;
-       int         clen = FcUtf8ToUcs4 (str, &ucs4, len);
-       if (clen <= 0)
-           return FcFalse;
-       if (!FcUcs4IsLatin (ucs4))
-           return FcFalse;
-       len -= clen;
-       str += clen;
+       
+       /*
+        * 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;
     }
-    return FcTrue;
+    if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
+    {
+       FcChar8         *u8;
+       const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
+       FcChar8         *src = (FcChar8 *) sname->string;
+       int             src_len = sname->string_len;
+       
+       /*
+        * Convert AppleRoman to Utf8
+        */
+       if (!map)
+           return 0;
+
+       utf8 = malloc (sname->string_len * 3 + 1);
+       if (!utf8)
+           return 0;
+
+       u8 = utf8;
+       while (src_len > 0)
+       {
+           FcChar32    ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
+           int         olen = FcUcs4ToUtf8 (ucs4, u8);
+           src_len--;
+           u8 += olen;
+       }
+       *u8 = '\0';
+       goto done;
+    }
+    return 0;
+done:
+    if (FcStrCmpIgnoreBlanksAndCase (utf8, "") == 0)
+    {
+       free (utf8);
+       return 0;
+    }
+    return utf8;
+}
+
+static FcChar8 *
+FcSfntNameLanguage (FT_SfntName *sname)
+{
+    int i;
+    for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
+       if (fcFtLanguage[i].platform_id == sname->platform_id &&
+           (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
+            fcFtLanguage[i].language_id == sname->language_id))
+           return fcFtLanguage[i].lang;
+    return 0;
 }
 
 /* Order is significant.  For example, some B&H fonts are hinted by
@@ -368,6 +953,20 @@ FcGetPixelSize (FT_Face face, int i)
 #endif
 }
 
+static FcBool
+FcStringInPatternElement (FcPattern *pat, char *elt, FcChar8 *string)
+{
+    int            e;
+    FcChar8 *old;
+    for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
+       if (!FcStrCmpIgnoreBlanksAndCase (old, string))
+       {
+           return FcTrue;
+           break;
+       }
+    return FcFalse;
+}
+
 FcPattern *
 FcFreeTypeQuery (const FcChar8 *file,
                 int            id,
@@ -383,8 +982,9 @@ FcFreeTypeQuery (const FcChar8      *file,
     FcCharSet      *cs;
     FcLangSet      *ls;
     FT_Library     ftLibrary;
+#if 0
     FcChar8        *family = 0;
-    FcChar8        *style = 0;
+#endif
     const FcChar8   *foundry = 0;
     int                    spacing;
     TT_OS2         *os2;
@@ -398,11 +998,17 @@ FcFreeTypeQuery (const FcChar8    *file,
     const FcChar8   *exclusiveLang = 0;
     FT_SfntName            sname;
     FT_UInt                snamei, snamec;
-    FcBool         family_allocated = FcFalse;
-    FcBool         style_allocated = FcFalse;
-    int                    family_prio = 0;
-    int                    style_prio = 0;
+    
+    int                    nfamily = 0;
+    int                    nfamily_lang = 0;
+    int                    nstyle = 0;
+    int                    nstyle_lang = 0;
+    int                    nfullname = 0;
+    int                    nfullname_lang = 0;
 
+    FcChar8        *style = 0;
+    int                    st;
+    
     if (FT_Init_FreeType (&ftLibrary))
        return 0;
     
@@ -440,6 +1046,8 @@ FcFreeTypeQuery (const FcChar8     *file,
     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
@@ -449,225 +1057,60 @@ FcFreeTypeQuery (const FcChar8  *file,
     for (snamei = 0; snamei < snamec; snamei++)
     {
        FcChar8         *utf8;
-       int             len;
-       int             wchar;
-       FcChar8         *src;
-       int             src_len;
-       FcChar8         *u8;
-       FcChar32        ucs4;
-       int             ilen, olen;
-       int             prio = 0;
-       
-       const FcCharMap *map;
-       enum {
-           FcNameEncodingUtf16, 
-           FcNameEncodingAppleRoman,
-           FcNameEncodingLatin1 
-       } encoding;
-       
-       
+       FcChar8         *lang;
+       char            *elt = 0, *eltlang = 0;
+       int             *np = 0, *nlangp = 0;
+
        if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
-           break;
+           continue;
        
-       /*
-        * Look for Unicode strings
-        */
-       switch (sname.platform_id) {
-       case TT_PLATFORM_APPLE_UNICODE:
-           /*
-            * All APPLE_UNICODE encodings are Utf16 BE
-            *
-            * Because there's no language id for Unicode,
-            * assume it's English
-            */
-           prio |= FC_NAME_PRIO_LANG_ENGLISH;
-           prio |= FC_NAME_PRIO_ENC_UNICODE;
-           encoding = FcNameEncodingUtf16;
-           break;
-       case TT_PLATFORM_MACINTOSH:
-           switch (sname.encoding_id) {
-           case TT_MAC_ID_ROMAN:
-               encoding = FcNameEncodingAppleRoman;
-               break;
-           default:
-               continue;
-           }
-           switch (sname.language_id) {
-           case TT_MAC_LANGID_ENGLISH:
-               prio |= FC_NAME_PRIO_LANG_ENGLISH;
-               break;
-           default:
-               /*
-                * Sometimes Microsoft language ids
-                * end up in the macintosh table.  This
-                * is often accompanied by data in
-                * some mystic encoding.  Ignore these names
-                */
-               if (sname.language_id >= 0x100)
-                   continue;
-               break;
-           }
-           break;
-       case TT_PLATFORM_MICROSOFT:
-           switch (sname.encoding_id) {
-           case TT_MS_ID_UNICODE_CS:
-               encoding = FcNameEncodingUtf16;
-               prio |= FC_NAME_PRIO_ENC_UNICODE;
-               break;
-           default:
-               continue;
-           }
-           switch (sname.language_id & 0xff) {
-           case 0x09:
-               prio |= FC_NAME_PRIO_LANG_ENGLISH;
-               break;
-           default:
-               break;
-           }
-           break;
-       case TT_PLATFORM_ISO:
-           switch (sname.encoding_id) {
-           case TT_ISO_ID_10646:
-               encoding = FcNameEncodingUtf16;
-               prio |= FC_NAME_PRIO_ENC_UNICODE;
-               break;
-           case TT_ISO_ID_7BIT_ASCII:
-           case TT_ISO_ID_8859_1:
-               encoding = FcNameEncodingLatin1;
-               break;
-           default:
-               continue;
-           }
-           break;
-       default:
+       utf8 = FcSfntNameTranscode (&sname);
+       lang = FcSfntNameLanguage (&sname);
+
+       if (!utf8)
            continue;
-       }
        
-       /*
-        * Look for family and style names 
-        */
        switch (sname.name_id) {
        case TT_NAME_ID_FONT_FAMILY:
-           prio |= FC_NAME_PRIO_NAME_FAMILY;
-           break;
+#if 0      
        case TT_NAME_ID_PS_NAME:
-           prio |= FC_NAME_PRIO_NAME_PS;
-           break;
-       case TT_NAME_ID_FONT_SUBFAMILY:
-        case TT_NAME_ID_TRADEMARK:
-        case TT_NAME_ID_MANUFACTURER:
-            break;
-       default:
-           continue;
-       }
-           
-        src = (FcChar8 *) sname.string;
-        src_len = sname.string_len;
-       
-       switch (encoding) {
-       case FcNameEncodingUtf16:
-           /*
-            * Convert Utf16 to Utf8
-            */
-           
-           if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
-               continue;
+       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);
     
-           /*
-            * Allocate plenty of space.  Freed below
-            */
-           utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
-           if (!utf8)
-               continue;
-               
-           u8 = utf8;
-           
-           while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
-           {
-               src_len -= ilen;
-               src += ilen;
-               olen = FcUcs4ToUtf8 (ucs4, u8);
-               u8 += olen;
-           }
-           *u8 = '\0';
-           break;
-       case FcNameEncodingLatin1:
-           /*
-            * Convert Latin1 to Utf8. Freed below
-            */
-           utf8 = malloc (src_len * 2 + 1);
-           if (!utf8)
-               continue;
-
-           u8 = utf8;
-           while (src_len > 0)
-           {
-               ucs4 = *src++;
-               src_len--;
-               olen = FcUcs4ToUtf8 (ucs4, u8);
-               u8 += olen;
-           }
-           *u8 = '\0';
+           elt = FC_FAMILY;
+           eltlang = FC_FAMILYLANG;
+           np = &nfamily;
+           nlangp = &nfamily_lang;
            break;
-       case FcNameEncodingAppleRoman:
-           /*
-            * Convert AppleRoman to Utf8
-            */
-           map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
-           if (!map)
-               continue;
-
-           /* freed below */
-           utf8 = malloc (src_len * 3 + 1);
-           if (!utf8)
-               continue;
-
-           u8 = utf8;
-           while (src_len > 0)
-           {
-               ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
-               src_len--;
-               olen = FcUcs4ToUtf8 (ucs4, u8);
-               u8 += olen;
-           }
-           *u8 = '\0';
-           break;
-       default:
-           continue;
-       }
-       if ((prio & FC_NAME_PRIO_LANG) == FC_NAME_PRIO_LANG_NONE)
-           if (FcUtf8IsLatin (utf8, strlen ((char *) utf8)))
-               prio |= FC_NAME_PRIO_LANG_LATIN;
-                              
-       if (FcDebug () & FC_DBG_SCANV)
-           printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n",
+       case TT_NAME_ID_FULL_NAME:
+       case TT_NAME_ID_MAC_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,
-                   prio, utf8);
+                   utf8);
     
-       switch (sname.name_id) {
-       case TT_NAME_ID_FONT_FAMILY:
-       case TT_NAME_ID_PS_NAME:
-           if (!family || prio > family_prio)
-           {
-               if (family)
-                   free (family);
-               family = utf8;
-               utf8 = 0;
-               family_allocated = FcTrue;
-               family_prio = prio;
-           }
+           elt = FC_FULLNAME;
+           eltlang = FC_FULLNAMELANG;
+           np = &nfullname;
+           nlangp = &nfullname_lang;
            break;
        case TT_NAME_ID_FONT_SUBFAMILY:
-           if (!style || prio > style_prio)
-           {
-               if (style)
-                   free (style);
-               style = utf8;
-               utf8 = 0;
-               style_allocated = FcTrue;
-               style_prio = prio;
-           }
+           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:
@@ -676,19 +1119,62 @@ FcFreeTypeQuery (const FcChar8   *file,
                 foundry = FcNoticeFoundry((FT_String *) utf8);
             break;
        }
-       if (utf8)
+       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, "xx"))
+                       goto bail1;
+                   ++*nlangp;
+               }
+               if (!FcPatternAddString (pat, eltlang, lang))
+                   goto bail1;
+               ++*nlangp;
+           }
+           ++*np;
+       }
+        else
            free (utf8);
     }
     
-    if (!family)
-       family = (FcChar8 *) face->family_name;
+    if (!nfamily && face->family_name)
+    {
+       if (FcDebug () & FC_DBG_SCANV)
+           printf ("using FreeType family %s", face->family_name);
+       if (!FcPatternAddString (pat, FC_FAMILY, face->family_name))
+           goto bail1;
+       ++nfamily;
+    }
     
-    if (!style)
-       style = (FcChar8 *) face->style_name;
+    if (!nstyle && face->style_name)
+    {
+       if (FcDebug () & FC_DBG_SCANV)
+           printf ("using FreeType style %s", face->family_name);
+       if (!FcPatternAddString (pat, FC_STYLE, face->style_name))
+           goto bail1;
+       ++nstyle;
+    }
     
-    if (!family)
+    if (!nfamily)
     {
        FcChar8 *start, *end;
+       FcChar8 *family;
        
        start = (FcChar8 *) strrchr ((char *) file, '/');
        if (start)
@@ -702,19 +1188,79 @@ FcFreeTypeQuery (const FcChar8   *file,
        family = malloc (end - start + 1);
        strncpy ((char *) family, (char *) start, end - start);
        family[end - start] = '\0';
-       family_allocated = FcTrue;
+       if (FcDebug () & FC_DBG_SCANV)
+           printf ("using filename for family %s", family);
+       if (!FcPatternAddString (pat, FC_FAMILY, family))
+       {
+           free (family);
+           goto bail1;
+       }
+       free (family);
+       ++nfamily;
     }
 
-    if (FcDebug() & FC_DBG_SCAN)
-       printf ("\n\"%s\" \"%s\"\n", family, style ? style : (FcChar8 *) "<none>");
+    /*
+     * Walk through FC_FULLNAME entries eliding those in FC_FAMILY
+     * or which are simply a FC_FAMILY and FC_STYLE glued together
+     */
+    {
+       int     fn, fa, st;
+       FcChar8 *full;
+       FcChar8 *fam;
+       FcChar8 *style;
 
-    if (!FcPatternAddString (pat, FC_FAMILY, family))
-       goto bail1;
+       for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
+       {
+           FcBool  remove = FcFalse;
+           /*
+            * Check each family
+            */
+           for (fa = 0; !remove && 
+                FcPatternGetString (pat, FC_FAMILY, 
+                                    fa, &fam) == FcResultMatch;
+                fa++)
+           {
+               /*
+                * for exact match
+                */
+               if (!FcStrCmpIgnoreBlanksAndCase (full, fam))
+               {
+                   remove = FcTrue;
+                   break;
+               }
+               /*
+                * If the family is in the full name, check the
+                * combination of this family with every style
+                */
+               if (!FcStrContainsIgnoreBlanksAndCase (full, fam))
+                   continue;
+               for (st = 0; !remove && 
+                    FcPatternGetString (pat, FC_STYLE, 
+                                        st, &style) == FcResultMatch;
+                    st++)
+               {
+                   FcChar8     *both = FcStrPlus (fam, style);
 
-    if (style)
-    {
-       if (!FcPatternAddString (pat, FC_STYLE, style))
-           goto bail1;
+                   if (both)
+                   {
+                       if (FcStrCmpIgnoreBlanksAndCase (full, both) == 0)
+                           remove = FcTrue;
+                       free (both);
+                   }
+               }
+           }
+           if (remove)
+           {
+               FcPatternRemove (pat, FC_FULLNAME, fn);
+               FcPatternRemove (pat, FC_FULLNAMELANG, fn);
+               fn--;
+               nfullname--;
+               nfullname_lang--;
+           }
+       }
+       if (FcDebug () & FC_DBG_SCANV)
+           for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
+               printf ("Saving unique fullname %s\n", full);
     }
 
     if (!FcPatternAddString (pat, FC_FILE, file))
@@ -906,7 +1452,7 @@ FcFreeTypeQuery (const FcChar8     *file,
     /*
      * Look for weight, width and slant names in the style value
      */
-    if (style)
+    for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
     {
        if (weight == -1)
        {
@@ -1062,11 +1608,6 @@ FcFreeTypeQuery (const FcChar8   *file,
      * Deallocate family/style values
      */
     
-    if (family_allocated)
-       free (family);
-    if (style_allocated)
-       free (style);
-    
     FT_Done_Face (face);
     FT_Done_FreeType (ftLibrary);
     return pat;
@@ -1075,10 +1616,6 @@ bail2:
     FcCharSetDestroy (cs);
 bail1:
     FcPatternDestroy (pat);
-    if (family_allocated)
-       free (family);
-    if (style_allocated)
-       free (style);
 bail0:
     FT_Done_Face (face);
 bail:
index 036da9e74ae3f78b68ba67d879b316dbbf712da0..cf86ad417a2ab07e24e65e563defe4d4f3e11f22 100644 (file)
@@ -329,6 +329,8 @@ struct _FcConfig {
      */
     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,
@@ -465,6 +467,15 @@ FcBool
 FcConfigAcceptFilename (FcConfig       *config,
                        const FcChar8   *filename);
 
+FcBool
+FcConfigPatternsAdd (FcConfig  *config,
+                    FcPattern  *pattern,
+                    FcBool     accept);
+
+FcBool
+FcConfigAcceptFont (FcConfig       *config,
+                   const FcPattern *font);
+
 /* fccharset.c */
 FcCharSet *
 FcCharSetFreeze (FcCharSet *cs);
@@ -639,6 +650,10 @@ FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls);
 
 /* fclist.c */
 
+FcBool
+FcListPatternMatchAny (const FcPattern *p,
+                      const FcPattern *font);
+
 /* fcmatch.c */
 
 /* fcname.c */
@@ -669,6 +684,12 @@ FcPatternFreeze (FcPattern *p);
 void
 FcPatternThawAll (void);
 
+FcBool
+FcPatternAppend (FcPattern *p, FcPattern *s);
+
+const char *
+FcObjectStaticName (const char *name);
+
 /* fcrender.c */
 
 /* fcmatrix.c */
index 0885c933dd592547cb5b6ebd30ea03fbe6aa362b..3474d995a031ed9085be502389977426989e2c2a 100644 (file)
@@ -200,9 +200,9 @@ FcListPatternEqual (FcPattern       *p1,
  * FcTrue iff all objects in "p" match "font"
  */
 
-static FcBool
-FcListPatternMatchAny (FcPattern *p,
-                      FcPattern *font)
+FcBool
+FcListPatternMatchAny (const FcPattern *p,
+                      const FcPattern *font)
 {
     int                    i;
     FcPatternElt   *e;
index c1df41b5fa43ada5c71d16070adce41cb24db5e4..f40bf64dd5b1e770de8e54e09e887d2096f21fc2 100644 (file)
 
 static const FcObjectType _FcBaseObjectTypes[] = {
     { FC_FAMILY,       FcTypeString, },
+    { FC_FAMILYLANG,   FcTypeString, },
     { FC_STYLE,                FcTypeString, },
+    { FC_STYLELANG,    FcTypeString, },
+    { FC_FULLNAME,     FcTypeString, },
+    { FC_FULLNAMELANG, FcTypeString, },
     { FC_SLANT,                FcTypeInteger, },
     { FC_WEIGHT,       FcTypeInteger, },
     { FC_WIDTH,                FcTypeInteger, },
index ddc16f835f4c4c8274f2d80681ccff7d2cf900af..421211f47ca653c1079144e4579e645b8bcdb863 100644 (file)
@@ -849,6 +849,31 @@ FcPatternDel (FcPattern *p, const char *object)
     return FcTrue;
 }
 
+FcBool
+FcPatternRemove (FcPattern *p, const char *object, int id)
+{
+    FcPatternElt   *e;
+    FcValueList    **prev, *l;
+
+    e = FcPatternFindElt (p, object);
+    if (!e)
+       return FcFalse;
+    for (prev = &e->values; (l = *prev); prev = &l->next)
+    {
+       if (!id)
+       {
+           *prev = l->next;
+           l->next = 0;
+           FcValueListDestroy (l);
+           if (!e->values)
+               FcPatternDel (p, object);
+           return FcTrue;
+       }
+       id--;
+    }
+    return FcFalse;
+}
+
 FcBool
 FcPatternAddInteger (FcPattern *p, const char *object, int i)
 {
@@ -1139,3 +1164,51 @@ FcPatternBuild (FcPattern *orig, ...)
     va_end (va);
     return orig;
 }
+
+/*
+ * Add all of the elements in 's' to 'p'
+ */
+FcBool
+FcPatternAppend (FcPattern *p, FcPattern *s)
+{
+    int                    i;
+    FcPatternElt    *e;
+    FcValueList            *v;
+    
+    for (i = 0; i < s->num; i++)
+    {
+       e = &s->elts[i];
+       for (v = e->values; v; v = v->next)
+       {
+           if (!FcPatternAddWithBinding (p, e->object,
+                                         v->value, v->binding, FcTrue))
+               return FcFalse;
+       }
+    }
+    return FcTrue;
+}
+
+const char *
+FcObjectStaticName (const char *name)
+{
+#define OBJECT_HASH_SIZE    31
+    static struct objectBucket {
+       struct objectBucket     *next;
+       FcChar32                hash;
+    } *buckets[OBJECT_HASH_SIZE];
+    FcChar32           hash = FcStringHash ((const FcChar8 *) name);
+    struct objectBucket        **p;
+    struct objectBucket        *b;
+
+    for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
+       if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
+           return (char *) (b + 1);
+    b = malloc (sizeof (struct objectBucket) + strlen (name) + 1);
+    if (!b)
+       return NULL;
+    b->next = 0;
+    b->hash = hash;
+    strcpy ((char *) (b + 1), name);
+    *p = b;
+    return (char *) (b + 1);
+}
index 70aeb034a49736ccc7f8973462d5535eebafb333..52172b25dcdb0adf67165144da8672556fd8efbc 100644 (file)
@@ -323,6 +323,8 @@ typedef enum _FcElement {
     FcElementAcceptfont,
     FcElementRejectfont,
     FcElementGlob,
+    FcElementPattern,
+    FcElementPatelt,
 
     FcElementTest,
     FcElementEdit,
@@ -384,6 +386,8 @@ FcElementMap (const XML_Char *name)
        { "acceptfont", FcElementAcceptfont },
        { "rejectfont", FcElementRejectfont },
        { "glob",       FcElementGlob },
+       { "pattern",    FcElementPattern },
+       { "patelt",     FcElementPatelt },
 
        { "test",       FcElementTest },
        { "edit",       FcElementEdit },
@@ -441,6 +445,7 @@ typedef enum _FcVStackTag {
     FcVStackField,
     FcVStackConstant,
     FcVStackGlob,
+    FcVStackPattern,
     
     FcVStackPrefer,
     FcVStackAccept,
@@ -473,6 +478,8 @@ typedef struct _FcVStack {
        FcOp            op;
        FcExpr          *expr;
        FcEdit          *edit;
+
+       FcPattern       *pattern;
     } u;
 } FcVStack;
 
@@ -560,6 +567,9 @@ FcVStackDestroy (FcVStack *vstack)
        case FcVStackGlob:
            FcStrFree (vstack->u.string);
            break;
+       case FcVStackPattern:
+           FcPatternDestroy (vstack->u.pattern);
+           break;
        case FcVStackInteger:
        case FcVStackDouble:
            break;
@@ -688,6 +698,18 @@ FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
     return FcTrue;
 }
 
+static FcBool
+FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
+{
+    FcVStack    *vstack = FcVStackCreate ();
+    if (!vstack)
+       return FcFalse;
+    vstack->u.pattern = pattern;
+    vstack->tag = FcVStackPattern;
+    FcVStackPush (parse, vstack);
+    return FcTrue;
+}
+
 static FcVStack *
 FcVStackFetch (FcConfigParse *parse, int off)
 {
@@ -1321,6 +1343,8 @@ FcPopExpr (FcConfigParse *parse)
        break;
     case FcVStackEdit:
        break;
+    default:
+       break;
     }
     FcVStackDestroy (vstack);
     return expr;
@@ -1675,6 +1699,16 @@ FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
                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;
@@ -1683,6 +1717,128 @@ FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
     }
 }
 
+
+static FcValue
+FcPopValue (FcConfigParse *parse)
+{
+    FcVStack   *vstack = FcVStackPop (parse);
+    FcValue    value;
+    
+    value.type = FcTypeVoid;
+    
+    if (!vstack)
+       return value;
+    
+    switch (vstack->tag) {
+    case FcVStackString:
+       value.u.s = FcStrCopy (vstack->u.string);
+       if (value.u.s)
+           value.type = FcTypeString;
+       break;
+    case FcVStackConstant:
+       if (FcNameConstant (vstack->u.string, &value.u.i))
+           value.type = FcTypeInteger;
+       break;
+    case FcVStackInteger:
+       value.u.i = vstack->u.integer;
+       value.type = FcTypeInteger;
+       break;
+    case FcVStackDouble:
+       value.u.d = vstack->u._double;
+       value.type = FcTypeInteger;
+       break;
+    case FcVStackMatrix:
+       value.u.m = FcMatrixCopy (vstack->u.matrix);
+       if (value.u.m)
+           value.type = FcTypeMatrix;
+       break;
+    case FcVStackBool:
+       value.u.b = vstack->u.bool;
+       value.type = FcTypeBool;
+       break;
+    default:
+       FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 
+                        vstack->tag);
+       break;
+    }
+    FcVStackDestroy (vstack);
+    
+    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 = FcConfigGetAttribute (parse, "name");
+    if (!name)
+    {
+       FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
+       return;
+    }
+    name = FcObjectStaticName (name);
+    if (!name)
+    {
+       FcConfigMessage (parse, FcSevereError, "out of memory");
+       return;
+    }
+    
+    for (;;)
+    {
+       value = FcPopValue (parse);
+       if (value.type == FcTypeVoid)
+           break;
+       if (!FcPatternAdd (pattern, name, value, FcTrue))
+       {
+           FcConfigMessage (parse, FcSevereError, "out of memory");
+           break;
+       }
+    }
+
+    FcVStackPushPattern (parse, pattern);
+}
+
+static void
+FcParsePattern (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcPattern  *pattern = FcPatternCreate ();
+
+    if (!pattern)
+    {
+       FcConfigMessage (parse, FcSevereError, "out of memory");
+       return;
+    }
+       
+    while ((vstack = FcVStackPop (parse)))
+    {
+       switch (vstack->tag) {
+       case FcVStackPattern:
+           if (!FcPatternAppend (pattern, vstack->u.pattern))
+           {
+               FcConfigMessage (parse, FcSevereError, "out of memory");
+               return;
+           }
+           break;
+       default:
+           FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
+           break;
+       }
+       FcVStackDestroy (vstack);
+    }
+
+    FcVStackPushPattern (parse, pattern);
+}
+
 static void
 FcEndElement(void *userData, const XML_Char *name)
 {
@@ -1814,6 +1970,12 @@ FcEndElement(void *userData, const XML_Char *name)
     case FcElementGlob:
        FcParseString (parse, FcVStackGlob);
        break;
+    case FcElementPattern:
+       FcParsePattern (parse);
+       break;
+    case FcElementPatelt:
+       FcParsePatelt (parse);
+       break;
     case FcElementName:
        FcParseString (parse, FcVStackField);
        break;