]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcfreetype.c
Avoid #warning directives on non-GCC compilers. (bug 7683)
[fontconfig.git] / src / fcfreetype.c
index 98c6f8297f563e381b6e17ddefe79a4892d97db6..f85e2f8931eae1bc8b2305829ce355a9e6a08c37 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcfreetype.c,v 1.5 2002/06/29 20:31:02 keithp Exp $
+ * $RCSId: xc/lib/fontconfig/src/fcfreetype.c,v 1.11 2002/08/31 22:17:32 keithp Exp $
  *
- * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ * 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
  * 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 <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include "fcint.h"
-#include <freetype/freetype.h>
-#include <freetype/internal/ftobjs.h>
-#include <freetype/tttables.h>
-
-static const FcChar8   *fcLangLatin1[] = {
-    (FcChar8 *) "br",   /* Breton */
-    (FcChar8 *) "ca",   /* Catalan */
-    (FcChar8 *) "da",   /* Danish */
-    (FcChar8 *) "de",   /* German */
-    (FcChar8 *) "en",   /* English */
-    (FcChar8 *) "es",   /* Spanish */
-    (FcChar8 *) "eu",   /* Basque */
-    (FcChar8 *) "fi",   /* Finnish */
-    (FcChar8 *) "fo",   /* Faroese */
-    (FcChar8 *) "fr",   /* French */
-    (FcChar8 *) "ga",   /* Irish */
-    (FcChar8 *) "gd",   /* Scottish */
-    (FcChar8 *) "gl",   /* Galician */
-    (FcChar8 *) "is",   /* Islandic */
-    (FcChar8 *) "it",   /* Italian */
-    (FcChar8 *) "kl",   /* Greenlandic */
-    (FcChar8 *) "la",   /* Latin */
-    (FcChar8 *) "nl",   /* Dutch */
-    (FcChar8 *) "no",   /* Norwegian */
-    (FcChar8 *) "pt",   /* Portuguese */
-    (FcChar8 *) "rm",   /* Rhaeto-Romanic */
-    (FcChar8 *) "sq",   /* Albanian */
-    (FcChar8 *) "sv",   /* Swedish */
-    0
-};
+#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
 
-static const FcChar8   *fcLangLatin2[] = {
-    (FcChar8 *) "cs",   /* Czech */
-    (FcChar8 *) "de",   /* German */
-    (FcChar8 *) "en",   /* English */
-    (FcChar8 *) "fi",   /* Finnish */
-    (FcChar8 *) "hr",   /* Croatian */
-    (FcChar8 *) "hu",   /* Hungarian */
-    (FcChar8 *) "la",   /* Latin */
-    (FcChar8 *) "pl",   /* Polish */
-    (FcChar8 *) "ro",   /* Romanian */
-    (FcChar8 *) "sk",   /* Slovak */
-    (FcChar8 *) "sl",   /* Slovenian */
-    (FcChar8 *) "sq",   /* Albanian */
-    0
-};
+#include "ftglue.h"
 
-static const FcChar8   *fcLangCyrillic[] = {
-    (FcChar8 *) "az",   /* Azerbaijani */
-    (FcChar8 *) "ba",   /* Bashkir */
-    (FcChar8 *) "bg",   /* Bulgarian */
-    (FcChar8 *) "be",   /* Byelorussian */
-    (FcChar8 *) "kk",   /* Kazakh */
-    (FcChar8 *) "ky",   /* Kirghiz */
-    (FcChar8 *) "mk",   /* Macedonian */
-    (FcChar8 *) "mo",   /* Moldavian */
-    (FcChar8 *) "mn",   /* Mongolian */
-    (FcChar8 *) "ru",   /* Russian */
-    (FcChar8 *) "sr",   /* Serbian */
-    (FcChar8 *) "tg",   /* Tadzhik */
-    (FcChar8 *) "tt",   /* Tatar */
-    (FcChar8 *) "tk",   /* Turkmen */
-    (FcChar8 *) "uz",   /* Uzbek */
-    (FcChar8 *) "uk",   /* Ukrainian */
-    0,
-};
+#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
 
-static const FcChar8   *fcLangGreek[] = {
-    (FcChar8 *) "el",   /* Greek */
-    0
-};
+#if !HAVE_FT_GET_PS_FONT_INFO
+#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
+#endif
+#endif
 
-static const FcChar8   *fcLangTurkish[] = {
-    (FcChar8 *) "tr",   /* Turkish */
-    0
-};
+/*
+ * Keep Han languages separated by eliminating languages
+ * that the codePageRange bits says aren't supported
+ */
 
