50ff3489c8179d419eb8d6cbf8d02b13cceedfcb
[platform/upstream/fontconfig.git] / src / fcfreetype.c
1 /*
2  * fontconfig/src/fcfreetype.c
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 the author(s) not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  The authors make 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  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR(S) 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 "fcftint.h"
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <ft2build.h>
53 #include FT_FREETYPE_H
54 #include FT_TRUETYPE_TABLES_H
55 #include FT_SFNT_NAMES_H
56 #include FT_TRUETYPE_IDS_H
57 #include FT_TYPE1_TABLES_H
58 #if HAVE_FT_GET_X11_FONT_FORMAT
59 #include FT_XFREE86_H
60 #endif
61 #if HAVE_FT_GET_BDF_PROPERTY
62 #include FT_BDF_H
63 #include FT_MODULE_H
64 #endif
65
66 #include "ftglue.h"
67
68 #if HAVE_WARNING_CPP_DIRECTIVE
69 #if !HAVE_FT_GET_BDF_PROPERTY
70 #warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later"
71 #endif
72
73 #if !HAVE_FT_GET_PS_FONT_INFO
74 #warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
75 #endif
76 #endif
77
78 /*
79  * Keep Han languages separated by eliminating languages
80  * that the codePageRange bits says aren't supported
81  */
82
83 static const struct {
84     char            bit;
85     const FcChar8   lang[6];
86 } FcCodePageRange[] = {
87     { 17,       "ja" },
88     { 18,       "zh-cn" },
89     { 19,       "ko" },
90     { 20,       "zh-tw" },
91 };
92
93 #define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
94
95 FcBool
96 FcFreeTypeIsExclusiveLang (const FcChar8  *lang)
97 {
98     int     i;
99
100     for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
101     {
102         if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual)
103             return FcTrue;
104     }
105     return FcFalse;
106 }
107
108 typedef struct {
109     const FT_UShort     platform_id;
110     const FT_UShort     encoding_id;
111     const char  fromcode[12];
112 } FcFtEncoding;
113
114 #define TT_ENCODING_DONT_CARE   0xffff
115 #define FC_ENCODING_MAC_ROMAN   "MACINTOSH"
116
117 static const FcFtEncoding   fcFtEncoding[] = {
118  {  TT_PLATFORM_APPLE_UNICODE,  TT_ENCODING_DONT_CARE,  "UTF-16BE" },
119  {  TT_PLATFORM_MACINTOSH,      TT_MAC_ID_ROMAN,        "MACINTOSH" },
120  {  TT_PLATFORM_MACINTOSH,      TT_MAC_ID_JAPANESE,     "SJIS" },
121  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_SYMBOL_CS,     "UTF-16BE" },
122  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_UNICODE_CS,    "UTF-16BE" },
123  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_SJIS,          "SJIS-WIN" },
124  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_GB2312,        "GB2312" },
125  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_BIG_5,         "BIG-5" },
126  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_WANSUNG,       "Wansung" },
127  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_JOHAB,         "Johab" },
128  {  TT_PLATFORM_MICROSOFT,      TT_MS_ID_UCS_4,         "UTF-16BE" },
129  {  TT_PLATFORM_ISO,            TT_ISO_ID_7BIT_ASCII,   "ASCII" },
130  {  TT_PLATFORM_ISO,            TT_ISO_ID_10646,        "UTF-16BE" },
131  {  TT_PLATFORM_ISO,            TT_ISO_ID_8859_1,       "ISO-8859-1" },
132 };
133
134 #define NUM_FC_FT_ENCODING  (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
135
136 typedef struct {
137     const FT_UShort     platform_id;
138     const FT_UShort     language_id;
139     const char  lang[8];
140 } FcFtLanguage;
141
142 #define TT_LANGUAGE_DONT_CARE   0xffff
143
144 static const FcFtLanguage   fcFtLanguage[] = {
145  {  TT_PLATFORM_APPLE_UNICODE,  TT_LANGUAGE_DONT_CARE,              "" },
146  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ENGLISH,              "en" },
147  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FRENCH,               "fr" },
148  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GERMAN,               "de" },
149  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ITALIAN,              "it" },
150  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_DUTCH,                "nl" },
151  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SWEDISH,              "sv" },
152  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SPANISH,              "es" },
153  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_DANISH,               "da" },
154  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_PORTUGUESE,           "pt" },
155  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_NORWEGIAN,            "no" },
156  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_HEBREW,               "he" },
157  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_JAPANESE,             "ja" },
158  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ARABIC,               "ar" },
159  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FINNISH,              "fi" },
160  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GREEK,                "el" },
161  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ICELANDIC,            "is" },
162  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALTESE,              "mt" },
163  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TURKISH,              "tr" },
164  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CROATIAN,             "hr" },
165  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CHINESE_TRADITIONAL,  "zh-tw" },
166  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_URDU,                 "ur" },
167  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_HINDI,                "hi" },
168  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_THAI,                 "th" },
169  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KOREAN,               "ko" },
170  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LITHUANIAN,           "lt" },
171  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_POLISH,               "pl" },
172  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_HUNGARIAN,            "hu" },
173  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ESTONIAN,             "et" },
174  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LETTISH,              "lv" },
175 /* {  TT_PLATFORM_MACINTOSH,    TT_MAC_LANGID_SAAMISK, ??? */
176  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FAEROESE,             "fo" },
177  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FARSI,                "fa" },
178  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_RUSSIAN,              "ru" },
179  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CHINESE_SIMPLIFIED,   "zh-cn" },
180  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_FLEMISH,              "nl" },
181  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_IRISH,                "ga" },
182  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ALBANIAN,             "sq" },
183  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ROMANIAN,             "ro" },
184  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CZECH,                "cs" },
185  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SLOVAK,               "sk" },
186  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SLOVENIAN,            "sl" },
187  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_YIDDISH,              "yi" },
188  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SERBIAN,              "sr" },
189  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MACEDONIAN,           "mk" },
190  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BULGARIAN,            "bg" },
191  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_UKRAINIAN,            "uk" },
192  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BYELORUSSIAN,         "be" },
193  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_UZBEK,                "uz" },
194  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KAZAKH,               "kk" },
195  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI,          "az" },
196  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
197  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT,    "ar" },
198  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ARMENIAN,             "hy" },
199  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GEORGIAN,             "ka" },
200  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MOLDAVIAN,            "mo" },
201  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KIRGHIZ,              "ky" },
202  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TAJIKI,               "tg" },
203  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TURKMEN,              "tk" },
204  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MONGOLIAN,            "mo" },
205  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
206  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
207  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_PASHTO,               "ps" },
208  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KURDISH,              "ku" },
209  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KASHMIRI,             "ks" },
210  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SINDHI,               "sd" },
211  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TIBETAN,              "bo" },
212  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_NEPALI,               "ne" },
213  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SANSKRIT,             "sa" },
214  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MARATHI,              "mr" },
215  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BENGALI,              "bn" },
216  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ASSAMESE,             "as" },
217  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GUJARATI,             "gu" },
218  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_PUNJABI,              "pa" },
219  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ORIYA,                "or" },
220  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAYALAM,            "ml" },
221  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KANNADA,              "kn" },
222  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TAMIL,                "ta" },
223  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TELUGU,               "te" },
224  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SINHALESE,            "si" },
225  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BURMESE,              "my" },
226  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_KHMER,                "km" },
227  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LAO,                  "lo" },
228  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_VIETNAMESE,           "vi" },
229  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_INDONESIAN,           "id" },
230  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TAGALOG,              "tl" },
231  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAY_ROMAN_SCRIPT,   "ms" },
232  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAY_ARABIC_SCRIPT,  "ms" },
233  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AMHARIC,              "am" },
234  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TIGRINYA,             "ti" },
235  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GALLA,                "om" },
236  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SOMALI,               "so" },
237  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SWAHILI,              "sw" },
238  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_RUANDA,               "rw" },
239  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_RUNDI,                "rn" },
240  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CHEWA,                "ny" },
241  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MALAGASY,             "mg" },
242  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_ESPERANTO,            "eo" },
243  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_WELSH,                "cy" },
244  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BASQUE,               "eu" },
245  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_CATALAN,              "ca" },
246  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_LATIN,                "la" },
247  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_QUECHUA,              "qu" },
248  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GUARANI,              "gn" },
249  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AYMARA,               "ay" },
250  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TATAR,                "tt" },
251  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_UIGHUR,               "ug" },
252  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_DZONGKHA,             "dz" },
253  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_JAVANESE,             "jw" },
254  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SUNDANESE,            "su" },
255
256 #if 0  /* these seem to be errors that have been dropped */
257
258  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SCOTTISH_GAELIC },
259  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_IRISH_GAELIC },
260
261 #endif
262
263   /* The following codes are new as of 2000-03-10 */
264  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GALICIAN,             "gl" },
265  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AFRIKAANS,            "af" },
266  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_BRETON,               "br" },
267  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_INUKTITUT,            "iu" },
268  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_SCOTTISH_GAELIC,      "gd" },
269  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_MANX_GAELIC,          "gv" },
270  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_IRISH_GAELIC,         "ga" },
271  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_TONGAN,               "to" },
272  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GREEK_POLYTONIC,      "el" },
273  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_GREELANDIC,           "ik" },
274  {  TT_PLATFORM_MACINTOSH,      TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
275
276  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_SAUDI_ARABIA,       "ar" },
277  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_IRAQ,               "ar" },
278  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_EGYPT,              "ar" },
279  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_LIBYA,              "ar" },
280  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_ALGERIA,            "ar" },
281  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_MOROCCO,            "ar" },
282  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_TUNISIA,            "ar" },
283  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_OMAN,               "ar" },
284  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_YEMEN,              "ar" },
285  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_SYRIA,              "ar" },
286  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_JORDAN,             "ar" },
287  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_LEBANON,            "ar" },
288  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_KUWAIT,             "ar" },
289  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_UAE,                "ar" },
290  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_BAHRAIN,            "ar" },
291  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_QATAR,              "ar" },
292  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BULGARIAN_BULGARIA,        "bg" },
293  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CATALAN_SPAIN,             "ca" },
294  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_TAIWAN,            "zh-tw" },
295  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_PRC,               "zh-cn" },
296  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_HONG_KONG,         "zh-hk" },
297  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_SINGAPORE,         "zh-sg" },
298
299  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_MACAU,             "zh-mo" },
300
301  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CZECH_CZECH_REPUBLIC,      "cs" },
302  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DANISH_DENMARK,            "da" },
303  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_GERMANY,            "de" },
304  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_SWITZERLAND,        "de" },
305  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_AUSTRIA,            "de" },
306  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_LUXEMBOURG,         "de" },
307  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GERMAN_LIECHTENSTEI,       "de" },
308  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GREEK_GREECE,              "el" },
309  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_UNITED_STATES,     "en" },
310  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_UNITED_KINGDOM,    "en" },
311  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_AUSTRALIA,         "en" },
312  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_CANADA,            "en" },
313  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_NEW_ZEALAND,       "en" },
314  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_IRELAND,           "en" },
315  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_SOUTH_AFRICA,      "en" },
316  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_JAMAICA,           "en" },
317  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_CARIBBEAN,         "en" },
318  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_BELIZE,            "en" },
319  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_TRINIDAD,          "en" },
320  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_ZIMBABWE,          "en" },
321  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_PHILIPPINES,       "en" },
322  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
323  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_MEXICO,            "es" },
324  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
325  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_GUATEMALA,         "es" },
326  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_COSTA_RICA,        "es" },
327  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PANAMA,            "es" },
328  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
329  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_VENEZUELA,         "es" },
330  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_COLOMBIA,          "es" },
331  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PERU,              "es" },
332  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_ARGENTINA,         "es" },
333  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_ECUADOR,           "es" },
334  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_CHILE,             "es" },
335  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_URUGUAY,           "es" },
336  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PARAGUAY,          "es" },
337  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_BOLIVIA,           "es" },
338  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_EL_SALVADOR,       "es" },
339  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_HONDURAS,          "es" },
340  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_NICARAGUA,         "es" },
341  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_PUERTO_RICO,       "es" },
342  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FINNISH_FINLAND,           "fi" },
343  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_FRANCE,             "fr" },
344  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_BELGIUM,            "fr" },
345  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_CANADA,             "fr" },
346  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_SWITZERLAND,        "fr" },
347  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_LUXEMBOURG,         "fr" },
348  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_MONACO,             "fr" },
349  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HEBREW_ISRAEL,             "he" },
350  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HUNGARIAN_HUNGARY,         "hu" },
351  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ICELANDIC_ICELAND,         "is" },
352  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ITALIAN_ITALY,             "it" },
353  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ITALIAN_SWITZERLAND,       "it" },
354  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_JAPANESE_JAPAN,            "ja" },
355  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
356  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KOREAN_JOHAB_KOREA,        "ko" },
357  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DUTCH_NETHERLANDS,         "nl" },
358  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DUTCH_BELGIUM,             "nl" },
359  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL,   "no" },
360  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK,  "nn" },
361  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_POLISH_POLAND,             "pl" },
362  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PORTUGUESE_BRAZIL,         "pt" },
363  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PORTUGUESE_PORTUGAL,       "pt" },
364  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
365  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ROMANIAN_ROMANIA,          "ro" },
366  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MOLDAVIAN_MOLDAVIA,        "mo" },
367  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_RUSSIAN_RUSSIA,            "ru" },
368  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_RUSSIAN_MOLDAVIA,          "ru" },
369  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CROATIAN_CROATIA,          "hr" },
370  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SERBIAN_SERBIA_LATIN,      "sr" },
371  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC,   "sr" },
372  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SLOVAK_SLOVAKIA,           "sk" },
373  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ALBANIAN_ALBANIA,          "sq" },
374  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SWEDISH_SWEDEN,            "sv" },
375  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SWEDISH_FINLAND,           "sv" },
376  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_THAI_THAILAND,             "th" },
377  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TURKISH_TURKEY,            "tr" },
378  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_URDU_PAKISTAN,             "ur" },
379  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_INDONESIAN_INDONESIA,      "id" },
380  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_UKRAINIAN_UKRAINE,         "uk" },
381  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BELARUSIAN_BELARUS,        "be" },
382  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SLOVENE_SLOVENIA,          "sl" },
383  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ESTONIAN_ESTONIA,          "et" },
384  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LATVIAN_LATVIA,            "lv" },
385  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LITHUANIAN_LITHUANIA,      "lt" },
386  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
387
388 #ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
389     /* this seems to be an error that have been dropped */
390  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MAORI_NEW_ZEALAND,         "mi" },
391 #endif
392
393  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FARSI_IRAN,                "fa" },
394  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_VIETNAMESE_VIET_NAM,       "vi" },
395  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARMENIAN_ARMENIA,          "hy" },
396  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN,    "az" },
397  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
398  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BASQUE_SPAIN,              "eu" },
399  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SORBIAN_GERMANY,           "wen" },
400  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MACEDONIAN_MACEDONIA,      "mk" },
401  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SUTU_SOUTH_AFRICA,         "st" },
402  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TSONGA_SOUTH_AFRICA,       "ts" },
403  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TSWANA_SOUTH_AFRICA,       "tn" },
404  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_VENDA_SOUTH_AFRICA,        "ven" },
405  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_XHOSA_SOUTH_AFRICA,        "xh" },
406  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ZULU_SOUTH_AFRICA,         "zu" },
407  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA,    "af" },
408  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GEORGIAN_GEORGIA,          "ka" },
409  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS,   "fo" },
410  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HINDI_INDIA,               "hi" },
411  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALTESE_MALTA,             "mt" },
412  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SAAMI_LAPONIA,             "se" },
413
414  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
415  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_IRISH_GAELIC_IRELAND,      "ga" },
416
417  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALAY_MALAYSIA,            "ms" },
418  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM,   "ms" },
419  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KAZAK_KAZAKSTAN,           "kk" },
420  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SWAHILI_KENYA,             "sw" },
421  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN,    "uz" },
422  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
423  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TATAR_TATARSTAN,           "tt" },
424  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BENGALI_INDIA,             "bn" },
425  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PUNJABI_INDIA,             "pa" },
426  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GUJARATI_INDIA,            "gu" },
427  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ORIYA_INDIA,               "or" },
428  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAMIL_INDIA,               "ta" },
429  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TELUGU_INDIA,              "te" },
430  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KANNADA_INDIA,             "kn" },
431  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MALAYALAM_INDIA,           "ml" },
432  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ASSAMESE_INDIA,            "as" },
433  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MARATHI_INDIA,             "mr" },
434  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SANSKRIT_INDIA,            "sa" },
435  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KONKANI_INDIA,             "kok" },
436
437   /* new as of 2001-01-01 */
438  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ARABIC_GENERAL,            "ar" },
439  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHINESE_GENERAL,           "zh" },
440  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_GENERAL,           "en" },
441  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_WEST_INDIES,        "fr" },
442  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_REUNION,            "fr" },
443  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_CONGO,              "fr" },
444
445  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_SENEGAL,            "fr" },
446  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_CAMEROON,           "fr" },
447  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_COTE_D_IVOIRE,      "fr" },
448  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_MALI,               "fr" },
449  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
450  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_URDU_INDIA,                "ur" },
451  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAJIK_TAJIKISTAN,          "tg" },
452  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_YIDDISH_GERMANY,           "yi" },
453  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN,       "ky" },
454
455  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TURKMEN_TURKMENISTAN,      "tk" },
456  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MONGOLIAN_MONGOLIA,        "mn" },
457
458   /* the following seems to be inconsistent;
459      here is the current "official" way: */
460  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIBETAN_BHUTAN,            "bo" },
461   /* and here is what is used by Passport SDK */
462  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIBETAN_CHINA,             "bo" },
463  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DZONGHKA_BHUTAN,           "dz" },
464   /* end of inconsistency */
465
466  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_WELSH_WALES,               "cy" },
467  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KHMER_CAMBODIA,            "km" },
468  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LAO_LAOS,                  "lo" },
469  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BURMESE_MYANMAR,           "my" },
470  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GALICIAN_SPAIN,            "gl" },
471  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MANIPURI_INDIA,            "mni" },
472  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SINDHI_INDIA,              "sd" },
473   /* the following one is only encountered in Microsoft RTF specification */
474  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KASHMIRI_PAKISTAN,         "ks" },
475   /* the following one is not in the Passport list, looks like an omission */
476  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KASHMIRI_INDIA,            "ks" },
477  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NEPALI_NEPAL,              "ne" },
478  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_NEPALI_INDIA,              "ne" },
479  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRISIAN_NETHERLANDS,       "fy" },
480
481   /* new as of 2001-03-01 (from Office Xp) */
482  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_HONG_KONG,         "en" },
483  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_INDIA,             "en" },
484  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_MALAYSIA,          "en" },
485  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_ENGLISH_SINGAPORE,         "en" },
486  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SYRIAC_SYRIA,              "syr" },
487  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SINHALESE_SRI_LANKA,       "si" },
488  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_CHEROKEE_UNITED_STATES,    "chr" },
489  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_INUKTITUT_CANADA,          "iu" },
490  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_AMHARIC_ETHIOPIA,          "am" },
491 #if 0
492  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAMAZIGHT_MOROCCO },
493  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
494 #endif
495  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PASHTO_AFGHANISTAN,        "ps" },
496  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FILIPINO_PHILIPPINES,      "phi" },
497  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_DHIVEHI_MALDIVES,          "div" },
498
499  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_OROMO_ETHIOPIA,            "om" },
500  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIGRIGNA_ETHIOPIA,         "ti" },
501  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_TIGRIGNA_ERYTHREA,         "ti" },
502
503   /* New additions from Windows Xp/Passport SDK 2001-11-10. */
504
505   /* don't ask what this one means... It is commented out currently. */
506 #if 0
507  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GREEK_GREECE2 },
508 #endif
509
510  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_UNITED_STATES,     "es" },
511   /* The following two IDs blatantly violate MS specs by using a */
512   /* sublanguage >,.                                         */
513  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SPANISH_LATIN_AMERICA,     "es" },
514  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_NORTH_AFRICA,       "fr" },
515
516  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_MOROCCO,            "fr" },
517  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FRENCH_HAITI,              "fr" },
518  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_BENGALI_BANGLADESH,        "bn" },
519  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN,   "ar" },
520  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
521 #if 0
522  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_EDO_NIGERIA },
523  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_FULFULDE_NIGERIA },
524  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_IBIBIO_NIGERIA },
525 #endif
526  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HAUSA_NIGERIA,             "ha" },
527  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_YORUBA_NIGERIA,            "yo" },
528   /* language codes from, to, are (still) unknown. */
529  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_IGBO_NIGERIA,              "ibo" },
530  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_KANURI_NIGERIA,            "kau" },
531  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_GUARANI_PARAGUAY,          "gn" },
532  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_HAWAIIAN_UNITED_STATES,    "haw" },
533  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_LATIN,                     "la" },
534  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_SOMALI_SOMALIA,            "so" },
535 #if 0
536   /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
537   /*       not written (but OTOH the peculiar writing system is worth     */
538   /*       studying).                                                     */
539  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_YI_CHINA },
540 #endif
541  {  TT_PLATFORM_MICROSOFT,      TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
542 };
543
544 #define NUM_FC_FT_LANGUAGE  (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
545
546 typedef struct {
547     FT_UShort   language_id;
548     char        fromcode[12];
549 } FcMacRomanFake;
550
551 static const FcMacRomanFake fcMacRomanFake[] = {
552  {  TT_MS_LANGID_JAPANESE_JAPAN,        "SJIS-WIN" },
553  {  TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" },
554 };
555
556 static FcChar8 *
557 FcFontCapabilities(FT_Face face);
558
559 #define NUM_FC_MAC_ROMAN_FAKE   (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
560
561
562 /* From http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT */
563 static const FcChar16 fcMacRomanNonASCIIToUnicode[128] = {
564   /*0x80*/ 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
565   /*0x81*/ 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
566   /*0x82*/ 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */
567   /*0x83*/ 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */
568   /*0x84*/ 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */
569   /*0x85*/ 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
570   /*0x86*/ 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
571   /*0x87*/ 0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */
572   /*0x88*/ 0x00E0, /* LATIN SMALL LETTER A WITH GRAVE */
573   /*0x89*/ 0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
574   /*0x8A*/ 0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */
575   /*0x8B*/ 0x00E3, /* LATIN SMALL LETTER A WITH TILDE */
576   /*0x8C*/ 0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */
577   /*0x8D*/ 0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */
578   /*0x8E*/ 0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */
579   /*0x8F*/ 0x00E8, /* LATIN SMALL LETTER E WITH GRAVE */
580   /*0x90*/ 0x00EA, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
581   /*0x91*/ 0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */
582   /*0x92*/ 0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */
583   /*0x93*/ 0x00EC, /* LATIN SMALL LETTER I WITH GRAVE */
584   /*0x94*/ 0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
585   /*0x95*/ 0x00EF, /* LATIN SMALL LETTER I WITH DIAERESIS */
586   /*0x96*/ 0x00F1, /* LATIN SMALL LETTER N WITH TILDE */
587   /*0x97*/ 0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */
588   /*0x98*/ 0x00F2, /* LATIN SMALL LETTER O WITH GRAVE */
589   /*0x99*/ 0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
590   /*0x9A*/ 0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */
591   /*0x9B*/ 0x00F5, /* LATIN SMALL LETTER O WITH TILDE */
592   /*0x9C*/ 0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */
593   /*0x9D*/ 0x00F9, /* LATIN SMALL LETTER U WITH GRAVE */
594   /*0x9E*/ 0x00FB, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
595   /*0x9F*/ 0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */
596   /*0xA0*/ 0x2020, /* DAGGER */
597   /*0xA1*/ 0x00B0, /* DEGREE SIGN */
598   /*0xA2*/ 0x00A2, /* CENT SIGN */
599   /*0xA3*/ 0x00A3, /* POUND SIGN */
600   /*0xA4*/ 0x00A7, /* SECTION SIGN */
601   /*0xA5*/ 0x2022, /* BULLET */
602   /*0xA6*/ 0x00B6, /* PILCROW SIGN */
603   /*0xA7*/ 0x00DF, /* LATIN SMALL LETTER SHARP S */
604   /*0xA8*/ 0x00AE, /* REGISTERED SIGN */
605   /*0xA9*/ 0x00A9, /* COPYRIGHT SIGN */
606   /*0xAA*/ 0x2122, /* TRADE MARK SIGN */
607   /*0xAB*/ 0x00B4, /* ACUTE ACCENT */
608   /*0xAC*/ 0x00A8, /* DIAERESIS */
609   /*0xAD*/ 0x2260, /* NOT EQUAL TO */
610   /*0xAE*/ 0x00C6, /* LATIN CAPITAL LETTER AE */
611   /*0xAF*/ 0x00D8, /* LATIN CAPITAL LETTER O WITH STROKE */
612   /*0xB0*/ 0x221E, /* INFINITY */
613   /*0xB1*/ 0x00B1, /* PLUS-MINUS SIGN */
614   /*0xB2*/ 0x2264, /* LESS-THAN OR EQUAL TO */
615   /*0xB3*/ 0x2265, /* GREATER-THAN OR EQUAL TO */
616   /*0xB4*/ 0x00A5, /* YEN SIGN */
617   /*0xB5*/ 0x00B5, /* MICRO SIGN */
618   /*0xB6*/ 0x2202, /* PARTIAL DIFFERENTIAL */
619   /*0xB7*/ 0x2211, /* N-ARY SUMMATION */
620   /*0xB8*/ 0x220F, /* N-ARY PRODUCT */
621   /*0xB9*/ 0x03C0, /* GREEK SMALL LETTER PI */
622   /*0xBA*/ 0x222B, /* INTEGRAL */
623   /*0xBB*/ 0x00AA, /* FEMININE ORDINAL INDICATOR */
624   /*0xBC*/ 0x00BA, /* MASCULINE ORDINAL INDICATOR */
625   /*0xBD*/ 0x03A9, /* GREEK CAPITAL LETTER OMEGA */
626   /*0xBE*/ 0x00E6, /* LATIN SMALL LETTER AE */
627   /*0xBF*/ 0x00F8, /* LATIN SMALL LETTER O WITH STROKE */
628   /*0xC0*/ 0x00BF, /* INVERTED QUESTION MARK */
629   /*0xC1*/ 0x00A1, /* INVERTED EXCLAMATION MARK */
630   /*0xC2*/ 0x00AC, /* NOT SIGN */
631   /*0xC3*/ 0x221A, /* SQUARE ROOT */
632   /*0xC4*/ 0x0192, /* LATIN SMALL LETTER F WITH HOOK */
633   /*0xC5*/ 0x2248, /* ALMOST EQUAL TO */
634   /*0xC6*/ 0x2206, /* INCREMENT */
635   /*0xC7*/ 0x00AB, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
636   /*0xC8*/ 0x00BB, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
637   /*0xC9*/ 0x2026, /* HORIZONTAL ELLIPSIS */
638   /*0xCA*/ 0x00A0, /* NO-BREAK SPACE */
639   /*0xCB*/ 0x00C0, /* LATIN CAPITAL LETTER A WITH GRAVE */
640   /*0xCC*/ 0x00C3, /* LATIN CAPITAL LETTER A WITH TILDE */
641   /*0xCD*/ 0x00D5, /* LATIN CAPITAL LETTER O WITH TILDE */
642   /*0xCE*/ 0x0152, /* LATIN CAPITAL LIGATURE OE */
643   /*0xCF*/ 0x0153, /* LATIN SMALL LIGATURE OE */
644   /*0xD0*/ 0x2013, /* EN DASH */
645   /*0xD1*/ 0x2014, /* EM DASH */
646   /*0xD2*/ 0x201C, /* LEFT DOUBLE QUOTATION MARK */
647   /*0xD3*/ 0x201D, /* RIGHT DOUBLE QUOTATION MARK */
648   /*0xD4*/ 0x2018, /* LEFT SINGLE QUOTATION MARK */
649   /*0xD5*/ 0x2019, /* RIGHT SINGLE QUOTATION MARK */
650   /*0xD6*/ 0x00F7, /* DIVISION SIGN */
651   /*0xD7*/ 0x25CA, /* LOZENGE */
652   /*0xD8*/ 0x00FF, /* LATIN SMALL LETTER Y WITH DIAERESIS */
653   /*0xD9*/ 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
654   /*0xDA*/ 0x2044, /* FRACTION SLASH */
655   /*0xDB*/ 0x20AC, /* EURO SIGN */
656   /*0xDC*/ 0x2039, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
657   /*0xDD*/ 0x203A, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
658   /*0xDE*/ 0xFB01, /* LATIN SMALL LIGATURE FI */
659   /*0xDF*/ 0xFB02, /* LATIN SMALL LIGATURE FL */
660   /*0xE0*/ 0x2021, /* DOUBLE DAGGER */
661   /*0xE1*/ 0x00B7, /* MIDDLE DOT */
662   /*0xE2*/ 0x201A, /* SINGLE LOW-9 QUOTATION MARK */
663   /*0xE3*/ 0x201E, /* DOUBLE LOW-9 QUOTATION MARK */
664   /*0xE4*/ 0x2030, /* PER MILLE SIGN */
665   /*0xE5*/ 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
666   /*0xE6*/ 0x00CA, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
667   /*0xE7*/ 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */
668   /*0xE8*/ 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
669   /*0xE9*/ 0x00C8, /* LATIN CAPITAL LETTER E WITH GRAVE */
670   /*0xEA*/ 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */
671   /*0xEB*/ 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
672   /*0xEC*/ 0x00CF, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
673   /*0xED*/ 0x00CC, /* LATIN CAPITAL LETTER I WITH GRAVE */
674   /*0xEE*/ 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */
675   /*0xEF*/ 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
676   /*0xF0*/ 0xF8FF, /* Apple logo */
677   /*0xF1*/ 0x00D2, /* LATIN CAPITAL LETTER O WITH GRAVE */
678   /*0xF2*/ 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */
679   /*0xF3*/ 0x00DB, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
680   /*0xF4*/ 0x00D9, /* LATIN CAPITAL LETTER U WITH GRAVE */
681   /*0xF5*/ 0x0131, /* LATIN SMALL LETTER DOTLESS I */
682   /*0xF6*/ 0x02C6, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
683   /*0xF7*/ 0x02DC, /* SMALL TILDE */
684   /*0xF8*/ 0x00AF, /* MACRON */
685   /*0xF9*/ 0x02D8, /* BREVE */
686   /*0xFA*/ 0x02D9, /* DOT ABOVE */
687   /*0xFB*/ 0x02DA, /* RING ABOVE */
688   /*0xFC*/ 0x00B8, /* CEDILLA */
689   /*0xFD*/ 0x02DD, /* DOUBLE ACUTE ACCENT */
690   /*0xFE*/ 0x02DB, /* OGONEK */
691   /*0xFF*/ 0x02C7, /* CARON */
692 };
693
694 #if USE_ICONV
695 #include <iconv.h>
696 #endif
697
698 /*
699  * A shift-JIS will have many high bits turned on
700  */
701 static FcBool
702 FcLooksLikeSJIS (FcChar8 *string, int len)
703 {
704     int     nhigh = 0, nlow = 0;
705
706     while (len-- > 0)
707     {
708         if (*string++ & 0x80) nhigh++;
709         else nlow++;
710     }
711     /*
712      * Heuristic -- if more than 1/3 of the bytes have the high-bit set,
713      * this is likely to be SJIS and not ROMAN
714      */
715     if (nhigh * 2 > nlow)
716         return FcTrue;
717     return FcFalse;
718 }
719
720 static FcChar8 *
721 FcSfntNameTranscode (FT_SfntName *sname)
722 {
723     int        i;
724     const char *fromcode;
725 #if USE_ICONV
726     iconv_t cd;
727 #endif
728     FcChar8 *utf8;
729
730     for (i = 0; i < NUM_FC_FT_ENCODING; i++)
731         if (fcFtEncoding[i].platform_id == sname->platform_id &&
732             (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
733              fcFtEncoding[i].encoding_id == sname->encoding_id))
734             break;
735     if (i == NUM_FC_FT_ENCODING)
736         return 0;
737     fromcode = fcFtEncoding[i].fromcode;
738
739     /*
740      * Many names encoded for TT_PLATFORM_MACINTOSH are broken
741      * in various ways. Kludge around them.
742      */
743     if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
744     {
745         if (sname->language_id == TT_MAC_LANGID_ENGLISH &&
746             FcLooksLikeSJIS (sname->string, sname->string_len))
747         {
748             fromcode = "SJIS";
749         }
750         else if (sname->language_id >= 0x100)
751         {
752             /*
753              * "real" Mac language IDs are all less than 150.
754              * Names using one of the MS language IDs are assumed
755              * to use an associated encoding (Yes, this is a kludge)
756              */
757             int f;
758
759             fromcode = NULL;
760             for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
761                 if (fcMacRomanFake[f].language_id == sname->language_id)
762                 {
763                     fromcode = fcMacRomanFake[f].fromcode;
764                     break;
765                 }
766             if (!fromcode)
767                 return 0;
768         }
769     }
770     if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
771     {
772         FcChar8     *src = sname->string;
773         int         src_len = sname->string_len;
774         int         len;
775         int         wchar;
776         int         ilen, olen;
777         FcChar8     *u8;
778         FcChar32    ucs4;
779         
780         /*
781          * Convert Utf16 to Utf8
782          */
783
784         if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
785             return 0;
786
787         /*
788          * Allocate plenty of space.  Freed below
789          */
790         utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
791         if (!utf8)
792             return 0;
793
794         u8 = utf8;
795
796         while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
797         {
798             src_len -= ilen;
799             src += ilen;
800             olen = FcUcs4ToUtf8 (ucs4, u8);
801             u8 += olen;
802         }
803         *u8 = '\0';
804         goto done;
805     }
806     if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
807     {
808         FcChar8     *src = sname->string;
809         int         src_len = sname->string_len;
810         int         olen;
811         FcChar8     *u8;
812         FcChar32    ucs4;
813         
814         /*
815          * Convert Latin1 to Utf8. Freed below
816          */
817         utf8 = malloc (src_len * 2 + 1);
818         if (!utf8)
819             return 0;
820
821         u8 = utf8;
822         while (src_len > 0)
823         {
824             ucs4 = *src++;
825             src_len--;
826             olen = FcUcs4ToUtf8 (ucs4, u8);
827             u8 += olen;
828         }
829         *u8 = '\0';
830         goto done;
831     }
832     if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
833     {
834         FcChar8     *src = sname->string;
835         int         src_len = sname->string_len;
836         int         olen;
837         FcChar8     *u8;
838         FcChar32    ucs4;
839
840         /*
841          * Convert Latin1 to Utf8. Freed below
842          */
843         utf8 = malloc (src_len * 3 + 1);
844         if (!utf8)
845             return 0;
846
847         u8 = utf8;
848         while (src_len > 0)
849         {
850             ucs4 = *src++;
851             if (ucs4 >= 128)
852                 ucs4 = fcMacRomanNonASCIIToUnicode[ucs4 - 128];
853             src_len--;
854             olen = FcUcs4ToUtf8 (ucs4, u8);
855             u8 += olen;
856         }
857         *u8 = '\0';
858         goto done;
859     }
860
861 #if USE_ICONV
862     cd = iconv_open ("UTF-8", fromcode);
863     if (cd && cd != (iconv_t) (-1))
864     {
865         size_t      in_bytes_left = sname->string_len;
866         size_t      out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
867         char        *inbuf, *outbuf;
868         
869         utf8 = malloc (out_bytes_left + 1);
870         if (!utf8)
871         {
872             iconv_close (cd);
873             return 0;
874         }
875         
876         outbuf = (char *) utf8;
877         inbuf = (char *) sname->string;
878         
879         while (in_bytes_left)
880         {
881             size_t      did = iconv (cd,
882                                  &inbuf, &in_bytes_left,
883                                  &outbuf, &out_bytes_left);
884             if (did == (size_t) (-1))
885             {
886                 iconv_close (cd);
887                 free (utf8);
888                 return 0;
889             }
890         }
891         iconv_close (cd);
892         *outbuf = '\0';
893         goto done;
894     }
895 #endif
896     return 0;
897 done:
898     if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
899     {
900         free (utf8);
901         return 0;
902     }
903     return utf8;
904 }
905
906 static const FcChar8 *
907 FcSfntNameLanguage (FT_SfntName *sname)
908 {
909     int i;
910     FT_UShort   platform_id = sname->platform_id;
911     FT_UShort   language_id = sname->language_id;
912
913     /*
914      * Many names encoded for TT_PLATFORM_MACINTOSH are broken
915      * in various ways. Kludge around them.
916      */
917     if (platform_id == TT_PLATFORM_MACINTOSH &&
918         sname->encoding_id == TT_MAC_ID_ROMAN &&
919         FcLooksLikeSJIS (sname->string, sname->string_len))
920     {
921         language_id = TT_MAC_LANGID_JAPANESE;
922     }
923
924     for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
925         if (fcFtLanguage[i].platform_id == platform_id &&
926             (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
927              fcFtLanguage[i].language_id == language_id))
928         {
929             if (fcFtLanguage[i].lang[0] == '\0')
930               return NULL;
931             else
932               return (FcChar8 *) fcFtLanguage[i].lang;
933         }
934     return 0;
935 }
936
937 /* Order is significant.  For example, some B&H fonts are hinted by
938    URW++, and both strings appear in the notice. */
939
940 static const char *FcNoticeFoundries[][2] =
941     {
942      {"Adobe", "adobe"},
943      {"Bigelow", "b&h"},
944      {"Bitstream", "bitstream"},
945      {"Gnat", "culmus"},
946      {"Iorsh", "culmus"},
947      {"HanYang System", "hanyang"},
948      {"Font21", "hwan"},
949      {"IBM", "ibm"},
950      {"International Typeface Corporation", "itc"},
951      {"Linotype", "linotype"},
952      {"LINOTYPE-HELL", "linotype"},
953      {"Microsoft", "microsoft"},
954      {"Monotype", "monotype"},
955      {"Omega", "omega"},
956      {"Tiro Typeworks", "tiro"},
957      {"URW", "urw"},
958      {"XFree86", "xfree86"},
959      {"Xorg", "xorg"},
960 };
961
962 #define NUM_NOTICE_FOUNDRIES    (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
963
964 static const FcChar8 *
965 FcNoticeFoundry(const FT_String *notice)
966 {
967     int i;
968
969     if (notice)
970         for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
971         {
972             const char *n = FcNoticeFoundries[i][0];
973             const char *f = FcNoticeFoundries[i][1];
974
975             if (strstr ((const char *) notice, n))
976                 return (const FcChar8 *) f;
977         }
978     return 0;
979 }
980
981 static FcBool
982 FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
983 {
984     /* vendor is not necessarily NUL-terminated. */
985     int i, len;
986
987     len = strlen((char *) vendor_string);
988     if (memcmp(vendor, vendor_string, len) != 0)
989         return FcFalse;
990     for (i = len; i < 4; i++)
991         if (vendor[i] != ' ' && vendor[i] != '\0')
992             return FcFalse;
993     return FcTrue;
994 }
995
996 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
997
998 /* It should not contain useless entries (such as UNKN) nor duplicate
999    entries for padding both with spaces and NULs. */
1000
1001 static const struct {
1002     const FT_Char   vendor[5];
1003     const FcChar8   foundry[13];
1004 } FcVendorFoundries[] = {
1005     { "ADBE", "adobe"},
1006     { "AGFA", "agfa"},
1007     { "ALTS", "altsys"},
1008     { "APPL", "apple"},
1009     { "ARPH", "arphic"},
1010     { "ATEC", "alltype"},
1011     { "B&H",  "b&h"},
1012     { "BITS", "bitstream"},
1013     { "CANO", "cannon"},
1014     { "CLM",  "culmus"},
1015     { "DYNA", "dynalab"},
1016     { "EPSN", "epson"},
1017     { "FJ",   "fujitsu"},
1018     { "IBM",  "ibm"},
1019     { "ITC",  "itc"},
1020     { "IMPR", "impress"},
1021     { "LARA", "larabiefonts"},
1022     { "LEAF", "interleaf"},
1023     { "LETR", "letraset"},
1024     { "LINO", "linotype"},
1025     { "MACR", "macromedia"},
1026     { "MONO", "monotype"},
1027     { "MS",   "microsoft"},
1028     { "MT",   "monotype"},
1029     { "NEC",  "nec"},
1030     { "PARA", "paratype"},
1031     { "QMSI", "qms"},
1032     { "RICO", "ricoh"},
1033     { "URW",  "urw"},
1034     { "Y&Y",  "y&y"}
1035 };
1036
1037 #define NUM_VENDOR_FOUNDRIES    (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
1038
1039 static const FcChar8 *
1040 FcVendorFoundry(const FT_Char vendor[4])
1041 {
1042     int i;
1043
1044     if (vendor)
1045         for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
1046             if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
1047                 return FcVendorFoundries[i].foundry;
1048     return 0;
1049 }
1050
1051 typedef struct _FcStringConst {
1052     const FcChar8   *name;
1053     int             value;
1054 } FcStringConst;
1055
1056 static int
1057 FcStringIsConst (const FcChar8          *string,
1058                  const FcStringConst    *c,
1059                  int                    nc)
1060 {
1061     int i;
1062
1063     for (i = 0; i < nc; i++)
1064         if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
1065             return c[i].value;
1066     return -1;
1067 }
1068
1069 static int
1070 FcStringContainsConst (const FcChar8        *string,
1071                        const FcStringConst  *c,
1072                        int                  nc)
1073 {
1074     int i;
1075
1076     for (i = 0; i < nc; i++)
1077     {
1078         if (c[i].name[0] == '<')
1079         {
1080             if (FcStrContainsWord (string, c[i].name + 1))
1081                 return c[i].value;
1082         }
1083         else
1084         {
1085             if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
1086                 return c[i].value;
1087         }
1088     }
1089     return -1;
1090 }
1091
1092 typedef FcChar8 *FC8;
1093
1094 static const FcStringConst  weightConsts[] = {
1095     { (FC8) "thin",             FC_WEIGHT_THIN },
1096     { (FC8) "extralight",       FC_WEIGHT_EXTRALIGHT },
1097     { (FC8) "ultralight",       FC_WEIGHT_ULTRALIGHT },
1098     { (FC8) "demilight",        FC_WEIGHT_DEMILIGHT },
1099     { (FC8) "semilight",        FC_WEIGHT_SEMILIGHT },
1100     { (FC8) "light",            FC_WEIGHT_LIGHT },
1101     { (FC8) "book",             FC_WEIGHT_BOOK },
1102     { (FC8) "regular",          FC_WEIGHT_REGULAR },
1103     { (FC8) "normal",           FC_WEIGHT_NORMAL },
1104     { (FC8) "medium",           FC_WEIGHT_MEDIUM },
1105     { (FC8) "demibold",         FC_WEIGHT_DEMIBOLD },
1106     { (FC8) "demi",             FC_WEIGHT_DEMIBOLD },
1107     { (FC8) "semibold",         FC_WEIGHT_SEMIBOLD },
1108     { (FC8) "extrabold",        FC_WEIGHT_EXTRABOLD },
1109     { (FC8) "superbold",        FC_WEIGHT_EXTRABOLD },
1110     { (FC8) "ultrabold",        FC_WEIGHT_ULTRABOLD },
1111     { (FC8) "bold",             FC_WEIGHT_BOLD },
1112     { (FC8) "ultrablack",       FC_WEIGHT_ULTRABLACK },
1113     { (FC8) "superblack",       FC_WEIGHT_EXTRABLACK },
1114     { (FC8) "extrablack",       FC_WEIGHT_EXTRABLACK },
1115     { (FC8) "<ultra",           FC_WEIGHT_ULTRABOLD }, /* only if a word */
1116     { (FC8) "black",            FC_WEIGHT_BLACK },
1117     { (FC8) "heavy",            FC_WEIGHT_HEAVY },
1118 };
1119
1120 #define NUM_WEIGHT_CONSTS  (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
1121
1122 #define FcIsWeight(s)       FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
1123 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
1124
1125 static const FcStringConst  widthConsts[] = {
1126     { (FC8) "ultracondensed",   FC_WIDTH_ULTRACONDENSED },
1127     { (FC8) "extracondensed",   FC_WIDTH_EXTRACONDENSED },
1128     { (FC8) "semicondensed",    FC_WIDTH_SEMICONDENSED },
1129     { (FC8) "condensed",        FC_WIDTH_CONDENSED },   /* must be after *condensed */
1130     { (FC8) "normal",           FC_WIDTH_NORMAL },
1131     { (FC8) "semiexpanded",     FC_WIDTH_SEMIEXPANDED },
1132     { (FC8) "extraexpanded",    FC_WIDTH_EXTRAEXPANDED },
1133     { (FC8) "ultraexpanded",    FC_WIDTH_ULTRAEXPANDED },
1134     { (FC8) "expanded",         FC_WIDTH_EXPANDED },    /* must be after *expanded */
1135     { (FC8) "extended",         FC_WIDTH_EXPANDED },
1136 };
1137
1138 #define NUM_WIDTH_CONSTS    (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
1139
1140 #define FcIsWidth(s)        FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
1141 #define FcContainsWidth(s)  FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
1142
1143 static const FcStringConst  slantConsts[] = {
1144     { (FC8) "italic",           FC_SLANT_ITALIC },
1145     { (FC8) "kursiv",           FC_SLANT_ITALIC },
1146     { (FC8) "oblique",          FC_SLANT_OBLIQUE },
1147 };
1148
1149 #define NUM_SLANT_CONSTS    (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
1150
1151 #define FcContainsSlant(s)  FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
1152
1153 static const FcStringConst  decorativeConsts[] = {
1154     { (FC8) "shadow",           FcTrue },
1155     { (FC8) "caps",             FcTrue },
1156     { (FC8) "antiqua",          FcTrue },
1157     { (FC8) "romansc",          FcTrue },
1158     { (FC8) "embosed",          FcTrue },
1159     { (FC8) "dunhill",          FcTrue },
1160 };
1161
1162 #define NUM_DECORATIVE_CONSTS   (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
1163
1164 #define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1165
1166 static double
1167 FcGetPixelSize (FT_Face face, int i)
1168 {
1169 #if HAVE_FT_GET_BDF_PROPERTY
1170     if (face->num_fixed_sizes == 1)
1171     {
1172         BDF_PropertyRec prop;
1173         int             rc;
1174
1175         rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
1176         if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1177             return (double) prop.u.integer;
1178     }
1179 #endif
1180 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
1181     return (double) face->available_sizes[i].y_ppem / 64.0;
1182 #else
1183     return (double) face->available_sizes[i].height;
1184 #endif
1185 }
1186
1187 static FcBool
1188 FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
1189 {
1190     int     e;
1191     FcChar8 *old;
1192     for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1193         if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1194         {
1195             return FcTrue;
1196         }
1197     return FcFalse;
1198 }
1199
1200 static const FT_UShort platform_order[] = {
1201     TT_PLATFORM_MICROSOFT,
1202     TT_PLATFORM_APPLE_UNICODE,
1203     TT_PLATFORM_MACINTOSH,
1204 };
1205 #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
1206
1207 static const FT_UShort nameid_order[] = {
1208 #ifdef TT_NAME_ID_WWS_FAMILY
1209     TT_NAME_ID_WWS_FAMILY,
1210 #endif
1211     TT_NAME_ID_PREFERRED_FAMILY,
1212     TT_NAME_ID_FONT_FAMILY,
1213     TT_NAME_ID_MAC_FULL_NAME,
1214     TT_NAME_ID_FULL_NAME,
1215 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1216     TT_NAME_ID_WWS_SUBFAMILY,
1217 #endif
1218     TT_NAME_ID_PREFERRED_SUBFAMILY,
1219     TT_NAME_ID_FONT_SUBFAMILY,
1220     TT_NAME_ID_TRADEMARK,
1221     TT_NAME_ID_MANUFACTURER,
1222 };
1223
1224 #define NUM_NAMEID_ORDER  (sizeof (nameid_order) / sizeof (nameid_order[0]))
1225 FcPattern *
1226 FcFreeTypeQueryFace (const FT_Face  face,
1227                      const FcChar8  *file,
1228                      int            id,
1229                      FcBlanks       *blanks)
1230 {
1231     FcPattern       *pat;
1232     int             slant = -1;
1233     int             weight = -1;
1234     int             width = -1;
1235     FcBool          decorative = FcFalse;
1236     int             i;
1237     FcCharSet       *cs;
1238     FcLangSet       *ls;
1239 #if 0
1240     FcChar8         *family = 0;
1241 #endif
1242     FcChar8         *complex_;
1243     const FcChar8   *foundry = 0;
1244     int             spacing;
1245     TT_OS2          *os2;
1246 #if HAVE_FT_GET_PS_FONT_INFO
1247     PS_FontInfoRec  psfontinfo;
1248 #endif
1249 #if HAVE_FT_GET_BDF_PROPERTY
1250     BDF_PropertyRec prop;
1251 #endif
1252     TT_Header       *head;
1253     const FcChar8   *exclusiveLang = 0;
1254     FT_SfntName     sname;
1255     FT_UInt         snamei, snamec;
1256
1257     int             nfamily = 0;
1258     int             nfamily_lang = 0;
1259     int             nstyle = 0;
1260     int             nstyle_lang = 0;
1261     int             nfullname = 0;
1262     int             nfullname_lang = 0;
1263     unsigned int    p, n;
1264     int             platform, nameid;
1265
1266     FcChar8         *style = 0;
1267     int             st;
1268     char            psname[256];
1269     const char      *tmp;
1270
1271     FcRange         *r = NULL;
1272     double          lower_size = 0.0L, upper_size = DBL_MAX;
1273
1274     FcInitDebug (); /* We might be called with no initizalization whatsoever. */
1275
1276     pat = FcPatternCreate ();
1277     if (!pat)
1278         goto bail0;
1279
1280     {
1281         int has_outline = !!(face->face_flags & FT_FACE_FLAG_SCALABLE);
1282         int has_color = 0;
1283
1284 #ifdef FT_FACE_FLAG_COLOR
1285         has_color = !!(face->face_flags & FT_FACE_FLAG_COLOR);
1286 #endif
1287
1288         if (!FcPatternAddBool (pat, FC_OUTLINE, has_outline))
1289             goto bail1;
1290
1291 #ifdef FT_FACE_FLAG_COLOR
1292         if (!FcPatternAddBool (pat, FC_COLOR, has_color))
1293             goto bail1;
1294 #endif
1295
1296         /* All color fonts are designed to be scaled, even if they only have
1297          * bitmap strikes.  Client is responsible to scale the bitmaps.  This
1298          * is in constrast to non-color strikes... */
1299         if (!FcPatternAddBool (pat, FC_SCALABLE, has_outline || has_color))
1300             goto bail1;
1301     }
1302
1303
1304     /*
1305      * Get the OS/2 table
1306      */
1307     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1308
1309     /*
1310      * Look first in the OS/2 table for the foundry, if
1311      * not found here, the various notices will be searched for
1312      * that information, either from the sfnt name tables or
1313      * the Postscript FontInfo dictionary.  Finally, the
1314      * BDF properties will queried.
1315      */
1316
1317     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1318         foundry = FcVendorFoundry(os2->achVendID);
1319
1320     if (FcDebug () & FC_DBG_SCANV)
1321         printf ("\n");
1322     /*
1323      * Grub through the name table looking for family
1324      * and style names.  FreeType makes quite a hash
1325      * of them
1326      */
1327     snamec = FT_Get_Sfnt_Name_Count (face);
1328     for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
1329     {
1330         if (p < NUM_PLATFORM_ORDER)
1331             platform = platform_order[p];
1332         else
1333             platform = 0xffff;
1334
1335         /*
1336          * Order nameids so preferred names appear first
1337          * in the resulting list
1338          */
1339         for (n = 0; n < NUM_NAMEID_ORDER; n++)
1340         {
1341             nameid = nameid_order[n];
1342
1343             for (snamei = 0; snamei < snamec; snamei++)
1344             {
1345                 FcChar8         *utf8, *pp;
1346                 const FcChar8   *lang;
1347                 const char      *elt = 0, *eltlang = 0;
1348                 int             *np = 0, *nlangp = 0;
1349                 size_t          len;
1350
1351                 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1352                     continue;
1353                 if (sname.name_id != nameid)
1354                     continue;
1355
1356                 /*
1357                  * Sort platforms in preference order, accepting
1358                  * all other platforms last
1359                  */
1360                 if (p < NUM_PLATFORM_ORDER)
1361                 {
1362                     if (sname.platform_id != platform)
1363                         continue;
1364                 }
1365                 else
1366                 {
1367                     unsigned int        sp;
1368
1369                     for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1370                         if (sname.platform_id == platform_order[sp])
1371                             break;
1372                     if (sp != NUM_PLATFORM_ORDER)
1373                         continue;
1374                 }
1375                 utf8 = FcSfntNameTranscode (&sname);
1376                 lang = FcSfntNameLanguage (&sname);
1377
1378                 if (!utf8)
1379                     continue;
1380
1381                 switch (sname.name_id) {
1382 #ifdef TT_NAME_ID_WWS_FAMILY
1383                 case TT_NAME_ID_WWS_FAMILY:
1384 #endif
1385                 case TT_NAME_ID_PREFERRED_FAMILY:
1386                 case TT_NAME_ID_FONT_FAMILY:
1387 #if 0   
1388                 case TT_NAME_ID_UNIQUE_ID:
1389 #endif
1390                     if (FcDebug () & FC_DBG_SCANV)
1391                         printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1392                                 sname.name_id, sname.platform_id,
1393                                 sname.encoding_id, sname.language_id,
1394                                 utf8);
1395
1396                     elt = FC_FAMILY;
1397                     eltlang = FC_FAMILYLANG;
1398                     np = &nfamily;
1399                     nlangp = &nfamily_lang;
1400                     break;
1401                 case TT_NAME_ID_MAC_FULL_NAME:
1402                 case TT_NAME_ID_FULL_NAME:
1403                     if (FcDebug () & FC_DBG_SCANV)
1404                         printf ("found full   (n %2d p %d e %d l 0x%04x) %s\n",
1405                                 sname.name_id, sname.platform_id,
1406                                 sname.encoding_id, sname.language_id,
1407                                 utf8);
1408
1409                     elt = FC_FULLNAME;
1410                     eltlang = FC_FULLNAMELANG;
1411                     np = &nfullname;
1412                     nlangp = &nfullname_lang;
1413                     break;
1414 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1415                 case TT_NAME_ID_WWS_SUBFAMILY:
1416 #endif
1417                 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1418                 case TT_NAME_ID_FONT_SUBFAMILY:
1419                     if (utf8)
1420                     {
1421                         pp = utf8;
1422                         while (*pp == ' ')
1423                             pp++;
1424                         len = strlen ((const char *) pp);
1425                         memmove (utf8, pp, len + 1);
1426                         pp = utf8 + len - 1;
1427                         while (*pp == ' ')
1428                             pp--;
1429                         *(pp + 1) = 0;
1430                     }
1431                     if (FcDebug () & FC_DBG_SCANV)
1432                         printf ("found style  (n %2d p %d e %d l 0x%04x) %s\n",
1433                                 sname.name_id, sname.platform_id,
1434                                 sname.encoding_id, sname.language_id,
1435                                 utf8);
1436
1437                     elt = FC_STYLE;
1438                     eltlang = FC_STYLELANG;
1439                     np = &nstyle;
1440                     nlangp = &nstyle_lang;
1441                     break;
1442                 case TT_NAME_ID_TRADEMARK:
1443                 case TT_NAME_ID_MANUFACTURER:
1444                     /* If the foundry wasn't found in the OS/2 table, look here */
1445                     if(!foundry)
1446                         foundry = FcNoticeFoundry((FT_String *) utf8);
1447                     break;
1448                 }
1449                 if (elt)
1450                 {
1451                     if (FcStringInPatternElement (pat, elt, utf8))
1452                     {
1453                         free (utf8);
1454                         continue;
1455                     }
1456
1457                     /* add new element */
1458                     if (!FcPatternAddString (pat, elt, utf8))
1459                     {
1460                         free (utf8);
1461                         goto bail1;
1462                     }
1463                     free (utf8);
1464                     if (lang)
1465                     {
1466                         /* pad lang list with 'und' to line up with elt */
1467                         while (*nlangp < *np)
1468                         {
1469                             if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "und"))
1470                                 goto bail1;
1471                             ++*nlangp;
1472                         }
1473                         if (!FcPatternAddString (pat, eltlang, lang))
1474                             goto bail1;
1475                         ++*nlangp;
1476                     }
1477                     ++*np;
1478                 }
1479                 else
1480                     free (utf8);
1481             }
1482         }
1483     }
1484
1485     if (!nfamily && face->family_name &&
1486         FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1487     {
1488         if (FcDebug () & FC_DBG_SCANV)
1489             printf ("using FreeType family \"%s\"\n", face->family_name);
1490         if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1491             goto bail1;
1492         ++nfamily;
1493     }
1494
1495     if (!nstyle && face->style_name &&
1496         FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1497     {
1498         if (FcDebug () & FC_DBG_SCANV)
1499             printf ("using FreeType style \"%s\"\n", face->style_name);
1500         if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1501             goto bail1;
1502         ++nstyle;
1503     }
1504
1505     if (!nfamily && file && *file)
1506     {
1507         FcChar8 *start, *end;
1508         FcChar8 *family;
1509         
1510         start = (FcChar8 *) strrchr ((char *) file, '/');
1511         if (start)
1512             start++;
1513         else
1514             start = (FcChar8 *) file;
1515         end = (FcChar8 *) strrchr ((char *) start, '.');
1516         if (!end)
1517             end = start + strlen ((char *) start);
1518         /* freed below */
1519         family = malloc (end - start + 1);
1520         strncpy ((char *) family, (char *) start, end - start);
1521         family[end - start] = '\0';
1522         if (FcDebug () & FC_DBG_SCANV)
1523             printf ("using filename for family %s\n", family);
1524         if (!FcPatternAddString (pat, FC_FAMILY, family))
1525         {
1526             free (family);
1527             goto bail1;
1528         }
1529         free (family);
1530         ++nfamily;
1531     }
1532
1533     /* Add the PostScript name into the cache */
1534     tmp = FT_Get_Postscript_Name (face);
1535     if (!tmp)
1536     {
1537         FcChar8 *family, *familylang = NULL;
1538         size_t len;
1539         int n = 0;
1540
1541         /* Workaround when FT_Get_Postscript_Name didn't give any name.
1542          * try to find out the English family name and convert.
1543          */
1544         while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch)
1545         {
1546             if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0)
1547                 break;
1548             n++;
1549             familylang = NULL;
1550         }
1551         if (!familylang)
1552             n = 0;
1553
1554         if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
1555             goto bail1;
1556         len = strlen ((const char *)family);
1557         /* the literal name in PostScript Language is limited to 127 characters though,
1558          * It is the architectural limit. so assuming 255 characters may works enough.
1559          */
1560         for (i = 0; i < len && i < 255; i++)
1561         {
1562             /* those characters are not allowed to be the literal name in PostScript */
1563             static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n ";
1564
1565             if (strchr(exclusive_chars, family[i]) != NULL)
1566                 psname[i] = '-';
1567             else
1568                 psname[i] = family[i];
1569         }
1570         psname[i] = 0;
1571     }
1572     else
1573     {
1574         strncpy (psname, tmp, 255);
1575         psname[255] = 0;
1576     }
1577     if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname))
1578         goto bail1;
1579
1580     if (file && *file && !FcPatternAddString (pat, FC_FILE, file))
1581         goto bail1;
1582
1583     if (!FcPatternAddInteger (pat, FC_INDEX, id))
1584         goto bail1;
1585
1586 #if 0
1587     /*
1588      * don't even try this -- CJK 'monospace' fonts are really
1589      * dual width, and most other fonts don't bother to set
1590      * the attribute.  Sigh.
1591      */
1592     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1593         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1594             goto bail1;
1595 #endif
1596
1597     /*
1598      * Find the font revision (if available)
1599      */
1600     head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1601     if (head)
1602     {
1603         if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1604             goto bail1;
1605     }
1606     else
1607     {
1608         if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1609             goto bail1;
1610     }
1611
1612     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1613     {
1614         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1615         {
1616             FT_ULong    bits;
1617             int         bit;
1618             if (FcCodePageRange[i].bit < 32)
1619             {
1620                 bits = os2->ulCodePageRange1;
1621                 bit = FcCodePageRange[i].bit;
1622             }
1623             else
1624             {
1625                 bits = os2->ulCodePageRange2;
1626                 bit = FcCodePageRange[i].bit - 32;
1627             }
1628             if (bits & (1 << bit))
1629             {
1630                 /*
1631                  * If the font advertises support for multiple
1632                  * "exclusive" languages, then include support
1633                  * for any language found to have coverage
1634                  */
1635                 if (exclusiveLang)
1636                 {
1637                     exclusiveLang = 0;
1638                     break;
1639                 }
1640                 exclusiveLang = FcCodePageRange[i].lang;
1641             }
1642         }
1643     }
1644
1645     if (os2 && os2->version != 0xffff)
1646     {
1647         weight = FcWeightFromOpenType (os2->usWeightClass);
1648         if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1649             printf ("\tos2 weight class %d maps to weight %d\n",
1650                     os2->usWeightClass, weight);
1651
1652         switch (os2->usWidthClass) {
1653         case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1654         case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1655         case 3: width = FC_WIDTH_CONDENSED; break;
1656         case 4: width = FC_WIDTH_SEMICONDENSED; break;
1657         case 5: width = FC_WIDTH_NORMAL; break;
1658         case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1659         case 7: width = FC_WIDTH_EXPANDED; break;
1660         case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1661         case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1662         }
1663         if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1664             printf ("\tos2 width class %d maps to width %d\n",
1665                     os2->usWidthClass, width);
1666     }
1667     if (os2 && (complex_ = FcFontCapabilities(face)))
1668     {
1669         if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
1670         {
1671             free (complex_);
1672             goto bail1;
1673         }
1674         free (complex_);
1675     }
1676
1677 #if defined (HAVE_TT_OS2_USUPPEROPTICALPOINTSIZE) && defined (HAVE_TT_OS2_USLOWEROPTICALPOINTSIZE)
1678     if (os2 && os2->version >= 0x0005 && os2->version != 0xffff)
1679     {
1680         /* usLowerPointSize and usUpperPointSize is actually twips */
1681         lower_size = os2->usLowerOpticalPointSize / 20.0L;
1682         upper_size = os2->usUpperOpticalPointSize / 20.0L;
1683     }
1684 #endif
1685     if (os2)
1686     {
1687         r = FcRangeCreateDouble (lower_size, upper_size);
1688         if (!FcPatternAddRange (pat, FC_SIZE, r))
1689         {
1690             FcRangeDestroy (r);
1691             goto bail1;
1692         }
1693         FcRangeDestroy (r);
1694     }
1695     else
1696     {
1697         for (i = 0; i < face->num_fixed_sizes; i++)
1698         {
1699             double d = FcGetPixelSize (face, i);
1700             r = FcRangeCreateDouble (d, d);
1701             if (!FcPatternAddRange (pat, FC_SIZE, r))
1702             {
1703                 FcRangeDestroy (r);
1704                 goto bail1;
1705             }
1706             FcRangeDestroy (r);
1707         }
1708     }
1709
1710     /*
1711      * Type 1: Check for FontInfo dictionary information
1712      * Code from g2@magestudios.net (Gerard Escalante)
1713      */
1714
1715 #if HAVE_FT_GET_PS_FONT_INFO
1716     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1717     {
1718         if (weight == -1 && psfontinfo.weight)
1719         {
1720             weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1721             if (FcDebug() & FC_DBG_SCANV)
1722                 printf ("\tType1 weight %s maps to %d\n",
1723                         psfontinfo.weight, weight);
1724         }
1725
1726 #if 0
1727         /*
1728          * Don't bother with italic_angle; FreeType already extracts that
1729          * information for us and sticks it into style_flags
1730          */
1731         if (psfontinfo.italic_angle)
1732             slant = FC_SLANT_ITALIC;
1733         else
1734             slant = FC_SLANT_ROMAN;
1735 #endif
1736
1737         if(!foundry)
1738             foundry = FcNoticeFoundry(psfontinfo.notice);
1739     }
1740 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1741
1742 #if HAVE_FT_GET_BDF_PROPERTY
1743     /*
1744      * Finally, look for a FOUNDRY BDF property if no other
1745      * mechanism has managed to locate a foundry
1746      */
1747
1748     if (!foundry)
1749     {
1750         int             rc;
1751         rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1752         if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1753             foundry = (FcChar8 *) prop.u.atom;
1754     }
1755
1756     if (width == -1)
1757     {
1758         if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1759             (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1760              prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1761         {
1762             FT_Int32    value;
1763         
1764             if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1765                 value = prop.u.integer;
1766             else
1767                 value = (FT_Int32) prop.u.cardinal;
1768             switch ((value + 5) / 10) {
1769             case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1770             case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1771             case 3: width = FC_WIDTH_CONDENSED; break;
1772             case 4: width = FC_WIDTH_SEMICONDENSED; break;
1773             case 5: width = FC_WIDTH_NORMAL; break;
1774             case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1775             case 7: width = FC_WIDTH_EXPANDED; break;
1776             case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1777             case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1778             }
1779         }
1780         if (width == -1 &&
1781             FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1782             prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL)
1783         {
1784             width = FcIsWidth ((FcChar8 *) prop.u.atom);
1785             if (FcDebug () & FC_DBG_SCANV)
1786                 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1787         }
1788     }
1789 #endif
1790
1791     /*
1792      * Look for weight, width and slant names in the style value
1793      */
1794     for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1795     {
1796         if (weight == -1)
1797         {
1798             weight = FcContainsWeight (style);
1799             if (FcDebug() & FC_DBG_SCANV)
1800                 printf ("\tStyle %s maps to weight %d\n", style, weight);
1801         }
1802         if (width == -1)
1803         {
1804             width = FcContainsWidth (style);
1805             if (FcDebug() & FC_DBG_SCANV)
1806                 printf ("\tStyle %s maps to width %d\n", style, width);
1807         }
1808         if (slant == -1)
1809         {
1810             slant = FcContainsSlant (style);
1811             if (FcDebug() & FC_DBG_SCANV)
1812                 printf ("\tStyle %s maps to slant %d\n", style, slant);
1813         }
1814         if (decorative == FcFalse)
1815         {
1816             decorative = FcContainsDecorative (style) > 0;
1817             if (FcDebug() & FC_DBG_SCANV)
1818                 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1819         }
1820     }
1821     /*
1822      * Pull default values from the FreeType flags if more
1823      * specific values not found above
1824      */
1825     if (slant == -1)
1826     {
1827         slant = FC_SLANT_ROMAN;
1828         if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1829             slant = FC_SLANT_ITALIC;
1830     }
1831
1832     if (weight == -1)
1833     {
1834         weight = FC_WEIGHT_MEDIUM;
1835         if (face->style_flags & FT_STYLE_FLAG_BOLD)
1836             weight = FC_WEIGHT_BOLD;
1837     }
1838
1839     if (width == -1)
1840         width = FC_WIDTH_NORMAL;
1841
1842     if (foundry == 0)
1843         foundry = (FcChar8 *) "unknown";
1844
1845     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1846         goto bail1;
1847
1848     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1849         goto bail1;
1850
1851     if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1852         goto bail1;
1853
1854     if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1855         goto bail1;
1856
1857     if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1858         goto bail1;
1859
1860
1861     /*
1862      * Compute the unicode coverage for the font
1863      */
1864     cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1865     if (!cs)
1866         goto bail1;
1867
1868 #if HAVE_FT_GET_BDF_PROPERTY
1869     /* For PCF fonts, override the computed spacing with the one from
1870        the property */
1871     if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1872        prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL) {
1873         if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1874             spacing = FC_CHARCELL;
1875         else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1876             spacing = FC_MONO;
1877         else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1878             spacing = FC_PROPORTIONAL;
1879     }
1880 #endif
1881
1882     /*
1883      * Skip over PCF fonts that have no encoded characters; they're
1884      * usually just Unicode fonts transcoded to some legacy encoding
1885      * FT forces us to approximate whether a font is a PCF font
1886      * or not by whether it has any BDF properties.  Try PIXEL_SIZE;
1887      * I don't know how to get a list of BDF properties on the font. -PL
1888      */
1889     if (FcCharSetCount (cs) == 0)
1890     {
1891 #if HAVE_FT_GET_BDF_PROPERTY
1892         if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1893             goto bail2;
1894 #endif
1895     }
1896
1897     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1898         goto bail2;
1899
1900     ls = FcFreeTypeLangSet (cs, exclusiveLang);
1901     if (!ls)
1902         goto bail2;
1903
1904     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1905     {
1906         FcLangSetDestroy (ls);
1907         goto bail2;
1908     }
1909
1910     FcLangSetDestroy (ls);
1911
1912     if (spacing != FC_PROPORTIONAL)
1913         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1914             goto bail2;
1915
1916     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1917     {
1918         for (i = 0; i < face->num_fixed_sizes; i++)
1919             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1920                                      FcGetPixelSize (face, i)))
1921                 goto bail2;
1922         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1923             goto bail2;
1924     }
1925 #if HAVE_FT_GET_X11_FONT_FORMAT
1926     /*
1927      * Use the (not well documented or supported) X-specific function
1928      * from FreeType to figure out the font format
1929      */
1930     {
1931         const char *font_format = FT_Get_X11_Font_Format (face);
1932         if (font_format)
1933             if (!FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format))
1934                 goto bail2;
1935     }
1936 #endif
1937
1938     /*
1939      * Drop our reference to the charset
1940      */
1941     FcCharSetDestroy (cs);
1942
1943     return pat;
1944
1945 bail2:
1946     FcCharSetDestroy (cs);
1947 bail1:
1948     FcPatternDestroy (pat);
1949 bail0:
1950     return NULL;
1951 }
1952
1953 FcPattern *
1954 FcFreeTypeQuery(const FcChar8   *file,
1955                 int             id,
1956                 FcBlanks        *blanks,
1957                 int             *count)
1958 {
1959     FT_Face         face;
1960     FT_Library      ftLibrary;
1961     FcPattern       *pat = NULL;
1962
1963     if (FT_Init_FreeType (&ftLibrary))
1964         return NULL;
1965
1966     if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1967         goto bail;
1968
1969     *count = face->num_faces;
1970
1971     pat = FcFreeTypeQueryFace (face, file, id, blanks);
1972
1973     FT_Done_Face (face);
1974 bail:
1975     FT_Done_FreeType (ftLibrary);
1976     return pat;
1977 }
1978
1979 /*
1980  * For our purposes, this approximation is sufficient
1981  */
1982 #if !HAVE_FT_GET_NEXT_CHAR
1983 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1984                                           (*(gi) = 0), 0 : \
1985                                           (*(gi) = 1), (ucs4) + 1)
1986 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1987 #endif
1988
1989 static const FT_Encoding fcFontEncodings[] = {
1990     FT_ENCODING_UNICODE,
1991     FT_ENCODING_MS_SYMBOL
1992 };
1993
1994 #define NUM_DECODE  (int) (sizeof (fcFontEncodings) / sizeof (fcFontEncodings[0]))
1995
1996 static const FcChar32   prefer_unicode[] = {
1997     0x20ac,     /* EURO SIGN */
1998 };
1999
2000 #include "../fc-glyphname/fcglyphname.h"
2001
2002 static FcChar32
2003 FcHashGlyphName (const FcChar8 *name)
2004 {
2005     FcChar32    h = 0;
2006     FcChar8     c;
2007
2008     while ((c = *name++))
2009     {
2010         h = ((h << 1) | (h >> 31)) ^ c;
2011     }
2012     return h;
2013 }
2014
2015 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2016 /*
2017  * Use Type1 glyph names for fonts which have reliable names
2018  * and which export an Adobe Custom mapping
2019  */
2020 static FcBool
2021 FcFreeTypeUseNames (FT_Face face)
2022 {
2023     FT_Int  map;
2024
2025     if (!FT_Has_PS_Glyph_Names (face))
2026         return FcFalse;
2027     for (map = 0; map < face->num_charmaps; map++)
2028         if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2029             return FcTrue;
2030     return FcFalse;
2031 }
2032
2033 static const FcChar8 *
2034 FcUcs4ToGlyphName (FcChar32 ucs4)
2035 {
2036     int         i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2037     int         r = 0;
2038     FcGlyphId   gn;
2039
2040     while ((gn = _fc_ucs_to_name[i]) != -1)
2041     {
2042         if (_fc_glyph_names[gn].ucs == ucs4)
2043             return _fc_glyph_names[gn].name;
2044         if (!r)
2045         {
2046             r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2047             if (!r)
2048                 r = 1;
2049         }
2050         i += r;
2051         if (i >= FC_GLYPHNAME_HASH)
2052             i -= FC_GLYPHNAME_HASH;
2053     }
2054     return 0;
2055 }
2056
2057 static FcChar32
2058 FcGlyphNameToUcs4 (FcChar8 *name)
2059 {
2060     FcChar32    h = FcHashGlyphName (name);
2061     int         i = (int) (h % FC_GLYPHNAME_HASH);
2062     int         r = 0;
2063     FcGlyphId   gn;
2064
2065     while ((gn = _fc_name_to_ucs[i]) != -1)
2066     {
2067         if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name))
2068             return _fc_glyph_names[gn].ucs;
2069         if (!r)
2070         {
2071             r = (int) (h % FC_GLYPHNAME_REHASH);
2072             if (!r)
2073                 r = 1;
2074         }
2075         i += r;
2076         if (i >= FC_GLYPHNAME_HASH)
2077             i -= FC_GLYPHNAME_HASH;
2078     }
2079     return 0xffff;
2080 }
2081
2082 /*
2083  * Work around a bug in some FreeType versions which fail
2084  * to correctly bounds check glyph name buffers and overwrite
2085  * the stack. As Postscript names have a limit of 127 characters,
2086  * this should be sufficient.
2087  */
2088
2089 #if FC_GLYPHNAME_MAXLEN < 127
2090 # define FC_GLYPHNAME_BUFLEN 127
2091 #else
2092 # define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2093 #endif
2094
2095 /*
2096  * Search through a font for a glyph by name.  This is
2097  * currently a linear search as there doesn't appear to be
2098  * any defined order within the font
2099  */
2100 static FT_UInt
2101 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2102 {
2103     FT_UInt gindex;
2104     FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2105
2106     for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2107     {
2108         if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2109             if (!strcmp ((char *) name, (char *) name_buf))
2110                 return gindex;
2111     }
2112     return 0;
2113 }
2114 #endif
2115
2116 /*
2117  * Map a UCS4 glyph to a glyph index.  Use all available encoding
2118  * tables to try and find one that works.  This information is expected
2119  * to be cached by higher levels, so performance isn't critical
2120  */
2121
2122 FT_UInt
2123 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2124 {
2125     int             initial, offset, decode;
2126     FT_UInt         glyphindex;
2127
2128     initial = 0;
2129
2130     if (!face)
2131         return 0;
2132
2133     /*
2134      * Find the current encoding
2135      */
2136     if (face->charmap)
2137     {
2138         for (; initial < NUM_DECODE; initial++)
2139             if (fcFontEncodings[initial] == face->charmap->encoding)
2140                 break;
2141         if (initial == NUM_DECODE)
2142             initial = 0;
2143     }
2144     /*
2145      * Check each encoding for the glyph, starting with the current one
2146      */
2147     for (offset = 0; offset < NUM_DECODE; offset++)
2148     {
2149         decode = (initial + offset) % NUM_DECODE;
2150         if (!face->charmap || face->charmap->encoding != fcFontEncodings[decode])
2151             if (FT_Select_Charmap (face, fcFontEncodings[decode]) != 0)
2152                 continue;
2153         glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4);
2154         if (glyphindex)
2155             return glyphindex;
2156     }
2157 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2158     /*
2159      * Check postscript name table if present
2160      */
2161     if (FcFreeTypeUseNames (face))
2162     {
2163         const FcChar8   *name = FcUcs4ToGlyphName (ucs4);
2164         if (name)
2165         {
2166             glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2167             if (glyphindex)
2168                 return glyphindex;
2169         }
2170     }
2171 #endif
2172     return 0;
2173 }
2174
2175 static FcBool
2176 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2177                       FT_UInt glyph, FcBlanks *blanks,
2178                       FT_Pos *advance,
2179                       FcBool using_strike)
2180 {
2181     FT_Int          load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2182     FT_GlyphSlot    slot;
2183
2184     if (using_strike)
2185         load_flags &= ~FT_LOAD_NO_SCALE;
2186
2187     /*
2188      * When using scalable fonts, only report those glyphs
2189      * which can be scaled; otherwise those fonts will
2190      * only be available at some sizes, and never when
2191      * transformed.  Avoid this by simply reporting bitmap-only
2192      * glyphs as missing
2193      */
2194     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2195         load_flags |= FT_LOAD_NO_BITMAP;
2196
2197     if (FT_Load_Glyph (face, glyph, load_flags))
2198         return FcFalse;
2199
2200     slot = face->glyph;
2201     if (!glyph)
2202         return FcFalse;
2203
2204     *advance = slot->metrics.horiAdvance;
2205
2206     switch ((int) slot->format) {
2207     case ft_glyph_format_bitmap:
2208         /*
2209          * Bitmaps are assumed to be reasonable; if
2210          * this proves to be a rash assumption, this
2211          * code can be easily modified
2212          */
2213         return FcTrue;
2214     case ft_glyph_format_outline:
2215         /*
2216          * Glyphs with contours are always OK
2217          */
2218         if (slot->outline.n_contours != 0)
2219             return FcTrue;
2220         /*
2221          * Glyphs with no contours are only OK if
2222          * they're members of the Blanks set specified
2223          * in the configuration.  If blanks isn't set,
2224          * then allow any glyph to be blank
2225          */
2226         if (!blanks || FcBlanksIsMember (blanks, ucs4))
2227             return FcTrue;
2228         /* fall through ... */
2229     default:
2230         break;
2231     }
2232     return FcFalse;
2233 }
2234
2235 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2236
2237 static FcCharSet *
2238 FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index)
2239 {
2240     FcChar32        page, off, ucs4;
2241 #ifdef CHECK
2242     FcChar32        font_max = 0;
2243 #endif
2244     FcCharSet       *fcs;
2245     FcCharLeaf      *leaf;
2246     int             o;
2247     FT_UInt         glyph;
2248     FT_Pos          advance, advance_one = 0, advance_two = 0;
2249     FcBool          has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2250     FcBool          using_strike = FcFalse;
2251
2252     fcs = FcCharSetCreate ();
2253     if (!fcs)
2254         goto bail0;
2255
2256 #if HAVE_FT_SELECT_SIZE
2257     if (strike_index >= 0) {
2258         if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
2259             goto bail1;
2260         using_strike = FcTrue;
2261     }
2262 #endif
2263
2264 #ifdef CHECK
2265     printf ("Family %s style %s\n", face->family_name, face->style_name);
2266 #endif
2267     for (o = 0; o < NUM_DECODE; o++)
2268     {
2269         if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
2270             continue;
2271
2272         {
2273             page = ~0;
2274             leaf = NULL;
2275             ucs4 = FT_Get_First_Char (face, &glyph);
2276             while (glyph != 0)
2277             {
2278                 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2279                 {
2280                     if (advance)
2281                     {
2282                         if (!has_advance)
2283                         {
2284                             has_advance = FcTrue;
2285                             advance_one = advance;
2286                         }
2287                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2288                         {
2289                             if (fixed_advance)
2290                             {
2291                                 dual_advance = FcTrue;
2292                                 fixed_advance = FcFalse;
2293                                 advance_two = advance;
2294                             }
2295                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2296                                 dual_advance = FcFalse;
2297                         }
2298                     }
2299
2300                     if ((ucs4 >> 8) != page)
2301                     {
2302                         page = (ucs4 >> 8);
2303                         leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2304                         if (!leaf)
2305                             goto bail1;
2306                     }
2307                     off = ucs4 & 0xff;
2308                     leaf->map[off >> 5] |= (1 << (off & 0x1f));
2309 #ifdef CHECK
2310                     if (ucs4 > font_max)
2311                         font_max = ucs4;
2312 #endif
2313                 }
2314                 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2315             }
2316 #ifdef CHECK
2317             for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2318             {
2319                 FcBool      FT_Has, FC_Has;
2320
2321                 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2322                 FC_Has = FcCharSetHasChar (fcs, ucs4);
2323                 if (FT_Has != FC_Has)
2324                 {
2325                     printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2326                 }
2327             }
2328 #endif
2329         }
2330     }
2331 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2332     /*
2333      * Add mapping from PS glyph names if available
2334      */
2335     if (FcFreeTypeUseNames (face))
2336     {
2337         FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2338
2339         for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2340         {
2341             if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2342             {
2343                 ucs4 = FcGlyphNameToUcs4 (name_buf);
2344                 if (ucs4 != 0xffff &&
2345                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2346                 {
2347                     if (advance)
2348                     {
2349                         if (!has_advance)
2350                         {
2351                             has_advance = FcTrue;
2352                             advance_one = advance;
2353                         }
2354                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2355                         {
2356                             if (fixed_advance)
2357                             {
2358                                 dual_advance = FcTrue;
2359                                 fixed_advance = FcFalse;
2360                                 advance_two = advance;
2361                             }
2362                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2363                                 dual_advance = FcFalse;
2364                         }
2365                     }
2366                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2367                     if (!leaf)
2368                         goto bail1;
2369                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2370 #ifdef CHECK
2371                     if (ucs4 > font_max)
2372                         font_max = ucs4;
2373 #endif
2374                 }
2375             }
2376         }
2377     }
2378 #endif
2379 #ifdef CHECK
2380     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2381     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2382     {
2383         FcBool  has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2384         FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
2385
2386         if (has_char && !has_bit)
2387         {
2388             if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2389                 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2390             else
2391                 printf ("Bitmap missing char 0x%x\n", ucs4);
2392         }
2393         else if (!has_char && has_bit)
2394             printf ("Bitmap extra char 0x%x\n", ucs4);
2395     }
2396 #endif
2397     if (fixed_advance)
2398         *spacing = FC_MONO;
2399     else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2400         *spacing = FC_DUAL;
2401     else
2402         *spacing = FC_PROPORTIONAL;
2403     return fcs;
2404 bail1:
2405     FcCharSetDestroy (fcs);
2406 bail0:
2407     return 0;
2408 }
2409
2410 FcCharSet *
2411 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2412 {
2413     FcCharSet   *cs;
2414
2415     /*
2416      * Check for bitmap-only ttf fonts that are missing the glyf table.
2417      * In that case, pick a size and look for glyphs in that size instead
2418      */
2419     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
2420         face->num_fixed_sizes > 0 &&
2421         FT_Get_Sfnt_Table (face, ft_sfnt_head))
2422     {
2423         FT_Int  strike_index = 0;
2424         int         i;
2425
2426         /* Select the face closest to 16 pixels tall */
2427         for (i = 1; i < face->num_fixed_sizes; i++) {
2428             if (abs (face->available_sizes[i].height - 16) <
2429                 abs (face->available_sizes[strike_index].height - 16))
2430                 strike_index = i;
2431         }
2432         cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index);
2433     }
2434     else
2435         cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1);
2436     return cs;
2437 }
2438
2439 FcCharSet *
2440 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2441 {
2442     int spacing;
2443
2444     return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2445 }
2446
2447
2448 #define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2449 #define TTAG_GSUB  FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2450 #define TTAG_SILF  FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2451
2452 #define OTLAYOUT_HEAD       "otlayout:"
2453 #define OTLAYOUT_HEAD_LEN   9
2454 #define OTLAYOUT_ID_LEN     4
2455 /* space + head + id */
2456 #define OTLAYOUT_LEN        (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2457
2458 /*
2459  * This is a bit generous; the registry has only lower case and space
2460  * except for 'DFLT'.
2461  */
2462 #define FcIsSpace(x)        (040 == (x))
2463 #define FcIsDigit(c)        (('0' <= (c) && (c) <= '9'))
2464 #define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(x) || FcIsSpace(x))
2465                         
2466 static void
2467 addtag(FcChar8 *complex_, FT_ULong tag)
2468 {
2469     FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2470
2471     tagstring[0] = (FcChar8)(tag >> 24),
2472     tagstring[1] = (FcChar8)(tag >> 16),
2473     tagstring[2] = (FcChar8)(tag >> 8),
2474     tagstring[3] = (FcChar8)(tag);
2475     tagstring[4] = '\0';
2476
2477     /* skip tags which aren't alphanumeric, under the assumption that
2478      * they're probably broken
2479      */
2480     if (!FcIsValidScript(tagstring[0]) ||
2481         !FcIsValidScript(tagstring[1]) ||
2482         !FcIsValidScript(tagstring[2]) ||
2483         !FcIsValidScript(tagstring[3]))
2484         return;
2485
2486     if (*complex_ != '\0')
2487         strcat ((char *) complex_, " ");
2488     strcat ((char *) complex_, OTLAYOUT_HEAD);
2489     strcat ((char *) complex_, (char *) tagstring);
2490 }
2491
2492 static int
2493 compareulong (const void *a, const void *b)
2494 {
2495     const FT_ULong *ua = (const FT_ULong *) a;
2496     const FT_ULong *ub = (const FT_ULong *) b;
2497     return *ua - *ub;
2498 }
2499
2500
2501 static int
2502 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
2503 {
2504     FT_ULong   cur_offset, new_offset, base_offset;
2505     FT_Stream  stream = face->stream;
2506     FT_Error   error;
2507     FT_UShort  n, p;
2508     int        script_count;
2509
2510     if (!stream)
2511         return 0;
2512
2513     if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2514         return 0;
2515
2516     base_offset = ftglue_stream_pos ( stream );
2517
2518     /* skip version */
2519
2520     if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2521         return 0;
2522
2523     new_offset = GET_UShort() + base_offset;
2524
2525     ftglue_stream_frame_exit( stream );
2526
2527     cur_offset = ftglue_stream_pos( stream );
2528
2529     if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
2530         return 0;
2531
2532     base_offset = ftglue_stream_pos( stream );
2533
2534     if ( ftglue_stream_frame_enter( stream, 2L ) )
2535         return 0;
2536
2537     script_count = GET_UShort ();
2538
2539     ftglue_stream_frame_exit( stream );
2540
2541     *stags = malloc(script_count * sizeof (FT_ULong));
2542     if (!stags)
2543         return 0;
2544
2545     p = 0;
2546     for ( n = 0; n < script_count; n++ )
2547     {
2548         if ( ftglue_stream_frame_enter( stream, 6L ) )
2549             goto Fail;
2550
2551         (*stags)[p] = GET_ULong ();
2552         new_offset = GET_UShort () + base_offset;
2553
2554         ftglue_stream_frame_exit( stream );
2555
2556         cur_offset = ftglue_stream_pos( stream );
2557
2558         error = ftglue_stream_seek( stream, new_offset );
2559
2560         if ( error == FT_Err_Ok )
2561             p++;
2562
2563         (void)ftglue_stream_seek( stream, cur_offset );
2564     }
2565
2566     if (!p)
2567         goto Fail;
2568
2569     /* sort the tag list before returning it */
2570     qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
2571
2572     return script_count;
2573
2574 Fail:
2575     free(*stags);
2576     *stags = NULL;
2577     return 0;
2578 }
2579
2580 static FcChar8 *
2581 FcFontCapabilities(FT_Face face)
2582 {
2583     FcBool issilgraphitefont = 0;
2584     FT_Error err;
2585     FT_ULong len = 0;
2586     FT_ULong *gsubtags=NULL, *gpostags=NULL;
2587     FT_UShort gsub_count=0, gpos_count=0;
2588     FT_ULong maxsize;
2589     FcChar8 *complex_ = NULL;
2590     int indx1 = 0, indx2 = 0;
2591
2592     err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2593     issilgraphitefont = ( err == FT_Err_Ok);
2594
2595     gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
2596     gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
2597
2598     if (!issilgraphitefont && !gsub_count && !gpos_count)
2599         goto bail;
2600
2601     maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2602                (issilgraphitefont ? 13 : 0));
2603     complex_ = malloc (sizeof (FcChar8) * maxsize);
2604     if (!complex_)
2605         goto bail;
2606
2607     complex_[0] = '\0';
2608     if (issilgraphitefont)
2609         strcpy((char *) complex_, "ttable:Silf ");
2610
2611     while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2612         if (indx1 == gsub_count) {
2613             addtag(complex_, gpostags[indx2]);
2614             indx2++;
2615         } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2616             addtag(complex_, gsubtags[indx1]);
2617             indx1++;
2618         } else if (gsubtags[indx1] == gpostags[indx2]) {
2619             addtag(complex_, gsubtags[indx1]);
2620             indx1++;
2621             indx2++;
2622         } else {
2623             addtag(complex_, gpostags[indx2]);
2624             indx2++;
2625         }
2626     }
2627     if (FcDebug () & FC_DBG_SCANV)
2628         printf("complex_ features in this font: %s\n", complex_);
2629 bail:
2630     free(gsubtags);
2631     free(gpostags);
2632     return complex_;
2633 }
2634
2635 #define __fcfreetype__
2636 #include "fcaliastail.h"
2637 #include "fcftaliastail.h"
2638 #undef __fcfreetype__