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