-static const FcChar8   *fcLangHebrew[] = {
-    (FcChar8 *) "he",   /* Hebrew */
-    (FcChar8 *) "yi",   /* Yiddish */
-    0
+static const struct {
+    int                    bit;
+    const FcChar8   *lang;
+} FcCodePageRange[] = {
+    { 17,      (const FcChar8 *) "ja" },
+    { 18,      (const FcChar8 *) "zh-cn" },
+    { 19,      (const FcChar8 *) "ko" },
+    { 20,      (const FcChar8 *) "zh-tw" },
 };
 
-static const FcChar8   *fcLangArabic[] = {
-    (FcChar8 *) "ar",   /* arabic */
-    0
-};
+#define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
 
-static const FcChar8   *fcLangWindowsBaltic[] = {
-    (FcChar8 *) "da",   /* Danish */
-    (FcChar8 *) "de",   /* German */
-    (FcChar8 *) "en",   /* English */
-    (FcChar8 *) "et",   /* Estonian */
-    (FcChar8 *) "fi",   /* Finnish */
-    (FcChar8 *) "la",   /* Latin */
-    (FcChar8 *) "lt",   /* Lithuanian */
-    (FcChar8 *) "lv",   /* Latvian */
-    (FcChar8 *) "no",   /* Norwegian */
-    (FcChar8 *) "pl",   /* Polish */
-    (FcChar8 *) "sl",   /* Slovenian */
-    (FcChar8 *) "sv",   /* Swedish */
-    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;
+}
 
-static const FcChar8   *fcLangVietnamese[] = {
-    (FcChar8 *) "vi",   /* Vietnamese */
-    0,
+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,  "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,         "Johab" },
+ {  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" },
 };
 
-static const FcChar8   *fcLangThai[] = {
-    (FcChar8 *) "th",   /* Thai */
-    0,
+#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" },
 };
 
-static const FcChar8   *fcLangJapanese[] = {
-    (FcChar8 *) "ja",   /* Japanese */
-    0,
+#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 const FcChar8   *fcLangSimplifiedChinese[] = {
-    (FcChar8 *) "zh-cn",    /* Chinese-China */
-    0,
+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
+
+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;
+
+    /*
+     * "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 = NULL;
+       for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
+           if (fcMacRomanFake[f].language_id == sname->language_id)
+           {
+               fromcode = fcMacRomanFake[f].fromcode;
+               break;
+           }
+       if (!fromcode)
+           return 0;
+    }
+    if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
+    {
+       FcChar8     *src = sname->string;
+       int         src_len = sname->string_len;
+       int         len;
+       int         wchar;
+       int         ilen, olen;
+       FcChar8     *u8;
+       FcChar32    ucs4;
+       
+       /*
+        * Convert Utf16 to Utf8
+        */
+
+       if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
+           return 0;
+
+       /*
+        * Allocate plenty of space.  Freed below
+        */
+       utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
+       if (!utf8)
+           return 0;
+
+       u8 = utf8;
+
+       while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
+       {
+           src_len -= ilen;
+           src += ilen;
+           olen = FcUcs4ToUtf8 (ucs4, u8);
+           u8 += olen;
+       }
+       *u8 = '\0';
+       goto done;
+    }
+    if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
+    {
+       FcChar8     *src = sname->string;
+       int         src_len = sname->string_len;
+       int         olen;
+       FcChar8     *u8;
+       FcChar32    ucs4;
+       
+       /*
+        * Convert Latin1 to Utf8. Freed below
+        */
+       utf8 = malloc (src_len * 2 + 1);
+       if (!utf8)
+           return 0;
+
+       u8 = utf8;
+       while (src_len > 0)
+       {
+           ucs4 = *src++;
+           src_len--;
+           olen = FcUcs4ToUtf8 (ucs4, u8);
+           u8 += olen;
+       }
+       *u8 = '\0';
+       goto done;
+    }
+    if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
+    {
+       FcChar8         *u8;
+       const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
+       FcChar8         *src = (FcChar8 *) sname->string;
+       int             src_len = sname->string_len;
+       
+       /*
+        * Convert AppleRoman to Utf8
+        */
+       if (!map)
+           return 0;
+
+       utf8 = malloc (sname->string_len * 3 + 1);
+       if (!utf8)
+           return 0;
+
+       u8 = utf8;
+       while (src_len > 0)
+       {
+           FcChar32    ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
+           int         olen = FcUcs4ToUtf8 (ucs4, u8);
+           src_len--;
+           u8 += olen;
+       }
+       *u8 = '\0';
+       goto done;
+    }
+#if USE_ICONV
+    cd = iconv_open ("UTF-8", fromcode);
+    if (cd && cd != (iconv_t) (-1))
+    {
+       size_t      in_bytes_left = sname->string_len;
+       size_t      out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
+       char        *inbuf, *outbuf;
+       
+       utf8 = malloc (out_bytes_left + 1);
+       if (!utf8)
+       {
+           iconv_close (cd);
+           return 0;
+       }
+       
+       outbuf = (char *) utf8;
+       inbuf = (char *) sname->string;
+       
+       while (in_bytes_left)
+       {
+           size_t      did = iconv (cd, 
+                                &inbuf, &in_bytes_left,
+                                &outbuf, &out_bytes_left);
+           if (did == (size_t) (-1))
+           {
+               iconv_close (cd);
+               free (utf8);
+               return 0;
+           }
+       }
+       iconv_close (cd);
+       *outbuf = '\0';
+       goto done;
+    }
+#endif
+    return 0;
+done:
+    if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
+    {
+       free (utf8);
+       return 0;
+    }
+    return utf8;
+}
+
+static const FcChar8 *
+FcSfntNameLanguage (FT_SfntName *sname)
+{
+    int i;
+    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))
+       {
+           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 struct {
+    const FT_String *notice;
+    const FcChar8   *foundry;
+} FcNoticeFoundries[] = {
+    { (const FT_String *) "Bigelow",   (const FcChar8 *) "b&h" },
+    { (const FT_String *) "Adobe",     (const FcChar8 *) "adobe" },
+    { (const FT_String *) "Bitstream", (const FcChar8 *) "bitstream" },
+    { (const FT_String *) "Monotype",  (const FcChar8 *) "monotype" },
+    { (const FT_String *) "Linotype",  (const FcChar8 *) "linotype" },
+    { (const FT_String *) "LINOTYPE-HELL",
+                                       (const FcChar8 *) "linotype" },
+    { (const FT_String *) "IBM",       (const FcChar8 *) "ibm" },
+    { (const FT_String *) "URW",       (const FcChar8 *) "urw" },
+    { (const FT_String *) "International Typeface Corporation", 
+                                       (const FcChar8 *) "itc" },
+    { (const FT_String *) "Tiro Typeworks",
+                                       (const FcChar8 *) "tiro" },
+    { (const FT_String *) "XFree86",   (const FcChar8 *) "xfree86" },
+    { (const FT_String *) "Microsoft", (const FcChar8 *) "microsoft" },
+    { (const FT_String *) "Omega",     (const FcChar8 *) "omega" },
+    { (const FT_String *) "Font21",    (const FcChar8 *) "hwan" },
+    { (const FT_String *) "HanYang System",
+                                       (const FcChar8 *) "hanyang" }
 };
 
-static const FcChar8   *fcLangKorean[] = {
-    (FcChar8 *) "ko",   /* Korean */
-    0,
+#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++)
+           if (strstr ((const char *) notice, (const char *) FcNoticeFoundries[i].notice))
+               return FcNoticeFoundries[i].foundry;
+    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;
+    const FcChar8   *foundry;
+} FcVendorFoundries[] = {
+    { (const FT_Char *) "ADBE", (const FcChar8 *) "adobe"},
+    { (const FT_Char *) "AGFA", (const FcChar8 *) "agfa"},
+    { (const FT_Char *) "ALTS", (const FcChar8 *) "altsys"},
+    { (const FT_Char *) "APPL", (const FcChar8 *) "apple"},
+    { (const FT_Char *) "ARPH", (const FcChar8 *) "arphic"},
+    { (const FT_Char *) "ATEC", (const FcChar8 *) "alltype"},
+    { (const FT_Char *) "B&H",  (const FcChar8 *) "b&h"},
+    { (const FT_Char *) "BITS", (const FcChar8 *) "bitstream"},
+    { (const FT_Char *) "CANO", (const FcChar8 *) "cannon"},
+    { (const FT_Char *) "DYNA", (const FcChar8 *) "dynalab"},
+    { (const FT_Char *) "EPSN", (const FcChar8 *) "epson"},
+    { (const FT_Char *) "FJ",   (const FcChar8 *) "fujitsu"},
+    { (const FT_Char *) "IBM",  (const FcChar8 *) "ibm"},
+    { (const FT_Char *) "ITC",  (const FcChar8 *) "itc"},
+    { (const FT_Char *) "IMPR", (const FcChar8 *) "impress"},
+    { (const FT_Char *) "LARA", (const FcChar8 *) "larabiefonts"},
+    { (const FT_Char *) "LEAF", (const FcChar8 *) "interleaf"},
+    { (const FT_Char *) "LETR", (const FcChar8 *) "letraset"},
+    { (const FT_Char *) "LINO", (const FcChar8 *) "linotype"},
+    { (const FT_Char *) "MACR", (const FcChar8 *) "macromedia"},
+    { (const FT_Char *) "MONO", (const FcChar8 *) "monotype"},
+    { (const FT_Char *) "MS",   (const FcChar8 *) "microsoft"},
+    { (const FT_Char *) "MT",   (const FcChar8 *) "monotype"},
+    { (const FT_Char *) "NEC",  (const FcChar8 *) "nec"},
+    { (const FT_Char *) "PARA", (const FcChar8 *) "paratype"},
+    { (const FT_Char *) "QMSI", (const FcChar8 *) "qms"},
+    { (const FT_Char *) "RICO", (const FcChar8 *) "ricoh"},
+    { (const FT_Char *) "URW",  (const FcChar8 *) "urw"},
+    { (const FT_Char *) "Y&Y",  (const FcChar8 *) "y&y"}
 };
 
-static const FcChar8   *fcLangTraditionalChinese[] = {
-    (FcChar8 *) "zh-tw",    /* Chinese-Taiwan */
-    0,
+#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 (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) "bold",            FC_WEIGHT_BOLD },
+    { (FC8) "extrabold",       FC_WEIGHT_EXTRABOLD },
+    { (FC8) "ultrabold",       FC_WEIGHT_ULTRABOLD },
+    { (FC8) "black",           FC_WEIGHT_BLACK },
+    { (FC8) "heavy",           FC_WEIGHT_HEAVY },
 };
 
-static const FcChar8   *fcLangEnglish[] = {
-    (FcChar8 *) "en",   /* English */
-    0,
+#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 */
 };
 
-/*
- * Elide some of the less useful bits
- */
-static const struct {
-    int                    bit;
-    const FcChar8   **lang;
-} FcCodePageRange[] = {
-    { 0,       fcLangLatin1 },
-    { 1,       fcLangLatin2 },
-    { 2,       fcLangCyrillic },
-    { 3,       fcLangGreek },
-    { 4,       fcLangTurkish },
-    { 5,       fcLangHebrew },
-    { 6,       fcLangArabic },
-    { 7,       fcLangWindowsBaltic },
-    { 8,       fcLangVietnamese },
-/* 9-15 reserved for Alternate ANSI */
-    { 16,      fcLangThai },
-    { 17,      fcLangJapanese },
-    { 18,      fcLangSimplifiedChinese },
-    { 19,      fcLangKorean },
-    { 20,      fcLangTraditionalChinese },
-    { 21,      fcLangKorean },
-/* 22-28 reserved for Alternate ANSI & OEM */
-/*    { 29,    fcLangMacintosh }, */
-/*    { 30,    fcLangOem }, */
-/*     { 31,   fcLangSymbol },*/
-/* 32-47 reserved for OEM */
-    { 48,      fcLangGreek },
-    { 49,      fcLangCyrillic },
-/*    { 50,    fcLangMsdosNordic }, */
-    { 51,      fcLangArabic },
-/*    { 52,    fcLangMSDOS_CANADIAN_FRENCH }, */
-    { 53,      fcLangHebrew },
-/*    { 54,    fcLangMSDOS_ICELANDIC }, */
-/*    { 55,    fcLangMSDOS_PORTUGUESE }, */
-    { 56,      fcLangTurkish },
-    { 57,      fcLangCyrillic },
-    { 58,      fcLangLatin2 },
-    { 59,      fcLangWindowsBaltic },
-    { 60,      fcLangGreek },
-    { 61,      fcLangArabic },
-    { 62,      fcLangLatin1 },
-    { 63,      fcLangEnglish },
+#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) "oblique",         FC_SLANT_OBLIQUE },
 };
 
-#define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
+#define NUM_SLANT_CONSTS    (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
 
-FcBool
-FcFreeTypeHasLang (FcPattern *pattern, const FcChar8 *lang)
+#define FcIsSlant(s)       FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
+#define FcContainsSlant(s)  FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
+
+static double
+FcGetPixelSize (FT_Face face, int i)
 {
-    FcChar8    *old;
-    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
+}
 
-    for (i = 0; FcPatternGetString (pattern, FC_LANG, i, &old) == FcResultMatch; i++)
-       if (!FcStrCmp (lang, old))
+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;
 }
 
