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