]> git.wh0rd.org Git - fontconfig.git/blob - src/fcfreetype.c
Don't force bitmap font enable in default configuration; allows users to
[fontconfig.git] / src / fcfreetype.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcfreetype.c,v 1.11 2002/08/31 22:17:32 keithp Exp $
3  *
4  * Copyright © 2001 Keith Packard
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 /*
26   Copyright © 2002-2003 by Juliusz Chroboczek
27
28   Permission is hereby granted, free of charge, to any person obtaining a copy
29   of this software and associated documentation files (the "Software"), to deal
30   in the Software without restriction, including without limitation the rights
31   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32   copies of the Software, and to permit persons to whom the Software is
33   furnished to do so, subject to the following conditions:
34
35   The above copyright notice and this permission notice shall be included in
36   all copies or substantial portions of the Software.
37
38   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
41   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44   THE SOFTWARE.
45 */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include "fcint.h"
51 #include <ft2build.h>
52 #include FT_FREETYPE_H
53 #include FT_INTERNAL_OBJECTS_H
54 #include FT_TRUETYPE_TABLES_H
55 #include FT_SFNT_NAMES_H
56 #include FT_TRUETYPE_IDS_H
57 #include FT_TYPE1_TABLES_H
58 #include FT_INTERNAL_STREAM_H
59 #include FT_INTERNAL_SFNT_H
60 #include FT_INTERNAL_TRUETYPE_TYPES_H
61 #if HAVE_FT_GET_X11_FONT_FORMAT
62 #include FT_XFREE86_H
63 #endif
64
65 #if HAVE_FT_GET_BDF_PROPERTY
66 #include FT_BDF_H
67 #include FT_MODULE_H
68 #define HAS_BDF_PROPERTY(f) ((f) && (f)->driver && \
69                              (f)->driver->root.clazz->get_interface)
70 #define MY_Get_BDF_Property(f,n,p) (HAS_BDF_PROPERTY(f) ? \
71                                     FT_Get_BDF_Property(f,n,p) : \
72                                     FT_Err_Invalid_Argument)
73 #endif
74
75 #if !HAVE_FT_GET_BDF_PROPERTY
76 #warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later"
77 #endif
78
79 #if !HAVE_FT_GET_PS_FONT_INFO
80 #warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
81 #endif
82
83 /*
84  * Keep Han languages separated by eliminating languages
85  * that the codePageRange bits says aren't supported
86  */
87
88 static const struct {
89     int             bit;
90     const FcChar8   *lang;
91 } FcCodePageRange[] = {
92     { 17,       (const FcChar8 *) "ja" },
93     { 18,       (const FcChar8 *) "zh-cn" },
94     { 19,       (const FcChar8 *) "ko" },
95     { 20,       (const FcChar8 *) "zh-tw" },
96 };
97
98 #define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
99
100 FcBool
101 FcFreeTypeIsExclusiveLang (const FcChar8  *lang)
102 {
103     int     i;
104
105     for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
106     {
107         if (FcLangCompare (lang, FcCodePageRange[i].lang) != FcLangDifferentLang)
108             return FcTrue;
109     }
110     return FcFalse;
111 }
112
113 typedef struct {
114     FT_UShort   platform_id;
115     FT_UShort   encoding_id;
116     char        *fromcode;
117 } FcFtEncoding;
118
119 #define TT_ENCODING_DONT_CARE   0xffff
120 #define FC_ENCODING_MAC_ROMAN   "MACINTOSH"
121
122 static const FcFtEncoding   fcFtEncoding[] = {
123  {  TT_PLATFORM_APPLE_UNICODE,  TT_ENCODING_DONT_CARE,  "UCS-2BE" },
124  {  TT_PLATFORM_MACINTOSH,      TT_MAC_ID_ROMAN,        "MACINTOSH" },
125  {  TT_PLATFORM_MACINTOSH,      TT_MAC_ID_JAPANESE,     "SJIS" },
126  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_UNICODE_CS,    "UTF-16BE" },
127  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_SJIS,          "SJIS-WIN" },
128  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_GB2312,        "GB3212" },
129  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_BIG_5,         "BIG-5" },
130  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_WANSUNG,       "Wansung" },
131  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_JOHAB,         "Johab" },
132  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_UCS_4,         "UCS4" },
133  {  TT_PLATFORM_ISO,            TT_ISO_ID_7BIT_ASCII,   "ASCII" },
134  {  TT_PLATFORM_ISO,            TT_ISO_ID_10646,        "UCS-2BE" },
135  {  TT_PLATFORM_ISO,            TT_ISO_ID_8859_1,       "ISO-8859-1" },
136 };
137
138 #define NUM_FC_FT_ENCODING  (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
139
140 typedef struct {
141     FT_UShort   platform_id;
142     FT_UShort   language_id;
143     char        *lang;
144 } FcFtLanguage;
145
146 #define TT_LANGUAGE_DONT_CARE   0xffff
147
148 static const FcFtLanguage   fcFtLanguage[] = {
149  {  TT_PLATFORM_APPLE_UNICODE,  TT_LANGUAGE_DONT_CARE,              0 },
150  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ENGLISH,              "en" },
151  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FRENCH,               "fr" },
152  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GERMAN,               "de" },
153  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ITALIAN,              "it" },
154  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_DUTCH,                "nl" },
155  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SWEDISH,              "sv" },
156  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SPANISH,              "es" },
157  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_DANISH,               "da" },
158  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_PORTUGUESE,           "pt" },
159  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_NORWEGIAN,            "no" },
160  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_HEBREW,               "he" },
161  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_JAPANESE,             "ja" },
162  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ARABIC,               "ar" },
163  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FINNISH,              "fi" },
164  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GREEK,                "el" },
165  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ICELANDIC,            "is" },
166  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALTESE,              "mt" },
167  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TURKISH,              "tr" },
168  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CROATIAN,             "hr" },
169  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CHINESE_TRADITIONAL,  "zh-tw" },
170  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_URDU,                 "ur" },
171  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_HINDI,                "hi" },
172  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_THAI,                 "th" },
173  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KOREAN,               "ko" },
174  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LITHUANIAN,           "lt" },
175  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_POLISH,               "pl" },
176  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_HUNGARIAN,            "hu" },
177  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ESTONIAN,             "et" },
178  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LETTISH,              "lv" },
179 /* {  TT_PLATFORM_MACINTOSH,    TT_MAC_LANGID_SAAMISK, ??? */
180  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FAEROESE,             "fo" },
181  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FARSI,                "fa" },
182  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_RUSSIAN,              "ru" },
183  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CHINESE_SIMPLIFIED,   "zh-cn" },
184  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FLEMISH,              "nl" },
185  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_IRISH,                "ga" },
186  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ALBANIAN,             "sq" },
187  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ROMANIAN,             "ro" },
188  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CZECH,                "cs" },
189  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SLOVAK,               "sk" },
190  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SLOVENIAN,            "sl" },
191  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_YIDDISH,              "yi" },
192  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SERBIAN,              "sr" },
193  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MACEDONIAN,           "mk" },
194  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BULGARIAN,            "bg" },
195  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_UKRAINIAN,            "uk" },
196  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BYELORUSSIAN,         "be" },
197  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_UZBEK,                "uz" },
198  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KAZAKH,               "kk" },
199  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI,          "az" },
200  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
201  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT,    "ar" },
202  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ARMENIAN,             "hy" },
203  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GEORGIAN,             "ka" },
204  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MOLDAVIAN,            "mo" },
205  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KIRGHIZ,              "ky" },
206  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TAJIKI,               "tg" },
207  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TURKMEN,              "tk" },
208  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MONGOLIAN,            "mo" },
209  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
210  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
211  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_PASHTO,               "ps" },
212  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KURDISH,              "ku" },
213  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KASHMIRI,             "ks" },
214  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SINDHI,               "sd" },
215  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TIBETAN,              "bo" },
216  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_NEPALI,               "ne" },
217  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SANSKRIT,             "sa" },
218  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MARATHI,              "mr" },
219  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BENGALI,              "bn" },
220  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ASSAMESE,             "as" },
221  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GUJARATI,             "gu" },
222  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_PUNJABI,              "pa" },
223  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ORIYA,                "or" },
224  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAYALAM,            "ml" },
225  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KANNADA,              "kn" },
226  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TAMIL,                "ta" },
227  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TELUGU,               "te" },
228  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SINHALESE,            "si" },
229  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BURMESE,              "my" },
230  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KHMER,                "km" },
231  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LAO,                  "lo" },
232  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_VIETNAMESE,           "vi" },
233  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_INDONESIAN,           "id" },
234  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TAGALOG,              "tl" },
235  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAY_ROMAN_SCRIPT,   "ms" },
236  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAY_ARABIC_SCRIPT,  "ms" },
237  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AMHARIC,              "am" },
238  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TIGRINYA,             "ti" },
239  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GALLA,                "om" },
240  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SOMALI,               "so" },
241  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SWAHILI,              "sw" },
242  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_RUANDA,               "rw" },
243  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_RUNDI,                "rn" },
244  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CHEWA,                "ny" },
245  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAGASY,             "mg" },
246  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ESPERANTO,            "eo" },
247  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_WELSH,                "cy" },
248  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BASQUE,               "eu" },
249  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CATALAN,              "ca" },
250  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LATIN,                "la" },
251  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_QUECHUA,              "qu" },
252  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GUARANI,              "gn" },
253  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AYMARA,               "ay" },
254  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TATAR,                "tt" },
255  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_UIGHUR,               "ug" },
256  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_DZONGKHA,             "dz" },
257  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_JAVANESE,             "jw" },
258  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SUNDANESE,            "su" },
259     
260 #if 0  /* these seem to be errors that have been dropped */
261
262  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SCOTTISH_GAELIC },
263  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_IRISH_GAELIC },
264
265 #endif
266     
267   /* The following codes are new as of 2000-03-10 */
268  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GALICIAN,             "gl" },
269  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AFRIKAANS,            "af" },
270  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BRETON,               "br" },
271  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_INUKTITUT,            "iu" },
272  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SCOTTISH_GAELIC,      "gd" },
273  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MANX_GAELIC,          "gv" },
274  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_IRISH_GAELIC,         "ga" },
275  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TONGAN,               "to" },
276  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GREEK_POLYTONIC,      "el" },
277  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GREELANDIC,           "ik" },
278  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
279
280  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_SAUDI_ARABIA,       "ar" },
281  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_IRAQ,               "ar" },
282  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_EGYPT,              "ar" },
283  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_LIBYA,              "ar" },
284  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_ALGERIA,            "ar" },
285  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_MOROCCO,            "ar" },
286  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_TUNISIA,            "ar" },
287  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_OMAN,               "ar" },
288  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_YEMEN,              "ar" },
289  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_SYRIA,              "ar" },
290  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_JORDAN,             "ar" },
291  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_LEBANON,            "ar" },
292  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_KUWAIT,             "ar" },
293  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_UAE,                "ar" },
294  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_BAHRAIN,            "ar" },
295  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_QATAR,              "ar" },
296  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BULGARIAN_BULGARIA,        "bg" },
297  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CATALAN_SPAIN,             "ca" },
298  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_TAIWAN,            "zh-tw" },
299  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_PRC,               "zh-cn" },
300  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_HONG_KONG,         "zh-hk" },
301  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_SINGAPORE,         "zh-sg" },
302
303  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_MACAU,             "zh-mo" },
304
305  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CZECH_CZECH_REPUBLIC,      "cs" },
306  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DANISH_DENMARK,            "da" },
307  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_GERMANY,            "de" },
308  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_SWITZERLAND,        "de" },
309  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_AUSTRIA,            "de" },
310  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_LUXEMBOURG,         "de" },
311  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_LIECHTENSTEI,       "de" },
312  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GREEK_GREECE,              "el" },
313  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_UNITED_STATES,     "en" },
314  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_UNITED_KINGDOM,    "en" },
315  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_AUSTRALIA,         "en" },
316  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_CANADA,            "en" },
317  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_NEW_ZEALAND,       "en" },
318  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_IRELAND,           "en" },
319  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_SOUTH_AFRICA,      "en" },
320  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_JAMAICA,           "en" },
321  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_CARIBBEAN,         "en" },
322  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_BELIZE,            "en" },
323  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_TRINIDAD,          "en" },
324  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_ZIMBABWE,          "en" },
325  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_PHILIPPINES,       "en" },
326  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
327  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_MEXICO,            "es" },
328  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
329  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_GUATEMALA,         "es" },
330  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_COSTA_RICA,        "es" },
331  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PANAMA,            "es" },
332  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
333  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_VENEZUELA,         "es" },
334  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_COLOMBIA,          "es" },
335  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PERU,              "es" },
336  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_ARGENTINA,         "es" },
337  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_ECUADOR,           "es" },
338  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_CHILE,             "es" },
339  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_URUGUAY,           "es" },
340  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PARAGUAY,          "es" },
341  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_BOLIVIA,           "es" },
342  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_EL_SALVADOR,       "es" },
343  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_HONDURAS,          "es" },
344  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_NICARAGUA,         "es" },
345  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PUERTO_RICO,       "es" },
346  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FINNISH_FINLAND,           "fi" },
347  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_FRANCE,             "fr" },
348  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_BELGIUM,            "fr" },
349  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_CANADA,             "fr" },
350  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_SWITZERLAND,        "fr" },
351  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_LUXEMBOURG,         "fr" },
352  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_MONACO,             "fr" },
353  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HEBREW_ISRAEL,             "he" },
354  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HUNGARIAN_HUNGARY,         "hu" },
355  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ICELANDIC_ICELAND,         "is" },
356  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ITALIAN_ITALY,             "it" },
357  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ITALIAN_SWITZERLAND,       "it" },
358  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_JAPANESE_JAPAN,            "ja" },
359  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
360  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KOREAN_JOHAB_KOREA,        "ko" },
361  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DUTCH_NETHERLANDS,         "nl" },
362  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DUTCH_BELGIUM,             "nl" },
363  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL,   "no" },
364  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK,  "nn" },
365  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_POLISH_POLAND,             "pl" },
366  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PORTUGUESE_BRAZIL,         "pt" },
367  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PORTUGUESE_PORTUGAL,       "pt" },
368  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
369  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ROMANIAN_ROMANIA,          "ro" },
370  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MOLDAVIAN_MOLDAVIA,        "mo" },
371  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_RUSSIAN_RUSSIA,            "ru" },
372  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_RUSSIAN_MOLDAVIA,          "ru" },
373  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CROATIAN_CROATIA,          "hr" },
374  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SERBIAN_SERBIA_LATIN,      "sr" },
375  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC,   "sr" },
376  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SLOVAK_SLOVAKIA,           "sk" },
377  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ALBANIAN_ALBANIA,          "sq" },
378  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SWEDISH_SWEDEN,            "sv" },
379  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SWEDISH_FINLAND,           "sv" },
380  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_THAI_THAILAND,             "th" },
381  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TURKISH_TURKEY,            "tr" },
382  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_URDU_PAKISTAN,             "ur" },
383  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_INDONESIAN_INDONESIA,      "id" },
384  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_UKRAINIAN_UKRAINE,         "uk" },
385  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BELARUSIAN_BELARUS,        "be" },
386  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SLOVENE_SLOVENIA,          "sl" },
387  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ESTONIAN_ESTONIA,          "et" },
388  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LATVIAN_LATVIA,            "lv" },
389  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LITHUANIAN_LITHUANIA,      "lt" },
390  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
391
392 #ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
393     /* this seems to be an error that have been dropped */
394  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MAORI_NEW_ZEALAND,         "mi" },
395 #endif
396
397  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FARSI_IRAN,                "fa" },
398  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_VIETNAMESE_VIET_NAM,       "vi" },
399  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARMENIAN_ARMENIA,          "hy" },
400  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN,    "az" },
401  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
402  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BASQUE_SPAIN,              "eu" },
403  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SORBIAN_GERMANY,           "wen" },
404  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MACEDONIAN_MACEDONIA,      "mk" },
405  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SUTU_SOUTH_AFRICA,         "st" },
406  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TSONGA_SOUTH_AFRICA,       "ts" },
407  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TSWANA_SOUTH_AFRICA,       "tn" },
408  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_VENDA_SOUTH_AFRICA,        "ven" },
409  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_XHOSA_SOUTH_AFRICA,        "xh" },
410  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ZULU_SOUTH_AFRICA,         "zu" },
411  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA,    "af" },
412  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GEORGIAN_GEORGIA,          "ka" },
413  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS,   "fo" },
414  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HINDI_INDIA,               "hi" },
415  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALTESE_MALTA,             "mt" },
416  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SAAMI_LAPONIA,             "se" },
417
418  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
419  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_IRISH_GAELIC_IRELAND,      "ga" },
420
421  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALAY_MALAYSIA,            "ms" },
422  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM,   "ms" },
423  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KAZAK_KAZAKSTAN,           "kk" },
424  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SWAHILI_KENYA,             "sw" },
425  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN,    "uz" },
426  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
427  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TATAR_TATARSTAN,           "tt" },
428  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BENGALI_INDIA,             "bn" },
429  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PUNJABI_INDIA,             "pa" },
430  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GUJARATI_INDIA,            "gu" },
431  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ORIYA_INDIA,               "or" },
432  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAMIL_INDIA,               "ta" },
433  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TELUGU_INDIA,              "te" },
434  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KANNADA_INDIA,             "kn" },
435  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALAYALAM_INDIA,           "ml" },
436  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ASSAMESE_INDIA,            "as" },
437  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MARATHI_INDIA,             "mr" },
438  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SANSKRIT_INDIA,            "sa" },
439  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KONKANI_INDIA,             "kok" },
440
441   /* new as of 2001-01-01 */
442  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_GENERAL,            "ar" },
443  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_GENERAL,           "zh" },
444  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_GENERAL,           "en" },
445  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_WEST_INDIES,        "fr" },
446  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_REUNION,            "fr" },
447  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_CONGO,              "fr" },
448
449  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_SENEGAL,            "fr" },
450  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_CAMEROON,           "fr" },
451  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_COTE_D_IVOIRE,      "fr" },
452  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_MALI,               "fr" },
453  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
454  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_URDU_INDIA,                "ur" },
455  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAJIK_TAJIKISTAN,          "tg" },
456  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_YIDDISH_GERMANY,           "yi" },
457  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN,       "ky" },
458
459  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TURKMEN_TURKMENISTAN,      "tk" },
460  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MONGOLIAN_MONGOLIA,        "mn" },
461
462   /* the following seems to be inconsistent;
463      here is the current "official" way: */
464  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIBETAN_BHUTAN,            "bo" },
465   /* and here is what is used by Passport SDK */
466  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIBETAN_CHINA,             "bo" },
467  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DZONGHKA_BHUTAN,           "dz" },
468   /* end of inconsistency */
469
470  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_WELSH_WALES,               "cy" },
471  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KHMER_CAMBODIA,            "km" },
472  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LAO_LAOS,                  "lo" },
473  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BURMESE_MYANMAR,           "my" },
474  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GALICIAN_SPAIN,            "gl" },
475  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MANIPURI_INDIA,            "mni" },
476  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SINDHI_INDIA,              "sd" },
477   /* the following one is only encountered in Microsoft RTF specification */
478  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KASHMIRI_PAKISTAN,         "ks" },
479   /* the following one is not in the Passport list, looks like an omission */
480  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KASHMIRI_INDIA,            "ks" },
481  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NEPALI_NEPAL,              "ne" },
482  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NEPALI_INDIA,              "ne" },
483  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRISIAN_NETHERLANDS,       "fy" },
484
485   /* new as of 2001-03-01 (from Office Xp) */
486  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_HONG_KONG,         "en" },
487  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_INDIA,             "en" },
488  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_MALAYSIA,          "en" },
489  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_SINGAPORE,         "en" },
490  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SYRIAC_SYRIA,              "syr" },
491  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SINHALESE_SRI_LANKA,       "si" },
492  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHEROKEE_UNITED_STATES,    "chr" },
493  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_INUKTITUT_CANADA,          "iu" },
494  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AMHARIC_ETHIOPIA,          "am" },
495 #if 0
496  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAMAZIGHT_MOROCCO },
497  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
498 #endif
499  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PASHTO_AFGHANISTAN,        "ps" },
500  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FILIPINO_PHILIPPINES,      "phi" },
501  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DHIVEHI_MALDIVES,          "div" },
502     
503  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_OROMO_ETHIOPIA,            "om" },
504  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIGRIGNA_ETHIOPIA,         "ti" },
505  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIGRIGNA_ERYTHREA,         "ti" },
506
507   /* New additions from Windows Xp/Passport SDK 2001-11-10. */
508
509   /* don't ask what this one means... It is commented out currently. */
510 #if 0
511  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GREEK_GREECE2 },
512 #endif
513
514  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_UNITED_STATES,     "es" },
515   /* The following two IDs blatantly violate MS specs by using a */
516   /* sublanguage >,.                                         */
517  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_LATIN_AMERICA,     "es" },
518  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_NORTH_AFRICA,       "fr" },
519
520  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_MOROCCO,            "fr" },
521  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_HAITI,              "fr" },
522  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BENGALI_BANGLADESH,        "bn" },
523  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN,   "ar" },
524  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
525 #if 0
526  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_EDO_NIGERIA },
527  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FULFULDE_NIGERIA },
528  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_IBIBIO_NIGERIA },
529 #endif
530  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HAUSA_NIGERIA,             "ha" },
531  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_YORUBA_NIGERIA,            "yo" },
532   /* language codes from, to, are (still) unknown. */
533  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_IGBO_NIGERIA,              "ibo" },
534  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KANURI_NIGERIA,            "kau" },
535  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GUARANI_PARAGUAY,          "gn" },
536  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HAWAIIAN_UNITED_STATES,    "haw" },
537  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LATIN,                     "la" },
538  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SOMALI_SOMALIA,            "so" },
539 #if 0
540   /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
541   /*       not written (but OTOH the peculiar writing system is worth     */
542   /*       studying).                                                     */
543  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_YI_CHINA },
544 #endif
545  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
546 };
547
548 #define NUM_FC_FT_LANGUAGE  (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
549
550 typedef struct {
551     FT_UShort   language_id;
552     char        *fromcode;
553 } FcMacRomanFake;
554
555 static const FcMacRomanFake fcMacRomanFake[] = {
556  {  TT_MS_LANGID_JAPANESE_JAPAN,        "SJIS-WIN" },
557  {  TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" },
558 };
559
560 static FcChar8 *
561 FcFontCapabilities(FT_Face face);
562
563 #define NUM_FC_MAC_ROMAN_FAKE   (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
564
565 #if HAVE_ICONV && HAVE_ICONV_H
566 #define USE_ICONV 1
567 #include <iconv.h>
568 #endif
569
570 static FcChar8 *
571 FcSfntNameTranscode (FT_SfntName *sname)
572 {
573     int     i;
574     char    *fromcode;
575 #if USE_ICONV
576     iconv_t cd;
577 #endif
578     FcChar8 *utf8;
579
580     for (i = 0; i < NUM_FC_FT_ENCODING; i++)
581         if (fcFtEncoding[i].platform_id == sname->platform_id &&
582             (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
583              fcFtEncoding[i].encoding_id == sname->encoding_id))
584             break;
585     if (i == NUM_FC_FT_ENCODING)
586         return 0;
587     fromcode = fcFtEncoding[i].fromcode;
588
589     /*
590      * "real" Mac language IDs are all less than 150.
591      * Names using one of the MS language IDs are assumed
592      * to use an associated encoding (Yes, this is a kludge)
593      */
594     if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN) &&
595         sname->language_id >= 0x100)
596     {
597         int     f;
598
599         fromcode = 0;
600         for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
601             if (fcMacRomanFake[f].language_id == sname->language_id)
602             {
603                 fromcode = fcMacRomanFake[f].fromcode;
604                 break;
605             }
606         if (!fromcode)
607             return 0;
608     }
609     if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
610     {
611         FcChar8     *src = sname->string;
612         int         src_len = sname->string_len;
613         int         len;
614         int         wchar;
615         int         ilen, olen;
616         FcChar8     *u8;
617         FcChar32    ucs4;
618         
619         /*
620          * Convert Utf16 to Utf8
621          */
622
623         if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
624             return 0;
625
626         /*
627          * Allocate plenty of space.  Freed below
628          */
629         utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
630         if (!utf8)
631             return 0;
632
633         u8 = utf8;
634
635         while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
636         {
637             src_len -= ilen;
638             src += ilen;
639             olen = FcUcs4ToUtf8 (ucs4, u8);
640             u8 += olen;
641         }
642         *u8 = '\0';
643         goto done;
644     }
645     if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
646     {
647         FcChar8     *src = sname->string;
648         int         src_len = sname->string_len;
649         int         olen;
650         FcChar8     *u8;
651         FcChar32    ucs4;
652         
653         /*
654          * Convert Latin1 to Utf8. Freed below
655          */
656         utf8 = malloc (src_len * 2 + 1);
657         if (!utf8)
658             return 0;
659
660         u8 = utf8;
661         while (src_len > 0)
662         {
663             ucs4 = *src++;
664             src_len--;
665             olen = FcUcs4ToUtf8 (ucs4, u8);
666             u8 += olen;
667         }
668         *u8 = '\0';
669         goto done;
670     }
671     if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
672     {
673         FcChar8         *u8;
674         const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
675         FcChar8         *src = (FcChar8 *) sname->string;
676         int             src_len = sname->string_len;
677         
678         /*
679          * Convert AppleRoman to Utf8
680          */
681         if (!map)
682             return 0;
683
684         utf8 = malloc (sname->string_len * 3 + 1);
685         if (!utf8)
686             return 0;
687
688         u8 = utf8;
689         while (src_len > 0)
690         {
691             FcChar32    ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
692             int         olen = FcUcs4ToUtf8 (ucs4, u8);
693             src_len--;
694             u8 += olen;
695         }
696         *u8 = '\0';
697         goto done;
698     }
699 #if USE_ICONV
700     cd = iconv_open ("UTF-8", fromcode);
701     if (cd && cd != (iconv_t) (-1))
702     {
703         size_t      in_bytes_left = sname->string_len;
704         size_t      out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
705         char        *inbuf, *outbuf;
706         
707         utf8 = malloc (out_bytes_left + 1);
708         if (!utf8)
709         {
710             iconv_close (cd);
711             return 0;
712         }
713         
714         outbuf = (char *) utf8;
715         inbuf = (char *) sname->string;
716         
717         while (in_bytes_left)
718         {
719             size_t      did = iconv (cd, 
720                                  &inbuf, &in_bytes_left,
721                                  &outbuf, &out_bytes_left);
722             if (did == (size_t) (-1))
723             {
724                 iconv_close (cd);
725                 free (utf8);
726                 return 0;
727             }
728         }
729         iconv_close (cd);
730         *outbuf = '\0';
731         goto done;
732     }
733 #endif
734     return 0;
735 done:
736     if (FcStrCmpIgnoreBlanksAndCase (utf8, "") == 0)
737     {
738         free (utf8);
739         return 0;
740     }
741     return utf8;
742 }
743
744 static FcChar8 *
745 FcSfntNameLanguage (FT_SfntName *sname)
746 {
747     int i;
748     for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
749         if (fcFtLanguage[i].platform_id == sname->platform_id &&
750             (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
751              fcFtLanguage[i].language_id == sname->language_id))
752             return fcFtLanguage[i].lang;
753     return 0;
754 }
755
756 /* Order is significant.  For example, some B&H fonts are hinted by
757    URW++, and both strings appear in the notice. */
758
759 static const struct {
760     const FT_String *notice;
761     const FcChar8   *foundry;
762 } FcNoticeFoundries[] = {
763     { (const FT_String *) "Bigelow",    (const FcChar8 *) "b&h" },
764     { (const FT_String *) "Adobe",      (const FcChar8 *) "adobe" },
765     { (const FT_String *) "Bitstream",  (const FcChar8 *) "bitstream" },
766     { (const FT_String *) "Monotype",   (const FcChar8 *) "monotype" },
767     { (const FT_String *) "Linotype",   (const FcChar8 *) "linotype" },
768     { (const FT_String *) "LINOTYPE-HELL",
769                                         (const FcChar8 *) "linotype" },
770     { (const FT_String *) "IBM",        (const FcChar8 *) "ibm" },
771     { (const FT_String *) "URW",        (const FcChar8 *) "urw" },
772     { (const FT_String *) "International Typeface Corporation", 
773                                         (const FcChar8 *) "itc" },
774     { (const FT_String *) "Tiro Typeworks",
775                                         (const FcChar8 *) "tiro" },
776     { (const FT_String *) "XFree86",    (const FcChar8 *) "xfree86" },
777     { (const FT_String *) "Microsoft",  (const FcChar8 *) "microsoft" },
778     { (const FT_String *) "Omega",      (const FcChar8 *) "omega" },
779     { (const FT_String *) "Font21",     (const FcChar8 *) "hwan" },
780     { (const FT_String *) "HanYang System",
781                                         (const FcChar8 *) "hanyang" }
782 };
783
784 #define NUM_NOTICE_FOUNDRIES    (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
785
786 static const FcChar8 *
787 FcNoticeFoundry(const FT_String *notice)
788 {
789     int i;
790
791     if (notice)
792         for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
793             if (strstr ((const char *) notice, (const char *) FcNoticeFoundries[i].notice))
794                 return FcNoticeFoundries[i].foundry;
795     return 0;
796 }
797
798 static FcBool
799 FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
800 {
801     /* vendor is not necessarily NUL-terminated. */
802     int i, len;
803     
804     len = strlen(vendor_string);
805     if (memcmp(vendor, vendor_string, len) != 0)
806         return FcFalse;
807     for (i = len; i < 4; i++)
808         if (vendor[i] != ' ' && vendor[i] != '\0')
809             return FcFalse;
810     return FcTrue;
811 }
812
813 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
814
815 /* It should not contain useless entries (such as UNKN) nor duplicate
816    entries for padding both with spaces and NULs. */
817
818 static const struct {
819     const FT_Char   *vendor;
820     const FcChar8   *foundry;
821 } FcVendorFoundries[] = {
822     { (const FT_Char *) "ADBE", (const FcChar8 *) "adobe"},
823     { (const FT_Char *) "AGFA", (const FcChar8 *) "agfa"},
824     { (const FT_Char *) "ALTS", (const FcChar8 *) "altsys"},
825     { (const FT_Char *) "APPL", (const FcChar8 *) "apple"},
826     { (const FT_Char *) "ARPH", (const FcChar8 *) "arphic"},
827     { (const FT_Char *) "ATEC", (const FcChar8 *) "alltype"},
828     { (const FT_Char *) "B&H",  (const FcChar8 *) "b&h"},
829     { (const FT_Char *) "BITS", (const FcChar8 *) "bitstream"},
830     { (const FT_Char *) "CANO", (const FcChar8 *) "cannon"},
831     { (const FT_Char *) "DYNA", (const FcChar8 *) "dynalab"},
832     { (const FT_Char *) "EPSN", (const FcChar8 *) "epson"},
833     { (const FT_Char *) "FJ",   (const FcChar8 *) "fujitsu"},
834     { (const FT_Char *) "IBM",  (const FcChar8 *) "ibm"},
835     { (const FT_Char *) "ITC",  (const FcChar8 *) "itc"},
836     { (const FT_Char *) "IMPR", (const FcChar8 *) "impress"},
837     { (const FT_Char *) "LARA", (const FcChar8 *) "larabiefonts"},
838     { (const FT_Char *) "LEAF", (const FcChar8 *) "interleaf"},
839     { (const FT_Char *) "LETR", (const FcChar8 *) "letraset"},
840     { (const FT_Char *) "LINO", (const FcChar8 *) "linotype"},
841     { (const FT_Char *) "MACR", (const FcChar8 *) "macromedia"},
842     { (const FT_Char *) "MONO", (const FcChar8 *) "monotype"},
843     { (const FT_Char *) "MS",   (const FcChar8 *) "microsoft"},
844     { (const FT_Char *) "MT",   (const FcChar8 *) "monotype"},
845     { (const FT_Char *) "NEC",  (const FcChar8 *) "nec"},
846     { (const FT_Char *) "PARA", (const FcChar8 *) "paratype"},
847     { (const FT_Char *) "QMSI", (const FcChar8 *) "qms"},
848     { (const FT_Char *) "RICO", (const FcChar8 *) "ricoh"},
849     { (const FT_Char *) "URW",  (const FcChar8 *) "urw"},
850     { (const FT_Char *) "Y&Y",  (const FcChar8 *) "y&y"}
851 };
852
853 #define NUM_VENDOR_FOUNDRIES    (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
854
855 static const FcChar8 *
856 FcVendorFoundry(const FT_Char vendor[4])
857 {
858     int i;
859     
860     if (vendor)
861         for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
862             if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
863                 return FcVendorFoundries[i].foundry;
864     return 0;
865 }
866
867 typedef struct _FcStringConst {
868     const FcChar8   *name;
869     int             value;
870 } FcStringConst;
871
872 static int
873 FcStringIsConst (const FcChar8          *string,
874                  const FcStringConst    *c,
875                  int                    nc)
876 {
877     int i;
878
879     for (i = 0; i < nc; i++)
880         if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
881             return c[i].value;
882     return -1;
883 }
884
885 static int
886 FcStringContainsConst (const FcChar8        *string,
887                        const FcStringConst  *c,
888                        int                  nc)
889 {
890     int i;
891
892     for (i = 0; i < nc; i++)
893         if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
894             return c[i].value;
895     return -1;
896 }
897
898 static const FcStringConst  weightConsts[] = {
899     { "thin",           FC_WEIGHT_THIN },
900     { "extralight",     FC_WEIGHT_EXTRALIGHT },
901     { "ultralight",     FC_WEIGHT_ULTRALIGHT },
902     { "light",          FC_WEIGHT_LIGHT },
903     { "book",           FC_WEIGHT_BOOK },
904     { "regular",        FC_WEIGHT_REGULAR },
905     { "normal",         FC_WEIGHT_NORMAL },
906     { "medium",         FC_WEIGHT_MEDIUM },
907     { "demibold",       FC_WEIGHT_DEMIBOLD },
908     { "demi",           FC_WEIGHT_DEMIBOLD },
909     { "semibold",       FC_WEIGHT_SEMIBOLD },
910     { "bold",           FC_WEIGHT_BOLD },
911     { "extrabold",      FC_WEIGHT_EXTRABOLD },
912     { "ultrabold",      FC_WEIGHT_ULTRABOLD },
913     { "black",          FC_WEIGHT_BLACK },
914     { "heavy",          FC_WEIGHT_HEAVY },
915 };
916
917 #define NUM_WEIGHT_CONSTS  (sizeof (weightConsts) / sizeof (weightConsts[0]))
918
919 #define FcIsWeight(s)       FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
920 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
921
922 static const FcStringConst  widthConsts[] = {
923     { "ultracondensed", FC_WIDTH_ULTRACONDENSED },
924     { "extracondensed", FC_WIDTH_EXTRACONDENSED },
925     { "semicondensed",  FC_WIDTH_SEMICONDENSED },
926     { "condensed",      FC_WIDTH_CONDENSED },   /* must be after *condensed */
927     { "normal",         FC_WIDTH_NORMAL },
928     { "semiexpanded",   FC_WIDTH_SEMIEXPANDED },
929     { "extraexpanded",  FC_WIDTH_EXTRAEXPANDED },
930     { "ultraexpanded",  FC_WIDTH_ULTRAEXPANDED },
931     { "expanded",       FC_WIDTH_EXPANDED },    /* must be after *expanded */
932 };
933
934 #define NUM_WIDTH_CONSTS    (sizeof (widthConsts) / sizeof (widthConsts[0]))
935
936 #define FcIsWidth(s)        FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
937 #define FcContainsWidth(s)  FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
938
939 static const FcStringConst  slantConsts[] = {
940     { "italic",         FC_SLANT_ITALIC },
941     { "oblique",        FC_SLANT_OBLIQUE },
942 };
943
944 #define NUM_SLANT_CONSTS    (sizeof (slantConsts) / sizeof (slantConsts[0]))
945
946 #define FcIsSlant(s)        FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
947 #define FcContainsSlant(s)  FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
948
949 static double
950 FcGetPixelSize (FT_Face face, int i)
951 {
952 #if HAVE_FT_GET_BDF_PROPERTY
953     if (face->num_fixed_sizes == 1)
954     {
955         BDF_PropertyRec prop;
956         int             rc;
957
958         rc = MY_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
959         if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
960             return (double) prop.u.integer;
961     }
962 #endif
963 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
964     return (double) face->available_sizes[i].y_ppem / 64.0;
965 #else
966     return (double) face->available_sizes[i].height;
967 #endif
968 }
969
970 static FcBool
971 FcStringInPatternElement (FcPattern *pat, char *elt, FcChar8 *string)
972 {
973     int     e;
974     FcChar8 *old;
975     for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
976         if (!FcStrCmpIgnoreBlanksAndCase (old, string))
977         {
978             return FcTrue;
979             break;
980         }
981     return FcFalse;
982 }
983
984 FcPattern *
985 FcFreeTypeQuery (const FcChar8  *file,
986                  int            id,
987                  FcBlanks       *blanks,
988                  int            *count)
989 {
990     FT_Face         face;
991     FcPattern       *pat;
992     int             slant = -1;
993     int             weight = -1;
994     int             width = -1;
995     int             i;
996     FcCharSet       *cs;
997     FcLangSet       *ls;
998     FT_Library      ftLibrary;
999 #if 0
1000     FcChar8         *family = 0;
1001 #endif
1002     FcChar8         *complex;
1003     const FcChar8   *foundry = 0;
1004     int             spacing;
1005     TT_OS2          *os2;
1006 #if HAVE_FT_GET_PS_FONT_INFO
1007     PS_FontInfoRec  psfontinfo;
1008 #endif
1009 #if HAVE_FT_GET_BDF_PROPERTY
1010     BDF_PropertyRec prop;
1011 #endif
1012     TT_Header       *head;
1013     const FcChar8   *exclusiveLang = 0;
1014     FT_SfntName     sname;
1015     FT_UInt         snamei, snamec;
1016     
1017     int             nfamily = 0;
1018     int             nfamily_lang = 0;
1019     int             nstyle = 0;
1020     int             nstyle_lang = 0;
1021     int             nfullname = 0;
1022     int             nfullname_lang = 0;
1023
1024     FcChar8         *style = 0;
1025     int             st;
1026     
1027     if (FT_Init_FreeType (&ftLibrary))
1028         return 0;
1029     
1030     if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1031         goto bail;
1032
1033     *count = face->num_faces;
1034
1035     pat = FcPatternCreate ();
1036     if (!pat)
1037         goto bail0;
1038
1039     if (!FcPatternAddBool (pat, FC_OUTLINE,
1040                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1041         goto bail1;
1042
1043     if (!FcPatternAddBool (pat, FC_SCALABLE,
1044                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1045         goto bail1;
1046
1047
1048     /*
1049      * Get the OS/2 table
1050      */
1051     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1052
1053     /*
1054      * Look first in the OS/2 table for the foundry, if
1055      * not found here, the various notices will be searched for
1056      * that information, either from the sfnt name tables or
1057      * the Postscript FontInfo dictionary.  Finally, the
1058      * BDF properties will queried.
1059      */
1060     
1061     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1062         foundry = FcVendorFoundry(os2->achVendID);
1063
1064     if (FcDebug () & FC_DBG_SCANV)
1065         printf ("\n");
1066     /*
1067      * Grub through the name table looking for family
1068      * and style names.  FreeType makes quite a hash
1069      * of them
1070      */
1071     snamec = FT_Get_Sfnt_Name_Count (face);
1072     for (snamei = 0; snamei < snamec; snamei++)
1073     {
1074         FcChar8         *utf8;
1075         FcChar8         *lang;
1076         char            *elt = 0, *eltlang = 0;
1077         int             *np = 0, *nlangp = 0;
1078
1079         if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1080             continue;
1081         
1082         utf8 = FcSfntNameTranscode (&sname);
1083         lang = FcSfntNameLanguage (&sname);
1084
1085         if (!utf8)
1086             continue;
1087         
1088         switch (sname.name_id) {
1089         case TT_NAME_ID_FONT_FAMILY:
1090 #if 0       
1091         case TT_NAME_ID_PS_NAME:
1092         case TT_NAME_ID_UNIQUE_ID:
1093 #endif
1094             if (FcDebug () & FC_DBG_SCANV)
1095                 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1096                     sname.name_id, sname.platform_id,
1097                     sname.encoding_id, sname.language_id,
1098                     utf8);
1099     
1100             elt = FC_FAMILY;
1101             eltlang = FC_FAMILYLANG;
1102             np = &nfamily;
1103             nlangp = &nfamily_lang;
1104             break;
1105         case TT_NAME_ID_FULL_NAME:
1106         case TT_NAME_ID_MAC_FULL_NAME:
1107             if (FcDebug () & FC_DBG_SCANV)
1108                 printf ("found full   (n %2d p %d e %d l 0x%04x) %s\n",
1109                     sname.name_id, sname.platform_id,
1110                     sname.encoding_id, sname.language_id,
1111                     utf8);
1112     
1113             elt = FC_FULLNAME;
1114             eltlang = FC_FULLNAMELANG;
1115             np = &nfullname;
1116             nlangp = &nfullname_lang;
1117             break;
1118         case TT_NAME_ID_FONT_SUBFAMILY:
1119             if (FcDebug () & FC_DBG_SCANV)
1120                 printf ("found style  (n %2d p %d e %d l 0x%04x) %s\n",
1121                     sname.name_id, sname.platform_id,
1122                     sname.encoding_id, sname.language_id,
1123                     utf8);
1124     
1125             elt = FC_STYLE;
1126             eltlang = FC_STYLELANG;
1127             np = &nstyle;
1128             nlangp = &nstyle_lang;
1129             break;
1130         case TT_NAME_ID_TRADEMARK:
1131         case TT_NAME_ID_MANUFACTURER:
1132             /* If the foundry wasn't found in the OS/2 table, look here */
1133             if(!foundry)
1134                 foundry = FcNoticeFoundry((FT_String *) utf8);
1135             break;
1136         }
1137         if (elt)
1138         {
1139             if (FcStringInPatternElement (pat, elt, utf8))
1140             {
1141                 free (utf8);
1142                 continue;
1143             }
1144
1145             /* add new element */
1146             if (!FcPatternAddString (pat, elt, utf8))
1147             {
1148                 free (utf8);
1149                 goto bail1;
1150             }
1151             free (utf8);
1152             if (lang)
1153             {
1154                 /* pad lang list with 'xx' to line up with elt */
1155                 while (*nlangp < *np)
1156                 {
1157                     if (!FcPatternAddString (pat, eltlang, "xx"))
1158                         goto bail1;
1159                     ++*nlangp;
1160                 }
1161                 if (!FcPatternAddString (pat, eltlang, lang))
1162                     goto bail1;
1163                 ++*nlangp;
1164             }
1165             ++*np;
1166         }
1167         else
1168             free (utf8);
1169     }
1170     
1171     if (!nfamily && face->family_name && 
1172         FcStrCmpIgnoreBlanksAndCase (face->family_name, "") != 0)
1173     {
1174         if (FcDebug () & FC_DBG_SCANV)
1175             printf ("using FreeType family \"%s\"\n", face->family_name);
1176         if (!FcPatternAddString (pat, FC_FAMILY, face->family_name))
1177             goto bail1;
1178         ++nfamily;
1179     }
1180     
1181     if (!nstyle && face->style_name &&
1182         FcStrCmpIgnoreBlanksAndCase (face->style_name, "") != 0)
1183     {
1184         if (FcDebug () & FC_DBG_SCANV)
1185             printf ("using FreeType style \"%s\"\n", face->style_name);
1186         if (!FcPatternAddString (pat, FC_STYLE, face->style_name))
1187             goto bail1;
1188         ++nstyle;
1189     }
1190     
1191     if (!nfamily)
1192     {
1193         FcChar8 *start, *end;
1194         FcChar8 *family;
1195         
1196         start = (FcChar8 *) strrchr ((char *) file, '/');
1197         if (start)
1198             start++;
1199         else
1200             start = (FcChar8 *) file;
1201         end = (FcChar8 *) strrchr ((char *) start, '.');
1202         if (!end)
1203             end = start + strlen ((char *) start);
1204         /* freed below */
1205         family = malloc (end - start + 1);
1206         strncpy ((char *) family, (char *) start, end - start);
1207         family[end - start] = '\0';
1208         if (FcDebug () & FC_DBG_SCANV)
1209             printf ("using filename for family %s\n", family);
1210         if (!FcPatternAddString (pat, FC_FAMILY, family))
1211         {
1212             free (family);
1213             goto bail1;
1214         }
1215         free (family);
1216         ++nfamily;
1217     }
1218
1219     /*
1220      * Walk through FC_FULLNAME entries eliding those in FC_FAMILY
1221      * or which are simply a FC_FAMILY and FC_STYLE glued together
1222      */
1223     {
1224         int     fn, fa, st;
1225         FcChar8 *full;
1226         FcChar8 *fam;
1227         FcChar8 *style;
1228
1229         for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
1230         {
1231             FcBool  remove = FcFalse;
1232             /*
1233              * Check each family
1234              */
1235             for (fa = 0; !remove && 
1236                  FcPatternGetString (pat, FC_FAMILY, 
1237                                      fa, &fam) == FcResultMatch;
1238                  fa++)
1239             {
1240                 /*
1241                  * for exact match
1242                  */
1243                 if (!FcStrCmpIgnoreBlanksAndCase (full, fam))
1244                 {
1245                     remove = FcTrue;
1246                     break;
1247                 }
1248                 /*
1249                  * If the family is in the full name, check the
1250                  * combination of this family with every style
1251                  */
1252                 if (!FcStrContainsIgnoreBlanksAndCase (full, fam))
1253                     continue;
1254                 for (st = 0; !remove && 
1255                      FcPatternGetString (pat, FC_STYLE, 
1256                                          st, &style) == FcResultMatch;
1257                      st++)
1258                 {
1259                     FcChar8     *both = FcStrPlus (fam, style);
1260
1261                     if (both)
1262                     {
1263                         if (FcStrCmpIgnoreBlanksAndCase (full, both) == 0)
1264                             remove = FcTrue;
1265                         free (both);
1266                     }
1267                 }
1268             }
1269             if (remove)
1270             {
1271                 FcPatternRemove (pat, FC_FULLNAME, fn);
1272                 FcPatternRemove (pat, FC_FULLNAMELANG, fn);
1273                 fn--;
1274                 nfullname--;
1275                 nfullname_lang--;
1276             }
1277         }
1278         if (FcDebug () & FC_DBG_SCANV)
1279             for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
1280                 printf ("Saving unique fullname %s\n", full);
1281     }
1282
1283     if (!FcPatternAddString (pat, FC_FILE, file))
1284         goto bail1;
1285
1286     if (!FcPatternAddInteger (pat, FC_INDEX, id))
1287         goto bail1;
1288
1289 #if 0
1290     /*
1291      * don't even try this -- CJK 'monospace' fonts are really
1292      * dual width, and most other fonts don't bother to set
1293      * the attribute.  Sigh.
1294      */
1295     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1296         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1297             goto bail1;
1298 #endif
1299
1300     /*
1301      * Find the font revision (if available)
1302      */
1303     head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1304     if (head)
1305     {
1306         if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1307             goto bail1;
1308     }
1309     else
1310     {
1311         if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1312             goto bail1;
1313     }
1314
1315     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1316     {
1317         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1318         {
1319             FT_ULong    bits;
1320             int         bit;
1321             if (FcCodePageRange[i].bit < 32)
1322             {
1323                 bits = os2->ulCodePageRange1;
1324                 bit = FcCodePageRange[i].bit;
1325             }
1326             else
1327             {
1328                 bits = os2->ulCodePageRange2;
1329                 bit = FcCodePageRange[i].bit - 32;
1330             }
1331             if (bits & (1 << bit))
1332             {
1333                 /* 
1334                  * If the font advertises support for multiple
1335                  * "exclusive" languages, then include support
1336                  * for any language found to have coverage
1337                  */
1338                 if (exclusiveLang)
1339                 {
1340                     exclusiveLang = 0;
1341                     break;
1342                 }
1343                 exclusiveLang = FcCodePageRange[i].lang;
1344             }
1345         }
1346     }
1347
1348     if (os2 && os2->version != 0xffff)
1349     {
1350         if (os2->usWeightClass == 0)
1351             ;
1352         else if (os2->usWeightClass < 150)
1353             weight = FC_WEIGHT_THIN;
1354         else if (os2->usWeightClass < 250)
1355             weight = FC_WEIGHT_EXTRALIGHT;
1356         else if (os2->usWeightClass < 350)
1357             weight = FC_WEIGHT_LIGHT;
1358         else if (os2->usWeightClass < 450)
1359             weight = FC_WEIGHT_REGULAR;
1360         else if (os2->usWeightClass < 550)
1361             weight = FC_WEIGHT_MEDIUM;
1362         else if (os2->usWeightClass < 650)
1363             weight = FC_WEIGHT_SEMIBOLD;
1364         else if (os2->usWeightClass < 750)
1365             weight = FC_WEIGHT_BOLD;
1366         else if (os2->usWeightClass < 850)
1367             weight = FC_WEIGHT_EXTRABOLD;
1368         else if (os2->usWeightClass < 950)
1369             weight = FC_WEIGHT_BLACK;
1370
1371         switch (os2->usWidthClass) {
1372         case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1373         case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1374         case 3: width = FC_WIDTH_CONDENSED; break;
1375         case 4: width = FC_WIDTH_SEMICONDENSED; break;
1376         case 5: width = FC_WIDTH_NORMAL; break;
1377         case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1378         case 7: width = FC_WIDTH_EXPANDED; break;
1379         case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1380         case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1381         }
1382     }
1383     if (os2 && (complex = FcFontCapabilities(face)))
1384     {
1385         if (!FcPatternAddString (pat, FC_CAPABILITY, complex))
1386         {
1387             free (complex);
1388             goto bail1;
1389         }
1390         free (complex);
1391     }
1392
1393     /*
1394      * Type 1: Check for FontInfo dictionary information
1395      * Code from g2@magestudios.net (Gerard Escalante)
1396      */
1397     
1398 #if HAVE_FT_GET_PS_FONT_INFO
1399     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1400     {
1401         if (weight == -1 && psfontinfo.weight)
1402         {
1403             weight = FcIsWeight (psfontinfo.weight);
1404             if (FcDebug() & FC_DBG_SCANV)
1405                 printf ("\tType1 weight %s maps to %d\n",
1406                         psfontinfo.weight, weight);
1407         }
1408      
1409 #if 0
1410         /* 
1411          * Don't bother with italic_angle; FreeType already extracts that
1412          * information for us and sticks it into style_flags
1413          */
1414         if (psfontinfo.italic_angle)
1415             slant = FC_SLANT_ITALIC; 
1416         else
1417             slant = FC_SLANT_ROMAN; 
1418 #endif
1419
1420         if(!foundry)
1421             foundry = FcNoticeFoundry(psfontinfo.notice);
1422     }
1423 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1424     
1425 #if HAVE_FT_GET_BDF_PROPERTY
1426     /*
1427      * Finally, look for a FOUNDRY BDF property if no other
1428      * mechanism has managed to locate a foundry
1429      */
1430
1431     if (!foundry)
1432     {
1433         int             rc;
1434         BDF_PropertyRec prop;
1435         rc = MY_Get_BDF_Property(face, "FOUNDRY", &prop);
1436         if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1437             foundry = prop.u.atom;
1438     }
1439
1440     if (width == -1)
1441     {
1442         if (MY_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1443             (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1444              prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1445         {
1446             FT_Int32    value;
1447             
1448             if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1449                 value = prop.u.integer;
1450             else
1451                 value = (FT_Int32) prop.u.cardinal;
1452             switch ((value + 5) / 10) {
1453             case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1454             case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1455             case 3: width = FC_WIDTH_CONDENSED; break;
1456             case 4: width = FC_WIDTH_SEMICONDENSED; break;
1457             case 5: width = FC_WIDTH_NORMAL; break;
1458             case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1459             case 7: width = FC_WIDTH_EXPANDED; break;
1460             case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1461             case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1462             }
1463         }
1464         if (width == -1 &&
1465             MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1466             prop.type == BDF_PROPERTY_TYPE_ATOM)
1467         {
1468             width = FcIsWidth (prop.u.atom);
1469             if (FcDebug () & FC_DBG_SCANV)
1470                 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1471         }
1472     }
1473 #endif
1474
1475     /*
1476      * Look for weight, width and slant names in the style value
1477      */
1478     for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1479     {
1480         if (weight == -1)
1481         {
1482             weight = FcContainsWeight (style);
1483             if (FcDebug() & FC_DBG_SCANV)
1484                 printf ("\tStyle %s maps to weight %d\n", style, weight);
1485         }
1486         if (width == -1)
1487         {
1488             width = FcContainsWidth (style);
1489             if (FcDebug() & FC_DBG_SCANV)
1490                 printf ("\tStyle %s maps to width %d\n", style, width);
1491         }
1492         if (slant == -1)
1493         {
1494             slant = FcContainsSlant (style);
1495             if (FcDebug() & FC_DBG_SCANV)
1496                 printf ("\tStyle %s maps to slant %d\n", style, slant);
1497         }
1498     }
1499     /*
1500      * Pull default values from the FreeType flags if more
1501      * specific values not found above
1502      */
1503     if (slant == -1)
1504     {
1505         slant = FC_SLANT_ROMAN;
1506         if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1507             slant = FC_SLANT_ITALIC;
1508     }
1509
1510     if (weight == -1)
1511     {
1512         weight = FC_WEIGHT_MEDIUM;
1513         if (face->style_flags & FT_STYLE_FLAG_BOLD)
1514             weight = FC_WEIGHT_BOLD;
1515     }
1516
1517     if (width == -1)
1518         width = FC_WIDTH_NORMAL;
1519
1520     if (foundry == 0)
1521         foundry = "unknown";
1522
1523     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1524         goto bail1;
1525
1526     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1527         goto bail1;
1528
1529     if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1530         goto bail1;
1531
1532     if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1533         goto bail1;
1534
1535     /*
1536      * Compute the unicode coverage for the font
1537      */
1538     cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1539     if (!cs)
1540         goto bail1;
1541
1542 #if HAVE_FT_GET_BDF_PROPERTY
1543     /* For PCF fonts, override the computed spacing with the one from
1544        the property */
1545     if(MY_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1546        prop.type == BDF_PROPERTY_TYPE_ATOM) {
1547         if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1548             spacing = FC_CHARCELL;
1549         else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1550             spacing = FC_MONO;
1551         else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1552             spacing = FC_PROPORTIONAL;
1553     }
1554 #endif
1555
1556     /*
1557      * Skip over PCF fonts that have no encoded characters; they're
1558      * usually just Unicode fonts transcoded to some legacy encoding
1559      */
1560     if (FcCharSetCount (cs) == 0)
1561     {
1562         if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
1563             goto bail2;
1564     }
1565
1566     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1567         goto bail2;
1568
1569     ls = FcFreeTypeLangSet (cs, exclusiveLang);
1570     if (!ls)
1571         goto bail2;
1572
1573     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1574     {
1575         FcLangSetDestroy (ls);
1576         goto bail2;
1577     }
1578
1579     FcLangSetDestroy (ls);
1580
1581     if (spacing != FC_PROPORTIONAL)
1582         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1583             goto bail2;
1584
1585     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1586     {
1587         for (i = 0; i < face->num_fixed_sizes; i++)
1588             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1589                                      FcGetPixelSize (face, i)))
1590                 goto bail1;
1591         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1592             goto bail1;
1593 #if HAVE_FT_GET_BDF_PROPERTY
1594         if(face->num_fixed_sizes == 1) {
1595             int rc;
1596             int value;
1597             BDF_PropertyRec prop;
1598
1599             rc = MY_Get_BDF_Property(face, "POINT_SIZE", &prop);
1600             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1601                 value = prop.u.integer;
1602             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1603                 value = prop.u.cardinal;
1604             else
1605                 goto nevermind;
1606             if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1607                 goto nevermind;
1608
1609             rc = MY_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
1610             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1611                 value = prop.u.integer;
1612             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1613                 value = prop.u.cardinal;
1614             else
1615                 goto nevermind;
1616             if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1617                 goto nevermind;
1618
1619         }
1620     nevermind:
1621         ;
1622 #endif
1623     }
1624 #if HAVE_FT_GET_X11_FONT_FORMAT
1625     /*
1626      * Use the (not well documented or supported) X-specific function
1627      * from FreeType to figure out the font format
1628      */
1629     {
1630         const char *font_format = FT_Get_X11_Font_Format (face);
1631         if (font_format)
1632             FcPatternAddString (pat, FC_FONTFORMAT, font_format);
1633     }
1634 #endif
1635
1636     /*
1637      * Drop our reference to the charset
1638      */
1639     FcCharSetDestroy (cs);
1640     
1641     /*
1642      * Deallocate family/style values
1643      */
1644     
1645     FT_Done_Face (face);
1646     FT_Done_FreeType (ftLibrary);
1647     return pat;
1648
1649 bail2:
1650     FcCharSetDestroy (cs);
1651 bail1:
1652     FcPatternDestroy (pat);
1653 bail0:
1654     FT_Done_Face (face);
1655 bail:
1656     FT_Done_FreeType (ftLibrary);
1657     return 0;
1658 }
1659
1660
1661 /*
1662  * For our purposes, this approximation is sufficient
1663  */
1664 #if !HAVE_FT_GET_NEXT_CHAR
1665 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1666                                           (*(gi) = 0), 0 : \
1667                                           (*(gi) = 1), (ucs4) + 1)
1668 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1669 #endif
1670
1671 typedef struct _FcCharEnt {
1672     FcChar16        bmp;
1673     unsigned char   encode;
1674 } FcCharEnt;
1675
1676 struct _FcCharMap {
1677     const FcCharEnt *ent;
1678     int             nent;
1679 };
1680
1681 typedef struct _FcFontDecode {
1682     FT_Encoding     encoding;
1683     const FcCharMap *map;
1684     FcChar32        max;
1685 } FcFontDecode;
1686
1687 static const FcCharEnt AppleRomanEnt[] = {
1688     { 0x0020, 0x20 }, /* SPACE */
1689     { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1690     { 0x0022, 0x22 }, /* QUOTATION MARK */
1691     { 0x0023, 0x23 }, /* NUMBER SIGN */
1692     { 0x0024, 0x24 }, /* DOLLAR SIGN */
1693     { 0x0025, 0x25 }, /* PERCENT SIGN */
1694     { 0x0026, 0x26 }, /* AMPERSAND */
1695     { 0x0027, 0x27 }, /* APOSTROPHE */
1696     { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1697     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1698     { 0x002A, 0x2A }, /* ASTERISK */
1699     { 0x002B, 0x2B }, /* PLUS SIGN */
1700     { 0x002C, 0x2C }, /* COMMA */
1701     { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1702     { 0x002E, 0x2E }, /* FULL STOP */
1703     { 0x002F, 0x2F }, /* SOLIDUS */
1704     { 0x0030, 0x30 }, /* DIGIT ZERO */
1705     { 0x0031, 0x31 }, /* DIGIT ONE */
1706     { 0x0032, 0x32 }, /* DIGIT TWO */
1707     { 0x0033, 0x33 }, /* DIGIT THREE */
1708     { 0x0034, 0x34 }, /* DIGIT FOUR */
1709     { 0x0035, 0x35 }, /* DIGIT FIVE */
1710     { 0x0036, 0x36 }, /* DIGIT SIX */
1711     { 0x0037, 0x37 }, /* DIGIT SEVEN */
1712     { 0x0038, 0x38 }, /* DIGIT EIGHT */
1713     { 0x0039, 0x39 }, /* DIGIT NINE */
1714     { 0x003A, 0x3A }, /* COLON */
1715     { 0x003B, 0x3B }, /* SEMICOLON */
1716     { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1717     { 0x003D, 0x3D }, /* EQUALS SIGN */
1718     { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1719     { 0x003F, 0x3F }, /* QUESTION MARK */
1720     { 0x0040, 0x40 }, /* COMMERCIAL AT */
1721     { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1722     { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1723     { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1724     { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1725     { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1726     { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1727     { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1728     { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1729     { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1730     { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1731     { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1732     { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1733     { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1734     { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1735     { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1736     { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1737     { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1738     { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1739     { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1740     { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1741     { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1742     { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1743     { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1744     { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1745     { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1746     { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1747     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1748     { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1749     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1750     { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1751     { 0x005F, 0x5F }, /* LOW LINE */
1752     { 0x0060, 0x60 }, /* GRAVE ACCENT */
1753     { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1754     { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1755     { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1756     { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1757     { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1758     { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1759     { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1760     { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1761     { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1762     { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1763     { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1764     { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1765     { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1766     { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1767     { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1768     { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1769     { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1770     { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1771     { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1772     { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1773     { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1774     { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1775     { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1776     { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1777     { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1778     { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1779     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1780     { 0x007C, 0x7C }, /* VERTICAL LINE */
1781     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1782     { 0x007E, 0x7E }, /* TILDE */
1783     { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1784     { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1785     { 0x00A2, 0xA2 }, /* CENT SIGN */
1786     { 0x00A3, 0xA3 }, /* POUND SIGN */
1787     { 0x00A5, 0xB4 }, /* YEN SIGN */
1788     { 0x00A7, 0xA4 }, /* SECTION SIGN */
1789     { 0x00A8, 0xAC }, /* DIAERESIS */
1790     { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1791     { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1792     { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1793     { 0x00AC, 0xC2 }, /* NOT SIGN */
1794     { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1795     { 0x00AF, 0xF8 }, /* MACRON */
1796     { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1797     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1798     { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1799     { 0x00B5, 0xB5 }, /* MICRO SIGN */
1800     { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1801     { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1802     { 0x00B8, 0xFC }, /* CEDILLA */
1803     { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1804     { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1805     { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1806     { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1807     { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1808     { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1809     { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1810     { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1811     { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1812     { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1813     { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1814     { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1815     { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1816     { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1817     { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1818     { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1819     { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1820     { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1821     { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1822     { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1823     { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1824     { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1825     { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1826     { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1827     { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1828     { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1829     { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1830     { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1831     { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1832     { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1833     { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1834     { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1835     { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1836     { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1837     { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1838     { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1839     { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1840     { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1841     { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1842     { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1843     { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1844     { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1845     { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1846     { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1847     { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1848     { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1849     { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1850     { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1851     { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1852     { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1853     { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1854     { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1855     { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1856     { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1857     { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1858     { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1859     { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1860     { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1861     { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1862     { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1863     { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1864     { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1865     { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1866     { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1867     { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1868     { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1869     { 0x02C7, 0xFF }, /* CARON */
1870     { 0x02D8, 0xF9 }, /* BREVE */
1871     { 0x02D9, 0xFA }, /* DOT ABOVE */
1872     { 0x02DA, 0xFB }, /* RING ABOVE */
1873     { 0x02DB, 0xFE }, /* OGONEK */
1874     { 0x02DC, 0xF7 }, /* SMALL TILDE */
1875     { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1876     { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1877     { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1878     { 0x2013, 0xD0 }, /* EN DASH */
1879     { 0x2014, 0xD1 }, /* EM DASH */
1880     { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1881     { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1882     { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1883     { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1884     { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1885     { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1886     { 0x2020, 0xA0 }, /* DAGGER */
1887     { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
1888     { 0x2022, 0xA5 }, /* BULLET */
1889     { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
1890     { 0x2030, 0xE4 }, /* PER MILLE SIGN */
1891     { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
1892     { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
1893     { 0x2044, 0xDA }, /* FRACTION SLASH */
1894     { 0x20AC, 0xDB }, /* EURO SIGN */
1895     { 0x2122, 0xAA }, /* TRADE MARK SIGN */
1896     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
1897     { 0x2206, 0xC6 }, /* INCREMENT */
1898     { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
1899     { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
1900     { 0x221A, 0xC3 }, /* SQUARE ROOT */
1901     { 0x221E, 0xB0 }, /* INFINITY */
1902     { 0x222B, 0xBA }, /* INTEGRAL */
1903     { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
1904     { 0x2260, 0xAD }, /* NOT EQUAL TO */
1905     { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
1906     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
1907     { 0x25CA, 0xD7 }, /* LOZENGE */
1908     { 0xF8FF, 0xF0 }, /* Apple logo */
1909     { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
1910     { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
1911 };
1912
1913 static const FcCharMap AppleRoman = {
1914     AppleRomanEnt,
1915     sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
1916 };
1917
1918 static const FcCharEnt AdobeSymbolEnt[] = {
1919     { 0x0020, 0x20 }, /* SPACE  # space */
1920     { 0x0021, 0x21 }, /* EXCLAMATION MARK       # exclam */
1921     { 0x0023, 0x23 }, /* NUMBER SIGN    # numbersign */
1922     { 0x0025, 0x25 }, /* PERCENT SIGN   # percent */
1923     { 0x0026, 0x26 }, /* AMPERSAND      # ampersand */
1924     { 0x0028, 0x28 }, /* LEFT PARENTHESIS       # parenleft */
1925     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS      # parenright */
1926     { 0x002B, 0x2B }, /* PLUS SIGN      # plus */
1927     { 0x002C, 0x2C }, /* COMMA  # comma */
1928     { 0x002E, 0x2E }, /* FULL STOP      # period */
1929     { 0x002F, 0x2F }, /* SOLIDUS        # slash */
1930     { 0x0030, 0x30 }, /* DIGIT ZERO     # zero */
1931     { 0x0031, 0x31 }, /* DIGIT ONE      # one */
1932     { 0x0032, 0x32 }, /* DIGIT TWO      # two */
1933     { 0x0033, 0x33 }, /* DIGIT THREE    # three */
1934     { 0x0034, 0x34 }, /* DIGIT FOUR     # four */
1935     { 0x0035, 0x35 }, /* DIGIT FIVE     # five */
1936     { 0x0036, 0x36 }, /* DIGIT SIX      # six */
1937     { 0x0037, 0x37 }, /* DIGIT SEVEN    # seven */
1938     { 0x0038, 0x38 }, /* DIGIT EIGHT    # eight */
1939     { 0x0039, 0x39 }, /* DIGIT NINE     # nine */
1940     { 0x003A, 0x3A }, /* COLON  # colon */
1941     { 0x003B, 0x3B }, /* SEMICOLON      # semicolon */
1942     { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1943     { 0x003D, 0x3D }, /* EQUALS SIGN    # equal */
1944     { 0x003E, 0x3E }, /* GREATER-THAN SIGN      # greater */
1945     { 0x003F, 0x3F }, /* QUESTION MARK  # question */
1946     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET    # bracketleft */
1947     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET   # bracketright */
1948     { 0x005F, 0x5F }, /* LOW LINE       # underscore */
1949     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET     # braceleft */
1950     { 0x007C, 0x7C }, /* VERTICAL LINE  # bar */
1951     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET    # braceright */
1952     { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1953     { 0x00AC, 0xD8 }, /* NOT SIGN       # logicalnot */
1954     { 0x00B0, 0xB0 }, /* DEGREE SIGN    # degree */
1955     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN        # plusminus */
1956     { 0x00B5, 0x6D }, /* MICRO SIGN     # mu */
1957     { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN    # multiply */
1958     { 0x00F7, 0xB8 }, /* DIVISION SIGN  # divide */
1959     { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1960     { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA     # Alpha */
1961     { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA      # Beta */
1962     { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA     # Gamma */
1963     { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA     # Delta */
1964     { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON   # Epsilon */
1965     { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA      # Zeta */
1966     { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA       # Eta */
1967     { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA     # Theta */
1968     { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA      # Iota */
1969     { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA     # Kappa */
1970     { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA     # Lambda */
1971     { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU        # Mu */
1972     { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU        # Nu */
1973     { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI        # Xi */
1974     { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON   # Omicron */
1975     { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI        # Pi */
1976     { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO       # Rho */
1977     { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA     # Sigma */
1978     { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU       # Tau */
1979     { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON   # Upsilon */
1980     { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI       # Phi */
1981     { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI       # Chi */
1982     { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI       # Psi */
1983     { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA     # Omega */
1984     { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA       # alpha */
1985     { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA        # beta */
1986     { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA       # gamma */
1987     { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA       # delta */
1988     { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON     # epsilon */
1989     { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA        # zeta */
1990     { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1991     { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA       # theta */
1992     { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA        # iota */
1993     { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA       # kappa */
1994     { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA       # lambda */
1995     { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU  # mu */
1996     { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU  # nu */
1997     { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI  # xi */
1998     { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON     # omicron */
1999     { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI  # pi */
2000     { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
2001     { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
2002     { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA       # sigma */
2003     { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
2004     { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON     # upsilon */
2005     { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
2006     { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
2007     { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
2008     { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA       # omega */
2009     { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL     # theta1 */
2010     { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
2011     { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL       # phi1 */
2012     { 0x03D6, 0x76 }, /* GREEK PI SYMBOL        # omega1 */
2013     { 0x2022, 0xB7 }, /* BULLET # bullet */
2014     { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS    # ellipsis */
2015     { 0x2032, 0xA2 }, /* PRIME  # minute */
2016     { 0x2033, 0xB2 }, /* DOUBLE PRIME   # second */
2017     { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
2018     { 0x20AC, 0xA0 }, /* EURO SIGN      # Euro */
2019     { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
2020     { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P       # weierstrass */
2021     { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
2022     { 0x2126, 0x57 }, /* OHM SIGN       # Omega */
2023     { 0x2135, 0xC0 }, /* ALEF SYMBOL    # aleph */
2024     { 0x2190, 0xAC }, /* LEFTWARDS ARROW        # arrowleft */
2025     { 0x2191, 0xAD }, /* UPWARDS ARROW  # arrowup */
2026     { 0x2192, 0xAE }, /* RIGHTWARDS ARROW       # arrowright */
2027     { 0x2193, 0xAF }, /* DOWNWARDS ARROW        # arrowdown */
2028     { 0x2194, 0xAB }, /* LEFT RIGHT ARROW       # arrowboth */
2029     { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS  # carriagereturn */
2030     { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
2031     { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW   # arrowdblup */
2032     { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW        # arrowdblright */
2033     { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
2034     { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW        # arrowdblboth */
2035     { 0x2200, 0x22 }, /* FOR ALL        # universal */
2036     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL   # partialdiff */
2037     { 0x2203, 0x24 }, /* THERE EXISTS   # existential */
2038     { 0x2205, 0xC6 }, /* EMPTY SET      # emptyset */
2039     { 0x2206, 0x44 }, /* INCREMENT      # Delta */
2040     { 0x2207, 0xD1 }, /* NABLA  # gradient */
2041     { 0x2208, 0xCE }, /* ELEMENT OF     # element */
2042     { 0x2209, 0xCF }, /* NOT AN ELEMENT OF      # notelement */
2043     { 0x220B, 0x27 }, /* CONTAINS AS MEMBER     # suchthat */
2044     { 0x220F, 0xD5 }, /* N-ARY PRODUCT  # product */
2045     { 0x2211, 0xE5 }, /* N-ARY SUMMATION        # summation */
2046     { 0x2212, 0x2D }, /* MINUS SIGN     # minus */
2047     { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
2048     { 0x2217, 0x2A }, /* ASTERISK OPERATOR      # asteriskmath */
2049     { 0x221A, 0xD6 }, /* SQUARE ROOT    # radical */
2050     { 0x221D, 0xB5 }, /* PROPORTIONAL TO        # proportional */
2051     { 0x221E, 0xA5 }, /* INFINITY       # infinity */
2052     { 0x2220, 0xD0 }, /* ANGLE  # angle */
2053     { 0x2227, 0xD9 }, /* LOGICAL AND    # logicaland */
2054     { 0x2228, 0xDA }, /* LOGICAL OR     # logicalor */
2055     { 0x2229, 0xC7 }, /* INTERSECTION   # intersection */
2056     { 0x222A, 0xC8 }, /* UNION  # union */
2057     { 0x222B, 0xF2 }, /* INTEGRAL       # integral */
2058     { 0x2234, 0x5C }, /* THEREFORE      # therefore */
2059     { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
2060     { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
2061     { 0x2248, 0xBB }, /* ALMOST EQUAL TO        # approxequal */
2062     { 0x2260, 0xB9 }, /* NOT EQUAL TO   # notequal */
2063     { 0x2261, 0xBA }, /* IDENTICAL TO   # equivalence */
2064     { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO  # lessequal */
2065     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO       # greaterequal */
2066     { 0x2282, 0xCC }, /* SUBSET OF      # propersubset */
2067     { 0x2283, 0xC9 }, /* SUPERSET OF    # propersuperset */
2068     { 0x2284, 0xCB }, /* NOT A SUBSET OF        # notsubset */
2069     { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO  # reflexsubset */
2070     { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO        # reflexsuperset */
2071     { 0x2295, 0xC5 }, /* CIRCLED PLUS   # circleplus */
2072     { 0x2297, 0xC4 }, /* CIRCLED TIMES  # circlemultiply */
2073     { 0x22A5, 0x5E }, /* UP TACK        # perpendicular */
2074     { 0x22C5, 0xD7 }, /* DOT OPERATOR   # dotmath */
2075     { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL      # integraltp */
2076     { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL   # integralbt */
2077     { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET    # angleleft */
2078     { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET   # angleright */
2079     { 0x25CA, 0xE0 }, /* LOZENGE        # lozenge */
2080     { 0x2660, 0xAA }, /* BLACK SPADE SUIT       # spade */
2081     { 0x2663, 0xA7 }, /* BLACK CLUB SUIT        # club */
2082     { 0x2665, 0xA9 }, /* BLACK HEART SUIT       # heart */
2083     { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT     # diamond */
2084     { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF   # copyrightserif (CUS) */
2085     { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF  # registerserif (CUS) */
2086     { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF  # trademarkserif (CUS) */
2087     { 0xF8E5, 0x60 }, /* RADICAL EXTENDER       # radicalex (CUS) */
2088     { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER        # arrowvertex (CUS) */
2089     { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER      # arrowhorizex (CUS) */
2090     { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF     # registersans (CUS) */
2091     { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF      # copyrightsans (CUS) */
2092     { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF     # trademarksans (CUS) */
2093     { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2094     { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER    # parenleftex (CUS) */
2095     { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM      # parenleftbt (CUS) */
2096     { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP        # bracketlefttp (CUS) */
2097     { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER   # bracketleftex (CUS) */
2098     { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM     # bracketleftbt (CUS) */
2099     { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2100     { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2101     { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM      # braceleftbt (CUS) */
2102     { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2103     { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER      # integralex (CUS) */
2104     { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP        # parenrighttp (CUS) */
2105     { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER   # parenrightex (CUS) */
2106     { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM     # parenrightbt (CUS) */
2107     { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP       # bracketrighttp (CUS) */
2108     { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER  # bracketrightex (CUS) */
2109     { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM    # bracketrightbt (CUS) */
2110     { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP        # bracerighttp (CUS) */
2111     { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID        # bracerightmid (CUS) */
2112     { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM     # bracerightbt (CUS) */
2113 };
2114
2115 static const FcCharMap AdobeSymbol = {
2116     AdobeSymbolEnt,
2117     sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2118 };
2119     
2120 static const FcFontDecode fcFontDecoders[] = {
2121     { ft_encoding_unicode,      0,              (1 << 21) - 1 },
2122     { ft_encoding_symbol,       &AdobeSymbol,   (1 << 16) - 1 },
2123     { ft_encoding_apple_roman,  &AppleRoman,    (1 << 16) - 1 },
2124 };
2125
2126 #define NUM_DECODE  (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
2127
2128 static const FcChar32   prefer_unicode[] = {
2129     0x20ac,     /* EURO SIGN */
2130 };
2131
2132 #define NUM_PREFER_UNICODE  (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
2133
2134 FcChar32
2135 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2136 {
2137     int         low, high, mid;
2138     FcChar16    bmp;
2139
2140     low = 0;
2141     high = map->nent - 1;
2142     if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2143         return ~0;
2144     while (low <= high)
2145     {
2146         mid = (high + low) >> 1;
2147         bmp = map->ent[mid].bmp;
2148         if (ucs4 == bmp)
2149             return (FT_ULong) map->ent[mid].encode;
2150         if (ucs4 < bmp)
2151             high = mid - 1;
2152         else
2153             low = mid + 1;
2154     }
2155     return ~0;
2156 }
2157
2158 FcChar32
2159 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2160 {
2161     int     i;
2162
2163     for (i = 0; i < map->nent; i++)
2164         if (map->ent[i].encode == private)
2165             return (FcChar32) map->ent[i].bmp;
2166     return ~0;
2167 }
2168
2169 const FcCharMap *
2170 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2171 {
2172     int i;
2173
2174     for (i = 0; i < NUM_DECODE; i++)
2175         if (fcFontDecoders[i].encoding == encoding)
2176             return fcFontDecoders[i].map;
2177     return 0;
2178 }
2179
2180 #include "../fc-glyphname/fcglyphname.h"
2181
2182 static FcChar32
2183 FcHashGlyphName (const FcChar8 *name)
2184 {
2185     FcChar32    h = 0;
2186     FcChar8     c;
2187
2188     while ((c = *name++))
2189     {
2190         h = ((h << 1) | (h >> 31)) ^ c;
2191     }
2192     return h;
2193 }
2194
2195 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2196 /*
2197  * Use Type1 glyph names for fonts which have reliable names
2198  * and which export an Adobe Custom mapping
2199  */
2200 static FcBool
2201 FcFreeTypeUseNames (FT_Face face)
2202 {
2203     FT_Int  map;
2204     
2205     if (!FT_Has_PS_Glyph_Names (face))
2206         return FcFalse;
2207     for (map = 0; map < face->num_charmaps; map++)
2208         if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2209             return FcTrue;
2210     return FcFalse;
2211 }
2212
2213 static FcChar8 *
2214 FcUcs4ToGlyphName (FcChar32 ucs4)
2215 {
2216     int         i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2217     int         r = 0;
2218     FcGlyphName *gn;
2219
2220     while ((gn = ucs_to_name[i]))
2221     {
2222         if (gn->ucs == ucs4)
2223             return gn->name;
2224         if (!r) 
2225         {
2226             r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2227             if (!r)
2228                 r = 1;
2229         }
2230         i += r;
2231         if (i >= FC_GLYPHNAME_HASH)
2232             i -= FC_GLYPHNAME_HASH;
2233     }
2234     return 0;
2235 }
2236
2237 static FcChar32
2238 FcGlyphNameToUcs4 (FcChar8 *name)
2239 {
2240     FcChar32    h = FcHashGlyphName (name);
2241     int         i = (int) (h % FC_GLYPHNAME_HASH);
2242     int         r = 0;
2243     FcGlyphName *gn;
2244
2245     while ((gn = name_to_ucs[i]))
2246     {
2247         if (!strcmp ((char *) name, (char *) gn->name))
2248             return gn->ucs;
2249         if (!r) 
2250         {
2251             r = (int) (h % FC_GLYPHNAME_REHASH);
2252             if (!r)
2253                 r = 1;
2254         }
2255         i += r;
2256         if (i >= FC_GLYPHNAME_HASH)
2257             i -= FC_GLYPHNAME_HASH;
2258     }
2259     return 0xffff;
2260 }
2261
2262 /*
2263  * Search through a font for a glyph by name.  This is
2264  * currently a linear search as there doesn't appear to be
2265  * any defined order within the font
2266  */
2267 static FT_UInt
2268 FcFreeTypeGlyphNameIndex (FT_Face face, FcChar8 *name)
2269 {
2270     FT_UInt gindex;
2271     FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2272
2273     for (gindex = 0; gindex < face->num_glyphs; gindex++)
2274     {
2275         if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2276             if (!strcmp ((char *) name, (char *) name_buf))
2277                 return gindex;
2278     }
2279     return 0;
2280 }
2281 #endif
2282
2283 /*
2284  * Map a UCS4 glyph to a glyph index.  Use all available encoding
2285  * tables to try and find one that works.  This information is expected
2286  * to be cached by higher levels, so performance isn't critical
2287  */
2288
2289 FT_UInt
2290 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2291 {
2292     int             initial, offset, decode;
2293     FT_UInt         glyphindex;
2294     FcChar32        charcode;
2295     int             p;
2296
2297     initial = 0;
2298     /*
2299      * Find the current encoding
2300      */
2301     if (face->charmap)
2302     {
2303         for (; initial < NUM_DECODE; initial++)
2304             if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2305                 break;
2306         if (initial == NUM_DECODE)
2307             initial = 0;
2308     }
2309     for (p = 0; p < NUM_PREFER_UNICODE; p++)
2310         if (ucs4 == prefer_unicode[p])
2311         {
2312             initial = 0;
2313             break;
2314         }
2315     /*
2316      * Check each encoding for the glyph, starting with the current one
2317      */
2318     for (offset = 0; offset < NUM_DECODE; offset++)
2319     {
2320         decode = (initial + offset) % NUM_DECODE;
2321         if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2322             if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2323                 continue;
2324         if (fcFontDecoders[decode].map)
2325         {
2326             charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2327             if (charcode == ~0)
2328                 continue;
2329         }
2330         else
2331             charcode = ucs4;
2332         glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2333         if (glyphindex)
2334             return glyphindex;
2335     }
2336 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2337     /*
2338      * Check postscript name table if present
2339      */
2340     if (FcFreeTypeUseNames (face))
2341     {
2342         FcChar8 *name = FcUcs4ToGlyphName (ucs4);
2343         if (name)
2344         {
2345             glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2346             if (glyphindex)
2347                 return glyphindex;
2348         }
2349     }
2350 #endif
2351     return 0;
2352 }
2353
2354 static FcBool
2355 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, 
2356                       FT_UInt glyph, FcBlanks *blanks,
2357                       FT_Pos *advance)
2358 {
2359     FT_Int          load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2360     FT_GlyphSlot    slot;
2361     
2362     /*
2363      * When using scalable fonts, only report those glyphs
2364      * which can be scaled; otherwise those fonts will
2365      * only be available at some sizes, and never when
2366      * transformed.  Avoid this by simply reporting bitmap-only
2367      * glyphs as missing
2368      */
2369     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2370         load_flags |= FT_LOAD_NO_BITMAP;
2371     
2372     if (FT_Load_Glyph (face, glyph, load_flags))
2373         return FcFalse;
2374     
2375     slot = face->glyph;
2376     if (!glyph)
2377         return FcFalse;
2378     
2379     *advance = slot->metrics.horiAdvance;
2380
2381     switch (slot->format) {
2382     case ft_glyph_format_bitmap:
2383         /*
2384          * Bitmaps are assumed to be reasonable; if
2385          * this proves to be a rash assumption, this
2386          * code can be easily modified
2387          */
2388         return FcTrue;
2389     case ft_glyph_format_outline:
2390         /*
2391          * Glyphs with contours are always OK
2392          */
2393         if (slot->outline.n_contours != 0)
2394             return FcTrue;
2395         /*
2396          * Glyphs with no contours are only OK if
2397          * they're members of the Blanks set specified
2398          * in the configuration.  If blanks isn't set,
2399          * then allow any glyph to be blank
2400          */
2401         if (!blanks || FcBlanksIsMember (blanks, ucs4))
2402             return FcTrue;
2403         /* fall through ... */
2404     default:
2405         break;
2406     }
2407     return FcFalse;
2408 }
2409
2410 #define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
2411 #define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
2412 #define FC_ABS(a)   ((a) < 0 ? -(a) : (a))
2413 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2414
2415 FcCharSet *
2416 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2417 {
2418     FcChar32        page, off, max, ucs4;
2419 #ifdef CHECK
2420     FcChar32        font_max = 0;
2421 #endif
2422     FcCharSet       *fcs;
2423     FcCharLeaf      *leaf;
2424     const FcCharMap *map;
2425     int             o;
2426     int             i;
2427     FT_UInt         glyph;
2428     FT_Pos          advance, advance_one = 0, advance_two = 0;
2429     FcBool          has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2430
2431     fcs = FcCharSetCreate ();
2432     if (!fcs)
2433         goto bail0;
2434     
2435 #ifdef CHECK
2436     printf ("Family %s style %s\n", face->family_name, face->style_name);
2437 #endif
2438     for (o = 0; o < NUM_DECODE; o++)
2439     {
2440         if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2441             continue;
2442         map = fcFontDecoders[o].map;
2443         if (map)
2444         {
2445             /*
2446              * Non-Unicode tables are easy; there's a list of all possible
2447              * characters
2448              */
2449             for (i = 0; i < map->nent; i++)
2450             {
2451                 ucs4 = map->ent[i].bmp;
2452                 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2453                 if (glyph && 
2454                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2455                 {
2456                     if (!has_advance)
2457                     {
2458                         has_advance = FcTrue;
2459                         advance_one = advance;
2460                     }
2461                     else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2462                     {
2463                         if (fixed_advance)
2464                         {
2465                             dual_advance = FcTrue;
2466                             fixed_advance = FcFalse;
2467                             advance_two = advance;
2468                         }
2469                         else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2470                             dual_advance = FcFalse;
2471                     }
2472
2473                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2474                     if (!leaf)
2475                         goto bail1;
2476                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2477 #ifdef CHECK
2478                     if (ucs4 > font_max)
2479                         font_max = ucs4;
2480 #endif
2481                 }
2482             }
2483         }
2484         else
2485         {
2486             FT_UInt gindex;
2487           
2488             max = fcFontDecoders[o].max;
2489             /*
2490              * Find the first encoded character in the font
2491              */
2492             if (FT_Get_Char_Index (face, 0))
2493             {
2494                 ucs4 = 0;
2495                 gindex = 1;
2496             }
2497             else
2498             {
2499                 ucs4 = FT_Get_Next_Char (face, 0, &gindex);
2500                 if (!ucs4)
2501                     gindex = 0;
2502             }
2503
2504             while (gindex)
2505             {
2506                 page = ucs4 >> 8;
2507                 leaf = 0;
2508                 while ((ucs4 >> 8) == page)
2509                 {
2510                     glyph = FT_Get_Char_Index (face, ucs4);
2511                     if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
2512                                                        glyph, blanks, &advance))
2513                     {
2514                         if (!has_advance)
2515                         {
2516                             has_advance = FcTrue;
2517                             advance_one = advance;
2518                         }
2519                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2520                         {
2521                             if (fixed_advance)
2522                             {
2523                                 dual_advance = FcTrue;
2524                                 fixed_advance = FcFalse;
2525                                 advance_two = advance;
2526                             }
2527                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2528                                 dual_advance = FcFalse;
2529                         }
2530
2531                         if (!leaf)
2532                         {
2533                             leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2534                             if (!leaf)
2535                                 goto bail1;
2536                         }
2537                         off = ucs4 & 0xff;
2538                         leaf->map[off >> 5] |= (1 << (off & 0x1f));
2539 #ifdef CHECK
2540                         if (ucs4 > font_max)
2541                             font_max = ucs4;
2542 #endif
2543                     }
2544                     ucs4++;
2545                 }
2546                 ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
2547                 if (!ucs4)
2548                     gindex = 0;
2549             }
2550 #ifdef CHECK
2551             for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2552             {
2553                 FcBool      FT_Has, FC_Has;
2554
2555                 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2556                 FC_Has = FcCharSetHasChar (fcs, ucs4);
2557                 if (FT_Has != FC_Has)
2558                 {
2559                     printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2560                 }
2561             }
2562 #endif
2563         }
2564     }
2565 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2566     /*
2567      * Add mapping from PS glyph names if available
2568      */
2569     if (FcFreeTypeUseNames (face))
2570     {
2571         FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2572
2573         for (glyph = 0; glyph < face->num_glyphs; glyph++)
2574         {
2575             if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2576             {
2577                 ucs4 = FcGlyphNameToUcs4 (name_buf);
2578                 if (ucs4 != 0xffff && 
2579                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2580                 {
2581                     if (!has_advance)
2582                     {
2583                         has_advance = FcTrue;
2584                         advance_one = advance;
2585                     }
2586                     else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2587                     {
2588                         if (fixed_advance)
2589                         {
2590                             dual_advance = FcTrue;
2591                             fixed_advance = FcFalse;
2592                             advance_two = advance;
2593                         }
2594                         else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2595                             dual_advance = FcFalse;
2596                     }
2597                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2598                     if (!leaf)
2599                         goto bail1;
2600                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2601 #ifdef CHECK
2602                     if (ucs4 > font_max)
2603                         font_max = ucs4;
2604 #endif
2605                 }
2606             }
2607         }
2608     }
2609 #endif
2610 #ifdef CHECK
2611     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2612     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2613     {
2614         FcBool  has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2615         FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
2616
2617         if (has_char && !has_bit)
2618         {
2619             if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2620                 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2621             else
2622                 printf ("Bitmap missing char 0x%x\n", ucs4);
2623         }
2624         else if (!has_char && has_bit)
2625             printf ("Bitmap extra char 0x%x\n", ucs4);
2626     }
2627 #endif
2628     if (fixed_advance)
2629         *spacing = FC_MONO;
2630     else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2631         *spacing = FC_DUAL;
2632     else
2633         *spacing = FC_PROPORTIONAL;
2634     return fcs;
2635 bail1:
2636     FcCharSetDestroy (fcs);
2637 bail0:
2638     return 0;
2639 }
2640
2641 FcCharSet *
2642 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2643 {
2644     int spacing;
2645
2646     return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2647 }
2648
2649
2650 #define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2651 #define TTAG_GSUB  FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2652 #define TTAG_SILF  FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2653 #define TT_Err_Ok FT_Err_Ok
2654 #define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
2655 #define TTO_Err_Empty_Script              0x1005
2656 #define TTO_Err_Invalid_SubTable          0x1001
2657
2658 #define OTLAYOUT_HEAD       "otlayout:"
2659 #define OTLAYOUT_HEAD_LEN   9
2660 #define OTLAYOUT_ID_LEN     4
2661 /* space + head + id */
2662 #define OTLAYOUT_LEN        (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2663
2664 /*
2665  * This is a bit generous; the registry has only lower case and space
2666  * except for 'DFLT'.
2667  */
2668 #define FcIsSpace(x)        (040 == (x))
2669 #define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2670                              
2671 static void
2672 addtag(FcChar8 *complex, FT_ULong tag)
2673 {
2674     FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2675
2676     tagstring[0] = (FcChar8)(tag >> 24),
2677     tagstring[1] = (FcChar8)(tag >> 16),
2678     tagstring[2] = (FcChar8)(tag >> 8),
2679     tagstring[3] = (FcChar8)(tag);
2680     tagstring[4] = '\0';
2681     
2682     /* skip tags which aren't alphabetic, under the assumption that
2683      * they're probably broken
2684      */
2685     if (!FcIsValidScript(tagstring[0]) ||
2686         !FcIsValidScript(tagstring[1]) ||
2687         !FcIsValidScript(tagstring[2]) ||
2688         !FcIsValidScript(tagstring[3]))
2689         return;
2690
2691     if (*complex != '\0')
2692         strcat (complex, " ");
2693     strcat (complex, "otlayout:");
2694     strcat (complex, tagstring);
2695 }
2696
2697 static int
2698 compareulong (const void *a, const void *b)
2699 {
2700     const FT_ULong *ua = (const FT_ULong *) a;
2701     const FT_ULong *ub = (const FT_ULong *) b;
2702     return *ua - *ub;
2703 }
2704
2705
2706 static FT_Error
2707 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
2708 {
2709     FT_ULong         cur_offset, new_offset, base_offset;
2710     TT_Face          tt_face = (TT_Face)face;
2711     FT_Stream  stream = face->stream;
2712     FT_Error   error;
2713     FT_UShort          n, p;
2714     FT_Memory  memory = stream->memory;
2715
2716     if ( !stream )
2717         return TT_Err_Invalid_Face_Handle;
2718
2719     if (( error = tt_face->goto_table( tt_face, tabletag, stream, 0 ) ))
2720         return error;
2721
2722     base_offset = FT_STREAM_POS();
2723
2724     /* skip version */
2725
2726     if ( FT_STREAM_SEEK( base_offset + 4L ) || FT_FRAME_ENTER( 2L ) )
2727         return error;
2728
2729     new_offset = FT_GET_USHORT() + base_offset;
2730
2731     FT_FRAME_EXIT();
2732
2733     cur_offset = FT_STREAM_POS();
2734
2735     if ( FT_STREAM_SEEK( new_offset ) != TT_Err_Ok )
2736         return error;
2737
2738     base_offset = FT_STREAM_POS();
2739
2740     if ( FT_FRAME_ENTER( 2L ) )
2741         return error;
2742
2743     *script_count = FT_GET_USHORT();
2744
2745     FT_FRAME_EXIT();
2746
2747     if ( FT_SET_ERROR (FT_MEM_ALLOC_ARRAY( *stags, *script_count, FT_ULong )) )
2748         return error;
2749
2750     p = 0;
2751     for ( n = 0; n < *script_count; n++ )
2752     {
2753         if ( FT_FRAME_ENTER( 6L ) )
2754             goto Fail;
2755
2756         (*stags)[p] = FT_GET_ULONG();
2757         new_offset = FT_GET_USHORT() + base_offset;
2758
2759         FT_FRAME_EXIT();
2760
2761         cur_offset = FT_STREAM_POS();
2762
2763         if ( FT_STREAM_SEEK( new_offset ) )
2764             goto Fail;
2765
2766         if ( error == TT_Err_Ok )
2767             p++;
2768         else if ( error != TTO_Err_Empty_Script )
2769             goto Fail;
2770
2771         (void)FT_STREAM_SEEK( cur_offset );
2772     }
2773
2774     if (!p)
2775     {
2776         error = TTO_Err_Invalid_SubTable;
2777         goto Fail;
2778     }
2779
2780     // sort the tag list before returning it
2781     qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
2782
2783     return TT_Err_Ok;
2784
2785 Fail:
2786     *script_count = 0;
2787     FT_FREE( *stags );
2788     return error;
2789 }
2790
2791 static FcChar8 *
2792 FcFontCapabilities(FT_Face face)
2793 {
2794     FcBool issilgraphitefont = 0;
2795     FT_Error err;
2796     FT_ULong len = 0;
2797     FT_ULong *gsubtags=NULL, *gpostags=NULL;
2798     FT_UShort gsub_count=0, gpos_count=0;
2799     FT_ULong maxsize;
2800     FT_Memory  memory = face->stream->memory;
2801     FcChar8 *complex = NULL;
2802     int indx1 = 0, indx2 = 0;
2803
2804     err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2805     issilgraphitefont = ( err == FT_Err_Ok);
2806
2807     if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
2808         gpos_count = 0;
2809     if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
2810         gsub_count = 0;
2811     
2812     if (!issilgraphitefont && !gsub_count && !gpos_count)
2813         goto bail;
2814
2815     maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN + 
2816                (issilgraphitefont ? 13 : 0));
2817     complex = malloc (sizeof (FcChar8) * maxsize);
2818     if (!complex)
2819         goto bail;
2820
2821     complex[0] = '\0';
2822     if (issilgraphitefont)
2823         strcpy(complex, "ttable:Silf ");
2824
2825     while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2826         if (indx1 == gsub_count) {
2827             addtag(complex, gpostags[indx2]);
2828             indx2++;
2829         } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2830             addtag(complex, gsubtags[indx1]);
2831             indx1++;
2832         } else if (gsubtags[indx1] == gpostags[indx2]) {
2833             addtag(complex, gsubtags[indx1]);
2834             indx1++;
2835             indx2++;
2836         } else {
2837             addtag(complex, gpostags[indx2]);
2838             indx2++;
2839         }
2840     }
2841     if (FcDebug () & FC_DBG_SCANV)
2842         printf("complex features in this font: %s\n", complex);
2843 bail:
2844     FT_FREE(gsubtags);
2845     FT_FREE(gpostags);
2846     return complex;
2847 }