@@ -233,18 +988,41 @@ FcFreeTypeQuery (const FcChar8    *file,
 {
     FT_Face        face;
     FcPattern      *pat;
-    int                    slant;
-    int                    weight;
+    int                    slant = -1;
+    int                    weight = -1;
+    int                    width = -1;
     int                    i;
     FcCharSet      *cs;
+    FcLangSet      *ls;
     FT_Library     ftLibrary;
-    const FcChar8   *family;
+#if 0
+    FcChar8        *family = 0;
+#endif
+    FcChar8        *complex;
+    const FcChar8   *foundry = 0;
+    int                    spacing;
     TT_OS2         *os2;
-    FcChar32       codepoints;
-    FcChar8        *lang;
-    FcBool         hasLang = FcFalse;
+#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;
 
+    FcChar8        *style = 0;
+    int                    st;
+    
     if (FT_Init_FreeType (&ftLibrary))
        return 0;
     
@@ -266,36 +1044,239 @@ FcFreeTypeQuery (const FcChar8  *file,
        goto bail1;
 
 
-    slant = FC_SLANT_ROMAN;
-    if (face->style_flags & FT_STYLE_FLAG_ITALIC)
-       slant = FC_SLANT_ITALIC;
+    /*
+     * Get the OS/2 table
+     */
+    os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
 
-    if (!FcPatternAddInteger (pat, FC_SLANT, slant))
-       goto bail1;
+    /*
+     * 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);
 
-    weight = FC_WEIGHT_MEDIUM;
-    if (face->style_flags & FT_STYLE_FLAG_BOLD)
-       weight = FC_WEIGHT_BOLD;
+    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 (snamei = 0; snamei < snamec; snamei++)
+    {
+       FcChar8         *utf8;
+       const FcChar8   *lang;
+       const char      *elt = 0, *eltlang = 0;
+       int             *np = 0, *nlangp = 0;
 
-    if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
-       goto bail1;
+       if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
+           continue;
+       
+       utf8 = FcSfntNameTranscode (&sname);
+       lang = FcSfntNameLanguage (&sname);
+
+       if (!utf8)
+           continue;
+       
+       switch (sname.name_id) {
+       case TT_NAME_ID_FONT_FAMILY:
+#if 0      
+       case TT_NAME_ID_PS_NAME:
+       case TT_NAME_ID_UNIQUE_ID:
+#endif
+           if (FcDebug () & FC_DBG_SCANV)
+               printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
+                   sname.name_id, sname.platform_id,
+                   sname.encoding_id, sname.language_id,
+                   utf8);
+    
+           elt = FC_FAMILY;
+           eltlang = FC_FAMILYLANG;
+           np = &nfamily;
+           nlangp = &nfamily_lang;
+           break;
+       case TT_NAME_ID_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,
+                   utf8);
+    
+           elt = FC_FULLNAME;
+           eltlang = FC_FULLNAMELANG;
+           np = &nfullname;
+           nlangp = &nfullname_lang;
+           break;
+       case TT_NAME_ID_FONT_SUBFAMILY:
+           if (FcDebug () & FC_DBG_SCANV)
+               printf ("found style  (n %2d p %d e %d l 0x%04x) %s\n",
+                   sname.name_id, sname.platform_id,
+                   sname.encoding_id, sname.language_id,
+                   utf8);
+    
+           elt = FC_STYLE;
+           eltlang = FC_STYLELANG;
+           np = &nstyle;
+           nlangp = &nstyle_lang;
+           break;
+        case TT_NAME_ID_TRADEMARK:
+        case TT_NAME_ID_MANUFACTURER:
+           /* If the foundry wasn't found in the OS/2 table, look here */
+            if(!foundry)
+                foundry = FcNoticeFoundry((FT_String *) utf8);
+            break;
+       }
+       if (elt)
+       {
+           if (FcStringInPatternElement (pat, elt, utf8))
+           {
+               free (utf8);
+               continue;
+           }
 
-    family = (FcChar8 *) face->family_name;
-    if (!family)
+           /* 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)
     {
-       family = (FcChar8 *) strrchr ((char *) file, '/');
-       if (family)
-           family++;
-       else
-           family = file;
+       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 (!FcPatternAddString (pat, FC_FAMILY, family))
-       goto bail1;
-
-    if (face->style_name)
+    
+    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;
+    }
+
+    /*
+     * 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;
+       FcChar8 *full;
+       FcChar8 *fam;
+       FcChar8 *style;
+
+       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 (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))
@@ -304,26 +1285,39 @@ FcFreeTypeQuery (const FcChar8   *file,
     if (!FcPatternAddInteger (pat, FC_INDEX, id))
        goto bail1;
 
-    if (!FcPatternAddString (pat, FC_SOURCE, (FcChar8 *) "FreeType"))
-       goto bail1;
-
-#if 1
+#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
 
     /*
-     * Get the OS/2 table and poke about
+     * Find the font revision (if available)
      */
-    os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
-    if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
+    head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
+    if (head)
     {
-       for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
-       {
-           FT_ULong    bits;
-           int         bit;
-           if (FcCodePageRange[i].bit < 32)
+       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;
@@ -335,69 +1329,326 @@ FcFreeTypeQuery (const FcChar8  *file,
            }
            if (bits & (1 << bit))
            {
-               int             j;
-               const FcChar8   *lang;
+               /* 
+                * 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;
+           }
+       }
+    }
 
-               for (j = 0; (lang = FcCodePageRange[i].lang[j]); j++)
-                   if (!FcFreeTypeHasLang (pat, lang))
-                   {
-                       if (!FcPatternAddString (pat, FC_LANG, lang))
-                           goto bail1;
-                       hasLang = FcTrue;
-                   }
+    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 < 950)
+           weight = FC_WEIGHT_BLACK;
+
+       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 (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);
+       }
+    }
+    /*
+     * 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;
+
     /*
      * Compute the unicode coverage for the font
      */
-    cs = FcFreeTypeCharSet (face, blanks);
+    cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
     if (!cs)
        goto bail1;
 
-    codepoints = FcCharSetCount (cs);
+#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
+     * ftglue.c 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 (codepoints == 0)
+    if (FcCharSetCount (cs) == 0)
     {
-       if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
+#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;
 
-    if (!hasLang)
+    ls = FcFreeTypeLangSet (cs, exclusiveLang);
+    if (!ls)
+       goto bail2;
+
+    if (!FcPatternAddLangSet (pat, FC_LANG, ls))
     {
-       if (!FcFreeTypeSetLang (pat, cs))
+       FcLangSetDestroy (ls);
+       goto bail2;
+    }
+
+    FcLangSetDestroy (ls);
+
+    if (spacing != FC_PROPORTIONAL)
+       if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
            goto bail2;
 
-       /*
-        * Make sure it has a lang entry
-        */
-       if (FcPatternGetString (pat, FC_LANG, 0, &lang) != FcResultMatch)
-           if (!FcPatternAddString (pat, FC_LANG, (FcChar8 *) "x-unknown"))
+    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_BDF_PROPERTY
+        if(face->num_fixed_sizes == 1) {
+            int rc;
+            int value;
+
+           /* skip bitmap fonts which do not even have a family name */
+           rc =  FT_Get_BDF_Property(face, "FAMILY_NAME", &prop);
+           if (rc != 0 || prop.type != BDF_PROPERTY_TYPE_ATOM)
                goto bail2;
+
+            rc = FT_Get_BDF_Property(face, "POINT_SIZE", &prop);
+            if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
+                value = prop.u.integer;
+            else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
+                value = prop.u.cardinal;
+            else
+                goto nevermind;
+            if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
+                goto nevermind;
+
+            rc = FT_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
+            if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
+                value = prop.u.integer;
+            else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
+                value = prop.u.cardinal;
+            else
+                goto nevermind;
+            if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
+                goto nevermind;
+
+        }
+    nevermind:
+        ;
+#endif
+    }
+#if HAVE_FT_GET_X11_FONT_FORMAT
+    /*
+     * Use the (not well documented or supported) X-specific function
+     * from FreeType to figure out the font format
+     */
+    {
+       const char *font_format = FT_Get_X11_Font_Format (face);
+       if (font_format)
+           FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
     }
+#endif
 
     /*
      * Drop our reference to the charset
      */
     FcCharSetDestroy (cs);
     
-    if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
-    {
-       for (i = 0; i < face->num_fixed_sizes; i++)
-           if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
-                                    (double) face->available_sizes[i].height))
-               goto bail1;
-       if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
-           goto bail1;
-    }
-
+    /*
+     * Deallocate family/style values
+     */
+    
     FT_Done_Face (face);
     FT_Done_FreeType (ftLibrary);
     return pat;
@@ -412,3 +1663,1213 @@ bail:
     FT_Done_FreeType (ftLibrary);
     return 0;
 }
+
+
+/*
+ * For our purposes, this approximation is sufficient
+ */
+#if !HAVE_FT_GET_NEXT_CHAR
+#define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
+                                         (*(gi) = 0), 0 : \
+                                         (*(gi) = 1), (ucs4) + 1)
+#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
+#endif
+
+typedef struct _FcCharEnt {
+    FcChar16       bmp;
+    unsigned char   encode;
+} FcCharEnt;
+
+struct _FcCharMap {
+    const FcCharEnt *ent;
+    int                    nent;
+};
+
+typedef struct _FcFontDecode {
+    FT_Encoding            encoding;
+    const FcCharMap *map;
+    FcChar32       max;
+} FcFontDecode;
+
+static const FcCharEnt AppleRomanEnt[] = {
+    { 0x0020, 0x20 }, /* SPACE */
+    { 0x0021, 0x21 }, /* EXCLAMATION MARK */
+    { 0x0022, 0x22 }, /* QUOTATION MARK */
+    { 0x0023, 0x23 }, /* NUMBER SIGN */
+    { 0x0024, 0x24 }, /* DOLLAR SIGN */
+    { 0x0025, 0x25 }, /* PERCENT SIGN */
+    { 0x0026, 0x26 }, /* AMPERSAND */
+    { 0x0027, 0x27 }, /* APOSTROPHE */
+    { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
+    { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
+    { 0x002A, 0x2A }, /* ASTERISK */
+    { 0x002B, 0x2B }, /* PLUS SIGN */
+    { 0x002C, 0x2C }, /* COMMA */
+    { 0x002D, 0x2D }, /* HYPHEN-MINUS */
+    { 0x002E, 0x2E }, /* FULL STOP */
+    { 0x002F, 0x2F }, /* SOLIDUS */
+    { 0x0030, 0x30 }, /* DIGIT ZERO */
+    { 0x0031, 0x31 }, /* DIGIT ONE */
+    { 0x0032, 0x32 }, /* DIGIT TWO */
+    { 0x0033, 0x33 }, /* DIGIT THREE */
+    { 0x0034, 0x34 }, /* DIGIT FOUR */
+    { 0x0035, 0x35 }, /* DIGIT FIVE */
+    { 0x0036, 0x36 }, /* DIGIT SIX */
+    { 0x0037, 0x37 }, /* DIGIT SEVEN */
+    { 0x0038, 0x38 }, /* DIGIT EIGHT */
+    { 0x0039, 0x39 }, /* DIGIT NINE */
+    { 0x003A, 0x3A }, /* COLON */
+    { 0x003B, 0x3B }, /* SEMICOLON */
+    { 0x003C, 0x3C }, /* LESS-THAN SIGN */
+    { 0x003D, 0x3D }, /* EQUALS SIGN */
+    { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
+    { 0x003F, 0x3F }, /* QUESTION MARK */
+    { 0x0040, 0x40 }, /* COMMERCIAL AT */
+    { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
+    { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
+    { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
+    { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
+    { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
+    { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
+    { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
+    { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
+    { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
+    { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
+    { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
+    { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
+    { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
+    { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
+    { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
+    { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
+    { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
+    { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
+    { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
+    { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
+    { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
+    { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
+    { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
+    { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
+    { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
+    { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
+    { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
+    { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
+    { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
+    { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
+    { 0x005F, 0x5F }, /* LOW LINE */
+    { 0x0060, 0x60 }, /* GRAVE ACCENT */
+    { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
+    { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
+    { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
+    { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
+    { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
+    { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
+    { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
+    { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
+    { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
+    { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
+    { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
+    { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
+    { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
+    { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
+    { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
+    { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
+    { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
+    { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
+    { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
+    { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
+    { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
+    { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
+    { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
+    { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
+    { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
+    { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
+    { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
+    { 0x007C, 0x7C }, /* VERTICAL LINE */
+    { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
+    { 0x007E, 0x7E }, /* TILDE */
+    { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
+    { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
+    { 0x00A2, 0xA2 }, /* CENT SIGN */
+    { 0x00A3, 0xA3 }, /* POUND SIGN */
+    { 0x00A5, 0xB4 }, /* YEN SIGN */
+    { 0x00A7, 0xA4 }, /* SECTION SIGN */
+    { 0x00A8, 0xAC }, /* DIAERESIS */
+    { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
+    { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
+    { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+    { 0x00AC, 0xC2 }, /* NOT SIGN */
+    { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
+    { 0x00AF, 0xF8 }, /* MACRON */
+    { 0x00B0, 0xA1 }, /* DEGREE SIGN */
+    { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
+    { 0x00B4, 0xAB }, /* ACUTE ACCENT */
+    { 0x00B5, 0xB5 }, /* MICRO SIGN */
+    { 0x00B6, 0xA6 }, /* PILCROW SIGN */
+    { 0x00B7, 0xE1 }, /* MIDDLE DOT */
+    { 0x00B8, 0xFC }, /* CEDILLA */
+    { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
+    { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+    { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
+    { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
+    { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
+    { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+    { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
+    { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
+    { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
+    { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
+    { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
+    { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
+    { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
+    { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+    { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+    { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
+    { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
+    { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+    { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+    { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
+    { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
+    { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
+    { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+    { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
+    { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
+    { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
+    { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
+    { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
+    { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+    { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
+    { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
+    { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
+    { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
+    { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
+    { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
+    { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
+    { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
+    { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
+    { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
+    { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
+    { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
+    { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
+    { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
+    { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
+    { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
+    { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
+    { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
+    { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
+    { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
+    { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
+    { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
+    { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
+    { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
+    { 0x00F7, 0xD6 }, /* DIVISION SIGN */
+    { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
+    { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
+    { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
+    { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
+    { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
+    { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
+    { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
+    { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
+    { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
+    { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+    { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
+    { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+    { 0x02C7, 0xFF }, /* CARON */
+    { 0x02D8, 0xF9 }, /* BREVE */
+    { 0x02D9, 0xFA }, /* DOT ABOVE */
+    { 0x02DA, 0xFB }, /* RING ABOVE */
+    { 0x02DB, 0xFE }, /* OGONEK */
+    { 0x02DC, 0xF7 }, /* SMALL TILDE */
+    { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
+    { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
+    { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
+    { 0x2013, 0xD0 }, /* EN DASH */
+    { 0x2014, 0xD1 }, /* EM DASH */
+    { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
+    { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
+    { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
+    { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
+    { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
+    { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
+    { 0x2020, 0xA0 }, /* DAGGER */
+    { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
+    { 0x2022, 0xA5 }, /* BULLET */
+    { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
+    { 0x2030, 0xE4 }, /* PER MILLE SIGN */
+    { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+    { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+    { 0x2044, 0xDA }, /* FRACTION SLASH */
+    { 0x20AC, 0xDB }, /* EURO SIGN */
+    { 0x2122, 0xAA }, /* TRADE MARK SIGN */
+    { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
+    { 0x2206, 0xC6 }, /* INCREMENT */
+    { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
+    { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
+    { 0x221A, 0xC3 }, /* SQUARE ROOT */
+    { 0x221E, 0xB0 }, /* INFINITY */
+    { 0x222B, 0xBA }, /* INTEGRAL */
+    { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
+    { 0x2260, 0xAD }, /* NOT EQUAL TO */
+    { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
+    { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
+    { 0x25CA, 0xD7 }, /* LOZENGE */
+    { 0xF8FF, 0xF0 }, /* Apple logo */
+    { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
+    { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
+};
+
+static const FcCharMap AppleRoman = {
+    AppleRomanEnt,
+    sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
+};
+
+static const FcCharEnt AdobeSymbolEnt[] = {
+    { 0x0020, 0x20 }, /* SPACE # space */
+    { 0x0021, 0x21 }, /* EXCLAMATION MARK      # exclam */
+    { 0x0023, 0x23 }, /* NUMBER SIGN   # numbersign */
+    { 0x0025, 0x25 }, /* PERCENT SIGN  # percent */
+    { 0x0026, 0x26 }, /* AMPERSAND     # ampersand */
+    { 0x0028, 0x28 }, /* LEFT PARENTHESIS      # parenleft */
+    { 0x0029, 0x29 }, /* RIGHT PARENTHESIS     # parenright */
+    { 0x002B, 0x2B }, /* PLUS SIGN     # plus */
+    { 0x002C, 0x2C }, /* COMMA # comma */
+    { 0x002E, 0x2E }, /* FULL STOP     # period */
+    { 0x002F, 0x2F }, /* SOLIDUS       # slash */
+    { 0x0030, 0x30 }, /* DIGIT ZERO    # zero */
+    { 0x0031, 0x31 }, /* DIGIT ONE     # one */
+    { 0x0032, 0x32 }, /* DIGIT TWO     # two */
+    { 0x0033, 0x33 }, /* DIGIT THREE   # three */
+    { 0x0034, 0x34 }, /* DIGIT FOUR    # four */
+    { 0x0035, 0x35 }, /* DIGIT FIVE    # five */
+    { 0x0036, 0x36 }, /* DIGIT SIX     # six */
+    { 0x0037, 0x37 }, /* DIGIT SEVEN   # seven */
+    { 0x0038, 0x38 }, /* DIGIT EIGHT   # eight */
+    { 0x0039, 0x39 }, /* DIGIT NINE    # nine */
+    { 0x003A, 0x3A }, /* COLON # colon */
+    { 0x003B, 0x3B }, /* SEMICOLON     # semicolon */
+    { 0x003C, 0x3C }, /* LESS-THAN SIGN        # less */
+    { 0x003D, 0x3D }, /* EQUALS SIGN   # equal */
+    { 0x003E, 0x3E }, /* GREATER-THAN SIGN     # greater */
+    { 0x003F, 0x3F }, /* QUESTION MARK # question */
+    { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET   # bracketleft */
+    { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET  # bracketright */
+    { 0x005F, 0x5F }, /* LOW LINE      # underscore */
+    { 0x007B, 0x7B }, /* LEFT CURLY BRACKET    # braceleft */
+    { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
+    { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET   # braceright */
+    { 0x00A0, 0x20 }, /* NO-BREAK SPACE        # space */
+    { 0x00AC, 0xD8 }, /* NOT SIGN      # logicalnot */
+    { 0x00B0, 0xB0 }, /* DEGREE SIGN   # degree */
+    { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN       # plusminus */
+    { 0x00B5, 0x6D }, /* MICRO SIGN    # mu */
+    { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN   # multiply */
+    { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
+    { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK        # florin */
+    { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA    # Alpha */
+    { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA     # Beta */
+    { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA    # Gamma */
+    { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA    # Delta */
+    { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON  # Epsilon */
+    { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA     # Zeta */
+    { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA      # Eta */
+    { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA    # Theta */
+    { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA     # Iota */
+    { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA    # Kappa */
+    { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA    # Lambda */
+    { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU       # Mu */
+    { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU       # Nu */
+    { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI       # Xi */
+    { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON  # Omicron */
+    { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI       # Pi */
+    { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO      # Rho */
+    { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA    # Sigma */
+    { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU      # Tau */
+    { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON  # Upsilon */
+    { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI      # Phi */
+    { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI      # Chi */
+    { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI      # Psi */
+    { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA    # Omega */
+    { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA      # alpha */
+    { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA       # beta */
+    { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA      # gamma */
+    { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA      # delta */
+    { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON    # epsilon */
+    { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA       # zeta */
+    { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA        # eta */
+    { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA      # theta */
+    { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA       # iota */
+    { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA      # kappa */
+    { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA      # lambda */
+    { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
+    { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
+    { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
+    { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON    # omicron */
+    { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
+    { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO        # rho */
+    { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA        # sigma1 */
+    { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA      # sigma */
+    { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU        # tau */
+    { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON    # upsilon */
+    { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI        # phi */
+    { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI        # chi */
+    { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI        # psi */
+    { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA      # omega */
+    { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL    # theta1 */
+    { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL        # Upsilon1 */
+    { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL      # phi1 */
+    { 0x03D6, 0x76 }, /* GREEK PI SYMBOL       # omega1 */
+    { 0x2022, 0xB7 }, /* BULLET        # bullet */
+    { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS   # ellipsis */
+    { 0x2032, 0xA2 }, /* PRIME # minute */
+    { 0x2033, 0xB2 }, /* DOUBLE PRIME  # second */
+    { 0x2044, 0xA4 }, /* FRACTION SLASH        # fraction */
+    { 0x20AC, 0xA0 }, /* EURO SIGN     # Euro */
+    { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I        # Ifraktur */
+    { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P      # weierstrass */
+    { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R        # Rfraktur */
+    { 0x2126, 0x57 }, /* OHM SIGN      # Omega */
+    { 0x2135, 0xC0 }, /* ALEF SYMBOL   # aleph */
+    { 0x2190, 0xAC }, /* LEFTWARDS ARROW       # arrowleft */
+    { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
+    { 0x2192, 0xAE }, /* RIGHTWARDS ARROW      # arrowright */
+    { 0x2193, 0xAF }, /* DOWNWARDS ARROW       # arrowdown */
+    { 0x2194, 0xAB }, /* LEFT RIGHT ARROW      # arrowboth */
+    { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
+    { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW        # arrowdblleft */
+    { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW  # arrowdblup */
+    { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW       # arrowdblright */
+    { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW        # arrowdbldown */
+    { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW       # arrowdblboth */
+    { 0x2200, 0x22 }, /* FOR ALL       # universal */
+    { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL  # partialdiff */
+    { 0x2203, 0x24 }, /* THERE EXISTS  # existential */
+    { 0x2205, 0xC6 }, /* EMPTY SET     # emptyset */
+    { 0x2206, 0x44 }, /* INCREMENT     # Delta */
+    { 0x2207, 0xD1 }, /* NABLA # gradient */
+    { 0x2208, 0xCE }, /* ELEMENT OF    # element */
+    { 0x2209, 0xCF }, /* NOT AN ELEMENT OF     # notelement */
+    { 0x220B, 0x27 }, /* CONTAINS AS MEMBER    # suchthat */
+    { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
+    { 0x2211, 0xE5 }, /* N-ARY SUMMATION       # summation */
+    { 0x2212, 0x2D }, /* MINUS SIGN    # minus */
+    { 0x2215, 0xA4 }, /* DIVISION SLASH        # fraction */
+    { 0x2217, 0x2A }, /* ASTERISK OPERATOR     # asteriskmath */
+    { 0x221A, 0xD6 }, /* SQUARE ROOT   # radical */
+    { 0x221D, 0xB5 }, /* PROPORTIONAL TO       # proportional */
+    { 0x221E, 0xA5 }, /* INFINITY      # infinity */
+    { 0x2220, 0xD0 }, /* ANGLE # angle */
+    { 0x2227, 0xD9 }, /* LOGICAL AND   # logicaland */
+    { 0x2228, 0xDA }, /* LOGICAL OR    # logicalor */
+    { 0x2229, 0xC7 }, /* INTERSECTION  # intersection */
+    { 0x222A, 0xC8 }, /* UNION # union */
+    { 0x222B, 0xF2 }, /* INTEGRAL      # integral */
+    { 0x2234, 0x5C }, /* THEREFORE     # therefore */
+    { 0x223C, 0x7E }, /* TILDE OPERATOR        # similar */
+    { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO        # congruent */
+    { 0x2248, 0xBB }, /* ALMOST EQUAL TO       # approxequal */
+    { 0x2260, 0xB9 }, /* NOT EQUAL TO  # notequal */
+    { 0x2261, 0xBA }, /* IDENTICAL TO  # equivalence */
+    { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
+    { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO      # greaterequal */
+    { 0x2282, 0xCC }, /* SUBSET OF     # propersubset */
+    { 0x2283, 0xC9 }, /* SUPERSET OF   # propersuperset */
+    { 0x2284, 0xCB }, /* NOT A SUBSET OF       # notsubset */
+    { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
+    { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO       # reflexsuperset */
+    { 0x2295, 0xC5 }, /* CIRCLED PLUS  # circleplus */
+    { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
+    { 0x22A5, 0x5E }, /* UP TACK       # perpendicular */
+    { 0x22C5, 0xD7 }, /* DOT OPERATOR  # dotmath */
+    { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL     # integraltp */
+    { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL  # integralbt */
+    { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET   # angleleft */
+    { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET  # angleright */
+    { 0x25CA, 0xE0 }, /* LOZENGE       # lozenge */
+    { 0x2660, 0xAA }, /* BLACK SPADE SUIT      # spade */
+    { 0x2663, 0xA7 }, /* BLACK CLUB SUIT       # club */
+    { 0x2665, 0xA9 }, /* BLACK HEART SUIT      # heart */
+    { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT    # diamond */
+    { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF  # copyrightserif (CUS) */
+    { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
+    { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
+    { 0xF8E5, 0x60 }, /* RADICAL EXTENDER      # radicalex (CUS) */
+    { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER       # arrowvertex (CUS) */
+    { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER     # arrowhorizex (CUS) */
+    { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF    # registersans (CUS) */
+    { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF     # copyrightsans (CUS) */
+    { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF    # trademarksans (CUS) */
+    { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP        # parenlefttp (CUS) */
+    { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER   # parenleftex (CUS) */
+    { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM     # parenleftbt (CUS) */
+    { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP       # bracketlefttp (CUS) */
+    { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER  # bracketleftex (CUS) */
+    { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM    # bracketleftbt (CUS) */
+    { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP        # bracelefttp (CUS) */
+    { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID        # braceleftmid (CUS) */
+    { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM     # braceleftbt (CUS) */
+    { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER        # braceex (CUS) */
+    { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER     # integralex (CUS) */
+    { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP       # parenrighttp (CUS) */
+    { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER  # parenrightex (CUS) */
+    { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM    # parenrightbt (CUS) */
+    { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP      # bracketrighttp (CUS) */
+    { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
+    { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM   # bracketrightbt (CUS) */
+    { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP       # bracerighttp (CUS) */
+    { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID       # bracerightmid (CUS) */
+    { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM    # bracerightbt (CUS) */
+};
+
+static const FcCharMap AdobeSymbol = {
+    AdobeSymbolEnt,
+    sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
+};
+    
+static const FcFontDecode fcFontDecoders[] = {
+    { ft_encoding_unicode,     0,              (1 << 21) - 1 },
+    { ft_encoding_symbol,      &AdobeSymbol,   (1 << 16) - 1 },
+    { ft_encoding_apple_roman, &AppleRoman,    (1 << 16) - 1 },
+};
+
+#define NUM_DECODE  (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
+
+static const FcChar32  prefer_unicode[] = {
+    0x20ac,    /* EURO SIGN */
+};
+
+#define NUM_PREFER_UNICODE  (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
+
+FcChar32
+FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
+{
+    int                low, high, mid;
+    FcChar16   bmp;
+
+    low = 0;
+    high = map->nent - 1;
+    if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
+       return ~0;
+    while (low <= high)
+    {
+       mid = (high + low) >> 1;
+       bmp = map->ent[mid].bmp;
+       if (ucs4 == bmp)
+           return (FT_ULong) map->ent[mid].encode;
+       if (ucs4 < bmp)
+           high = mid - 1;
+       else
+           low = mid + 1;
+    }
+    return ~0;
+}
+
+FcChar32
+FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
+{
+    int            i;
+
+    for (i = 0; i < map->nent; i++)
+       if (map->ent[i].encode == private)
+           return (FcChar32) map->ent[i].bmp;
+    return ~0;
+}
+
+const FcCharMap *
+FcFreeTypeGetPrivateMap (FT_Encoding encoding)
+{
+    int        i;
+
+    for (i = 0; i < NUM_DECODE; i++)
+       if (fcFontDecoders[i].encoding == encoding)
+           return fcFontDecoders[i].map;
+    return 0;
+}
+
+#include "../fc-glyphname/fcglyphname.h"
+
+static FcChar32
+FcHashGlyphName (const FcChar8 *name)
+{
+    FcChar32   h = 0;
+    FcChar8    c;
+
+    while ((c = *name++))
+    {
+       h = ((h << 1) | (h >> 31)) ^ c;
+    }
+    return h;
+}
+
+#if HAVE_FT_HAS_PS_GLYPH_NAMES
+/*
+ * Use Type1 glyph names for fonts which have reliable names
+ * and which export an Adobe Custom mapping
+ */
+static FcBool
+FcFreeTypeUseNames (FT_Face face)
+{
+    FT_Int  map;
+    
+    if (!FT_Has_PS_Glyph_Names (face))
+       return FcFalse;
+    for (map = 0; map < face->num_charmaps; map++)
+       if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
+           return FcTrue;
+    return FcFalse;
+}
+
+static const FcChar8 *
+FcUcs4ToGlyphName (FcChar32 ucs4)
+{
+    int                i = (int) (ucs4 % FC_GLYPHNAME_HASH);
+    int                r = 0;
+    const FcGlyphName  *gn;
+
+    while ((gn = ucs_to_name[i]))
+    {
+       if (gn->ucs == ucs4)
+           return 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;
+    const FcGlyphName  *gn;
+
+    while ((gn = name_to_ucs[i]))
+    {
+       if (!strcmp ((char *) name, (char *) gn->name))
+           return 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;
+}
+
+/*
+ * 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_MAXLEN + 2];
+
+    for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
+    {
+       if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+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)
+{
+    FT_Int         load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+    FT_GlyphSlot    slot;
+    
+    /*
+     * When using scalable fonts, only report those glyphs
+     * which can be scaled; otherwise those fonts will
+     * only be available at some sizes, and never when
+     * transformed.  Avoid this by simply reporting bitmap-only
+     * glyphs as missing
+     */
+    if (face->face_flags & FT_FACE_FLAG_SCALABLE)
+       load_flags |= FT_LOAD_NO_BITMAP;
+    
+    if (FT_Load_Glyph (face, glyph, load_flags))
+       return FcFalse;
+    
+    slot = face->glyph;
+    if (!glyph)
+       return FcFalse;
+    
+    *advance = slot->metrics.horiAdvance;
+
+    switch (slot->format) {
+    case ft_glyph_format_bitmap:
+       /*
+        * Bitmaps are assumed to be reasonable; if
+        * this proves to be a rash assumption, this
+        * code can be easily modified
+        */
+       return FcTrue;
+    case ft_glyph_format_outline:
+       /*
+        * Glyphs with contours are always OK
+        */
+       if (slot->outline.n_contours != 0)
+           return FcTrue;
+       /*
+        * Glyphs with no contours are only OK if
+        * they're members of the Blanks set specified
+        * in the configuration.  If blanks isn't set,
+        * then allow any glyph to be blank
+        */
+       if (!blanks || FcBlanksIsMember (blanks, ucs4))
+           return FcTrue;
+       /* fall through ... */
+    default:
+       break;
+    }
+    return FcFalse;
+}
+
+#define 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))
+#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
+
+FcCharSet *
+FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
+{
+    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;
+
+    fcs = FcCharSetCreate ();
+    if (!fcs)
+       goto bail0;
+    
+#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))
+               {
+                   /* 
+                    * 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
+       {
+           FT_UInt gindex;
+         
+           /*
+            * Find the first encoded character in the font
+            */
+           if (FT_Get_Char_Index (face, 0))
+           {
+               ucs4 = 0;
+               gindex = 1;
+           }
+           else
+           {
+               ucs4 = FT_Get_Next_Char (face, 0, &gindex);
+               if (!ucs4)
+                   gindex = 0;
+           }
+
+           while (gindex)
+           {
+               page = ucs4 >> 8;
+               leaf = 0;
+               while ((ucs4 >> 8) == page)
+               {
+                   glyph = FT_Get_Char_Index (face, ucs4);
+                   if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
+                                                      glyph, blanks, &advance))
+                   {
+                       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 (!leaf)
+                       {
+                           leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+                           if (!leaf)
+                               goto bail1;
+                       }
+                       off = ucs4 & 0xff;
+                       leaf->map[off >> 5] |= (1 << (off & 0x1f));
+#ifdef CHECK
+                       if (ucs4 > font_max)
+                           font_max = ucs4;
+#endif
+                   }
+                   ucs4++;
+               }
+               ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
+               if (!ucs4)
+                   gindex = 0;
+           }
+#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_MAXLEN + 2];
+
+       for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
+       {
+           if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
+           {
+               ucs4 = FcGlyphNameToUcs4 (name_buf);
+               if (ucs4 != 0xffff && 
+                   FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
+               {
+                   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))
+               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 *
+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 TT_Err_Ok FT_Err_Ok
+#define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
+#define TTO_Err_Empty_Script              0x1005
+#define TTO_Err_Invalid_SubTable          0x1001
+
+#define OTLAYOUT_HEAD      "otlayout:"
+#define OTLAYOUT_HEAD_LEN   9
+#define OTLAYOUT_ID_LEN            4
+/* space + head + id */
+#define OTLAYOUT_LEN       (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
+
+/*
+ * This is a bit generous; the registry has only lower case and space
+ * except for 'DFLT'.
+ */
+#define FcIsSpace(x)       (040 == (x))
+#define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
+                            
+static void
+addtag(FcChar8 *complex, FT_ULong tag)
+{
+    FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
+
+    tagstring[0] = (FcChar8)(tag >> 24),
+    tagstring[1] = (FcChar8)(tag >> 16),
+    tagstring[2] = (FcChar8)(tag >> 8),
+    tagstring[3] = (FcChar8)(tag);
+    tagstring[4] = '\0';
+    
+    /* skip tags which aren't alphabetic, under the assumption that
+     * they're probably broken
+     */
+    if (!FcIsValidScript(tagstring[0]) ||
+       !FcIsValidScript(tagstring[1]) ||
+       !FcIsValidScript(tagstring[2]) ||
+       !FcIsValidScript(tagstring[3]))
+       return;
+
+    if (*complex != '\0')
+       strcat ((char *) complex, " ");
+    strcat ((char *) complex, "otlayout:");
+    strcat ((char *) complex, (char *) tagstring);
+}
+
+static int
+compareulong (const void *a, const void *b)
+{
+    const FT_ULong *ua = (const FT_ULong *) a;
+    const FT_ULong *ub = (const FT_ULong *) b;
+    return *ua - *ub;
+}
+
+
+static FT_Error
+GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
+{
+    FT_ULong         cur_offset, new_offset, base_offset;
+    FT_Stream  stream = face->stream;
+    FT_Error   error;
+    FT_UShort          n, p;
+    FT_Memory  memory;
+
+    if ( !stream )
+       return TT_Err_Invalid_Face_Handle;
+
+    memory = stream->memory;
+
+    if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
+       return error;
+
+    base_offset = ftglue_stream_pos ( stream );
+
+    /* skip version */
+
+    if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
+       return error;
+
+    new_offset = GET_UShort() + base_offset;
+
+    ftglue_stream_frame_exit( stream );
+
+    cur_offset = ftglue_stream_pos( stream );
+
+    if ( ftglue_stream_seek( stream, new_offset ) != TT_Err_Ok )
+       return error;
+
+    base_offset = ftglue_stream_pos( stream );
+
+    if ( ftglue_stream_frame_enter( stream, 2L ) )
+       return error;
+
+    *script_count = GET_UShort ();
+
+    ftglue_stream_frame_exit( stream );
+
+    *stags = ftglue_alloc(memory, *script_count * sizeof( FT_ULong ), &error);
+
+    if (error)
+       return error;
+
+    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 == TT_Err_Ok )
+           p++;
+
+       (void)ftglue_stream_seek( stream, cur_offset );
+    }
+
+    if (!p)
+    {
+       error = TTO_Err_Invalid_SubTable;
+       goto Fail;
+    }
+
+    /* sort the tag list before returning it */
+    qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
+
+    return TT_Err_Ok;
+
+Fail:
+    *script_count = 0;
+    ftglue_free( memory, *stags );
+    *stags = NULL;
+    return error;
+}
+
+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;
+    FT_Memory  memory = face->stream->memory;
+    FcChar8 *complex = NULL;
+    int indx1 = 0, indx2 = 0;
+
+    err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
+    issilgraphitefont = ( err == FT_Err_Ok);
+
+    if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
+       gpos_count = 0;
+    if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
+       gsub_count = 0;
+    
+    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:
+    ftglue_free(memory, gsubtags);
+    ftglue_free(memory, gpostags);
+    return complex;
+}