Minor
[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 #if USE_ICONV
562 #include <iconv.h>
563 #endif
564
565 /*
566  * A shift-JIS will have many high bits turned on
567  */
568 static FcBool
569 FcLooksLikeSJIS (FcChar8 *string, int len)
570 {
571     int     nhigh = 0, nlow = 0;
572
573     while (len-- > 0)
574     {
575         if (*string++ & 0x80) nhigh++;
576         else nlow++;
577     }
578     /*
579      * Heuristic -- if more than 1/3 of the bytes have the high-bit set,
580      * this is likely to be SJIS and not ROMAN
581      */
582     if (nhigh * 2 > nlow)
583         return FcTrue;
584     return FcFalse;
585 }
586
587 static FcChar8 *
588 FcSfntNameTranscode (FT_SfntName *sname)
589 {
590     int        i;
591     const char *fromcode;
592 #if USE_ICONV
593     iconv_t cd;
594 #endif
595     FcChar8 *utf8;
596
597     for (i = 0; i < NUM_FC_FT_ENCODING; i++)
598         if (fcFtEncoding[i].platform_id == sname->platform_id &&
599             (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
600              fcFtEncoding[i].encoding_id == sname->encoding_id))
601             break;
602     if (i == NUM_FC_FT_ENCODING)
603         return 0;
604     fromcode = fcFtEncoding[i].fromcode;
605
606     /*
607      * Many names encoded for TT_PLATFORM_MACINTOSH are broken
608      * in various ways. Kludge around them.
609      */
610     if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
611     {
612         if (sname->language_id == TT_MAC_LANGID_ENGLISH &&
613             FcLooksLikeSJIS (sname->string, sname->string_len))
614         {
615             fromcode = "SJIS";
616         }
617         else if (sname->language_id >= 0x100)
618         {
619             /*
620              * "real" Mac language IDs are all less than 150.
621              * Names using one of the MS language IDs are assumed
622              * to use an associated encoding (Yes, this is a kludge)
623              */
624             int f;
625
626             fromcode = NULL;
627             for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
628                 if (fcMacRomanFake[f].language_id == sname->language_id)
629                 {
630                     fromcode = fcMacRomanFake[f].fromcode;
631                     break;
632                 }
633             if (!fromcode)
634                 return 0;
635         }
636     }
637     if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
638     {
639         FcChar8     *src = sname->string;
640         int         src_len = sname->string_len;
641         int         len;
642         int         wchar;
643         int         ilen, olen;
644         FcChar8     *u8;
645         FcChar32    ucs4;
646         
647         /*
648          * Convert Utf16 to Utf8
649          */
650
651         if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
652             return 0;
653
654         /*
655          * Allocate plenty of space.  Freed below
656          */
657         utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
658         if (!utf8)
659             return 0;
660
661         u8 = utf8;
662
663         while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
664         {
665             src_len -= ilen;
666             src += ilen;
667             olen = FcUcs4ToUtf8 (ucs4, u8);
668             u8 += olen;
669         }
670         *u8 = '\0';
671         goto done;
672     }
673     if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
674     {
675         FcChar8     *src = sname->string;
676         int         src_len = sname->string_len;
677         int         olen;
678         FcChar8     *u8;
679         FcChar32    ucs4;
680         
681         /*
682          * Convert Latin1 to Utf8. Freed below
683          */
684         utf8 = malloc (src_len * 2 + 1);
685         if (!utf8)
686             return 0;
687
688         u8 = utf8;
689         while (src_len > 0)
690         {
691             ucs4 = *src++;
692             src_len--;
693             olen = FcUcs4ToUtf8 (ucs4, u8);
694             u8 += olen;
695         }
696         *u8 = '\0';
697         goto done;
698     }
699 #if USE_ICONV
700     cd = iconv_open ("UTF-8", fromcode);
701     if (cd && cd != (iconv_t) (-1))
702     {
703         size_t      in_bytes_left = sname->string_len;
704         size_t      out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
705         char        *inbuf, *outbuf;
706         
707         utf8 = malloc (out_bytes_left + 1);
708         if (!utf8)
709         {
710             iconv_close (cd);
711             return 0;
712         }
713         
714         outbuf = (char *) utf8;
715         inbuf = (char *) sname->string;
716         
717         while (in_bytes_left)
718         {
719             size_t      did = iconv (cd,
720                                  &inbuf, &in_bytes_left,
721                                  &outbuf, &out_bytes_left);
722             if (did == (size_t) (-1))
723             {
724                 iconv_close (cd);
725                 free (utf8);
726                 return 0;
727             }
728         }
729         iconv_close (cd);
730         *outbuf = '\0';
731         goto done;
732     }
733 #endif
734     return 0;
735 done:
736     if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
737     {
738         free (utf8);
739         return 0;
740     }
741     return utf8;
742 }
743
744 static const FcChar8 *
745 FcSfntNameLanguage (FT_SfntName *sname)
746 {
747     int i;
748     FT_UShort   platform_id = sname->platform_id;
749     FT_UShort   language_id = sname->language_id;
750
751     /*
752      * Many names encoded for TT_PLATFORM_MACINTOSH are broken
753      * in various ways. Kludge around them.
754      */
755     if (platform_id == TT_PLATFORM_MACINTOSH &&
756         sname->encoding_id == TT_MAC_ID_ROMAN &&
757         FcLooksLikeSJIS (sname->string, sname->string_len))
758     {
759         language_id = TT_MAC_LANGID_JAPANESE;
760     }
761
762     for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
763         if (fcFtLanguage[i].platform_id == platform_id &&
764             (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
765              fcFtLanguage[i].language_id == language_id))
766         {
767             if (fcFtLanguage[i].lang[0] == '\0')
768               return NULL;
769             else
770               return (FcChar8 *) fcFtLanguage[i].lang;
771         }
772     return 0;
773 }
774
775 /* Order is significant.  For example, some B&H fonts are hinted by
776    URW++, and both strings appear in the notice. */
777
778 static const char notice_foundry_data[] =
779         "Bigelow\0b&h\0"
780         "Adobe\0adobe\0"
781         "Bitstream\0bitstream\0"
782         "Monotype\0monotype\0"
783         "Linotype\0linotype\0"
784         "LINOTYPE-HELL\0linotype\0"
785         "IBM\0ibm\0"
786         "URW\0urw\0"
787         "International Typeface Corporation\0itc\0"
788         "Tiro Typeworks\0tiro\0"
789         "XFree86\0xfree86\0"
790         "Microsoft\0microsoft\0"
791         "Omega\0omega\0"
792         "Font21\0hwan\0"
793         "HanYang System\0hanyang";
794
795 struct _notice_foundry {
796     /* these are the offsets into the
797      * notice_foundry_data array.
798      */
799     unsigned char notice_offset;
800     unsigned char foundry_offset;
801 };
802
803 static const struct _notice_foundry FcNoticeFoundries[] = {
804     { 0, 8 },
805     { 12, 18 },
806     { 24, 34 },
807     { 44, 53 },
808     { 62, 71 },
809     { 80, 94 },
810     { 103, 107 },
811     { 111, 115 },
812     { 119, 154 },
813     { 158, 173 },
814     { 178, 186 },
815     { 194, 204 },
816     { 214, 220 },
817     { 226, 233 },
818     { 238, 253 }
819 };
820
821 #define NUM_NOTICE_FOUNDRIES    (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
822
823 static const FcChar8 *
824 FcNoticeFoundry(const FT_String *notice)
825 {
826     int i;
827
828     if (notice)
829         for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
830         {
831             const struct _notice_foundry *nf = &FcNoticeFoundries[i];
832             const char *n = notice_foundry_data + nf->notice_offset;
833             const char *f = notice_foundry_data + nf->foundry_offset;
834
835             if (strstr ((const char *) notice, n))
836                 return (const FcChar8 *) f;
837         }
838     return 0;
839 }
840
841 static FcBool
842 FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
843 {
844     /* vendor is not necessarily NUL-terminated. */
845     int i, len;
846
847     len = strlen((char *) vendor_string);
848     if (memcmp(vendor, vendor_string, len) != 0)
849         return FcFalse;
850     for (i = len; i < 4; i++)
851         if (vendor[i] != ' ' && vendor[i] != '\0')
852             return FcFalse;
853     return FcTrue;
854 }
855
856 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
857
858 /* It should not contain useless entries (such as UNKN) nor duplicate
859    entries for padding both with spaces and NULs. */
860
861 static const struct {
862     const FT_Char   vendor[5];
863     const FcChar8   foundry[13];
864 } FcVendorFoundries[] = {
865     { "ADBE", "adobe"},
866     { "AGFA", "agfa"},
867     { "ALTS", "altsys"},
868     { "APPL", "apple"},
869     { "ARPH", "arphic"},
870     { "ATEC", "alltype"},
871     { "B&H",  "b&h"},
872     { "BITS", "bitstream"},
873     { "CANO", "cannon"},
874     { "DYNA", "dynalab"},
875     { "EPSN", "epson"},
876     { "FJ",   "fujitsu"},
877     { "IBM",  "ibm"},
878     { "ITC",  "itc"},
879     { "IMPR", "impress"},
880     { "LARA", "larabiefonts"},
881     { "LEAF", "interleaf"},
882     { "LETR", "letraset"},
883     { "LINO", "linotype"},
884     { "MACR", "macromedia"},
885     { "MONO", "monotype"},
886     { "MS",   "microsoft"},
887     { "MT",   "monotype"},
888     { "NEC",  "nec"},
889     { "PARA", "paratype"},
890     { "QMSI", "qms"},
891     { "RICO", "ricoh"},
892     { "URW",  "urw"},
893     { "Y&Y",  "y&y"}
894 };
895
896 #define NUM_VENDOR_FOUNDRIES    (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
897
898 static const FcChar8 *
899 FcVendorFoundry(const FT_Char vendor[4])
900 {
901     int i;
902
903     if (vendor)
904         for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
905             if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
906                 return FcVendorFoundries[i].foundry;
907     return 0;
908 }
909
910 typedef struct _FcStringConst {
911     const FcChar8   *name;
912     int             value;
913 } FcStringConst;
914
915 static int
916 FcStringIsConst (const FcChar8          *string,
917                  const FcStringConst    *c,
918                  int                    nc)
919 {
920     int i;
921
922     for (i = 0; i < nc; i++)
923         if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
924             return c[i].value;
925     return -1;
926 }
927
928 static int
929 FcStringContainsConst (const FcChar8        *string,
930                        const FcStringConst  *c,
931                        int                  nc)
932 {
933     int i;
934
935     for (i = 0; i < nc; i++)
936     {
937         if (c[i].name[0] == '<')
938         {
939             if (FcStrContainsWord (string, c[i].name + 1))
940                 return c[i].value;
941         }
942         else
943         {
944             if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
945                 return c[i].value;
946         }
947     }
948     return -1;
949 }
950
951 typedef FcChar8 *FC8;
952
953 static const FcStringConst  weightConsts[] = {
954     { (FC8) "thin",             FC_WEIGHT_THIN },
955     { (FC8) "extralight",       FC_WEIGHT_EXTRALIGHT },
956     { (FC8) "ultralight",       FC_WEIGHT_ULTRALIGHT },
957     { (FC8) "light",            FC_WEIGHT_LIGHT },
958     { (FC8) "book",             FC_WEIGHT_BOOK },
959     { (FC8) "regular",          FC_WEIGHT_REGULAR },
960     { (FC8) "normal",           FC_WEIGHT_NORMAL },
961     { (FC8) "medium",           FC_WEIGHT_MEDIUM },
962     { (FC8) "demibold",         FC_WEIGHT_DEMIBOLD },
963     { (FC8) "demi",             FC_WEIGHT_DEMIBOLD },
964     { (FC8) "semibold",         FC_WEIGHT_SEMIBOLD },
965     { (FC8) "extrabold",        FC_WEIGHT_EXTRABOLD },
966     { (FC8) "superbold",        FC_WEIGHT_EXTRABOLD },
967     { (FC8) "ultrabold",        FC_WEIGHT_ULTRABOLD },
968     { (FC8) "bold",             FC_WEIGHT_BOLD },
969     { (FC8) "ultrablack",       FC_WEIGHT_ULTRABLACK },
970     { (FC8) "superblack",       FC_WEIGHT_EXTRABLACK },
971     { (FC8) "extrablack",       FC_WEIGHT_EXTRABLACK },
972     { (FC8) "<ultra",           FC_WEIGHT_ULTRABOLD }, /* only if a word */
973     { (FC8) "black",            FC_WEIGHT_BLACK },
974     { (FC8) "heavy",            FC_WEIGHT_HEAVY },
975 };
976
977 #define NUM_WEIGHT_CONSTS  (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
978
979 #define FcIsWeight(s)       FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
980 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
981
982 static const FcStringConst  widthConsts[] = {
983     { (FC8) "ultracondensed",   FC_WIDTH_ULTRACONDENSED },
984     { (FC8) "extracondensed",   FC_WIDTH_EXTRACONDENSED },
985     { (FC8) "semicondensed",    FC_WIDTH_SEMICONDENSED },
986     { (FC8) "condensed",        FC_WIDTH_CONDENSED },   /* must be after *condensed */
987     { (FC8) "normal",           FC_WIDTH_NORMAL },
988     { (FC8) "semiexpanded",     FC_WIDTH_SEMIEXPANDED },
989     { (FC8) "extraexpanded",    FC_WIDTH_EXTRAEXPANDED },
990     { (FC8) "ultraexpanded",    FC_WIDTH_ULTRAEXPANDED },
991     { (FC8) "expanded",         FC_WIDTH_EXPANDED },    /* must be after *expanded */
992     { (FC8) "extended",         FC_WIDTH_EXPANDED },
993 };
994
995 #define NUM_WIDTH_CONSTS    (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
996
997 #define FcIsWidth(s)        FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
998 #define FcContainsWidth(s)  FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
999
1000 static const FcStringConst  slantConsts[] = {
1001     { (FC8) "italic",           FC_SLANT_ITALIC },
1002     { (FC8) "kursiv",           FC_SLANT_ITALIC },
1003     { (FC8) "oblique",          FC_SLANT_OBLIQUE },
1004 };
1005
1006 #define NUM_SLANT_CONSTS    (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
1007
1008 #define FcContainsSlant(s)  FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
1009
1010 static const FcStringConst  decorativeConsts[] = {
1011     { (FC8) "shadow",           FcTrue },
1012     { (FC8) "caps",             FcTrue },
1013     { (FC8) "antiqua",          FcTrue },
1014     { (FC8) "romansc",          FcTrue },
1015     { (FC8) "embosed",          FcTrue },
1016     { (FC8) "dunhill",          FcTrue },
1017 };
1018
1019 #define NUM_DECORATIVE_CONSTS   (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
1020
1021 #define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1022
1023 static double
1024 FcGetPixelSize (FT_Face face, int i)
1025 {
1026 #if HAVE_FT_GET_BDF_PROPERTY
1027     if (face->num_fixed_sizes == 1)
1028     {
1029         BDF_PropertyRec prop;
1030         int             rc;
1031
1032         rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
1033         if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1034             return (double) prop.u.integer;
1035     }
1036 #endif
1037 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
1038     return (double) face->available_sizes[i].y_ppem / 64.0;
1039 #else
1040     return (double) face->available_sizes[i].height;
1041 #endif
1042 }
1043
1044 static FcBool
1045 FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
1046 {
1047     int     e;
1048     FcChar8 *old;
1049     for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1050         if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1051         {
1052             return FcTrue;
1053         }
1054     return FcFalse;
1055 }
1056
1057 static const FT_UShort platform_order[] = {
1058     TT_PLATFORM_MICROSOFT,
1059     TT_PLATFORM_APPLE_UNICODE,
1060     TT_PLATFORM_MACINTOSH,
1061 };
1062 #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
1063
1064 static const FT_UShort nameid_order[] = {
1065 #ifdef TT_NAME_ID_WWS_FAMILY
1066     TT_NAME_ID_WWS_FAMILY,
1067 #endif
1068     TT_NAME_ID_PREFERRED_FAMILY,
1069     TT_NAME_ID_FONT_FAMILY,
1070     TT_NAME_ID_MAC_FULL_NAME,
1071     TT_NAME_ID_FULL_NAME,
1072 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1073     TT_NAME_ID_WWS_SUBFAMILY,
1074 #endif
1075     TT_NAME_ID_PREFERRED_SUBFAMILY,
1076     TT_NAME_ID_FONT_SUBFAMILY,
1077     TT_NAME_ID_TRADEMARK,
1078     TT_NAME_ID_MANUFACTURER,
1079 };
1080
1081 #define NUM_NAMEID_ORDER  (sizeof (nameid_order) / sizeof (nameid_order[0]))
1082 FcPattern *
1083 FcFreeTypeQueryFace (const FT_Face  face,
1084                      const FcChar8  *file,
1085                      int            id,
1086                      FcBlanks       *blanks)
1087 {
1088     FcPattern       *pat;
1089     int             slant = -1;
1090     int             weight = -1;
1091     int             width = -1;
1092     FcBool          decorative = FcFalse;
1093     int             i;
1094     FcCharSet       *cs;
1095     FcLangSet       *ls;
1096 #if 0
1097     FcChar8         *family = 0;
1098 #endif
1099     FcChar8         *complex_;
1100     const FcChar8   *foundry = 0;
1101     int             spacing;
1102     TT_OS2          *os2;
1103 #if HAVE_FT_GET_PS_FONT_INFO
1104     PS_FontInfoRec  psfontinfo;
1105 #endif
1106 #if HAVE_FT_GET_BDF_PROPERTY
1107     BDF_PropertyRec prop;
1108 #endif
1109     TT_Header       *head;
1110     const FcChar8   *exclusiveLang = 0;
1111     FT_SfntName     sname;
1112     FT_UInt         snamei, snamec;
1113
1114     int             nfamily = 0;
1115     int             nfamily_lang = 0;
1116     int             nstyle = 0;
1117     int             nstyle_lang = 0;
1118     int             nfullname = 0;
1119     int             nfullname_lang = 0;
1120     unsigned int    p, n;
1121     int             platform, nameid;
1122
1123     FcChar8         *style = 0;
1124     int             st;
1125
1126     pat = FcPatternCreate ();
1127     if (!pat)
1128         goto bail0;
1129
1130     if (!FcPatternAddBool (pat, FC_OUTLINE,
1131                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1132         goto bail1;
1133
1134     if (!FcPatternAddBool (pat, FC_SCALABLE,
1135                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1136         goto bail1;
1137
1138
1139     /*
1140      * Get the OS/2 table
1141      */
1142     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1143
1144     /*
1145      * Look first in the OS/2 table for the foundry, if
1146      * not found here, the various notices will be searched for
1147      * that information, either from the sfnt name tables or
1148      * the Postscript FontInfo dictionary.  Finally, the
1149      * BDF properties will queried.
1150      */
1151
1152     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1153         foundry = FcVendorFoundry(os2->achVendID);
1154
1155     if (FcDebug () & FC_DBG_SCANV)
1156         printf ("\n");
1157     /*
1158      * Grub through the name table looking for family
1159      * and style names.  FreeType makes quite a hash
1160      * of them
1161      */
1162     snamec = FT_Get_Sfnt_Name_Count (face);
1163     for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
1164     {
1165         if (p < NUM_PLATFORM_ORDER)
1166             platform = platform_order[p];
1167         else
1168             platform = 0xffff;
1169
1170         /*
1171          * Order nameids so preferred names appear first
1172          * in the resulting list
1173          */
1174         for (n = 0; n < NUM_NAMEID_ORDER; n++)
1175         {
1176             nameid = nameid_order[n];
1177
1178             for (snamei = 0; snamei < snamec; snamei++)
1179             {
1180                 FcChar8         *utf8, *pp;
1181                 const FcChar8   *lang;
1182                 const char      *elt = 0, *eltlang = 0;
1183                 int             *np = 0, *nlangp = 0;
1184                 size_t          len;
1185
1186                 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1187                     continue;
1188                 if (sname.name_id != nameid)
1189                     continue;
1190
1191                 /*
1192                  * Sort platforms in preference order, accepting
1193                  * all other platforms last
1194                  */
1195                 if (p < NUM_PLATFORM_ORDER)
1196                 {
1197                     if (sname.platform_id != platform)
1198                         continue;
1199                 }
1200                 else
1201                 {
1202                     unsigned int        sp;
1203
1204                     for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1205                         if (sname.platform_id == platform_order[sp])
1206                             break;
1207                     if (sp != NUM_PLATFORM_ORDER)
1208                         continue;
1209                 }
1210                 utf8 = FcSfntNameTranscode (&sname);
1211                 lang = FcSfntNameLanguage (&sname);
1212
1213                 if (!utf8)
1214                     continue;
1215
1216                 switch (sname.name_id) {
1217 #ifdef TT_NAME_ID_WWS_FAMILY
1218                 case TT_NAME_ID_WWS_FAMILY:
1219 #endif
1220                 case TT_NAME_ID_PREFERRED_FAMILY:
1221                 case TT_NAME_ID_FONT_FAMILY:
1222 #if 0   
1223                 case TT_NAME_ID_PS_NAME:
1224                 case TT_NAME_ID_UNIQUE_ID:
1225 #endif
1226                     if (FcDebug () & FC_DBG_SCANV)
1227                         printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1228                                 sname.name_id, sname.platform_id,
1229                                 sname.encoding_id, sname.language_id,
1230                                 utf8);
1231
1232                     elt = FC_FAMILY;
1233                     eltlang = FC_FAMILYLANG;
1234                     np = &nfamily;
1235                     nlangp = &nfamily_lang;
1236                     break;
1237                 case TT_NAME_ID_MAC_FULL_NAME:
1238                 case TT_NAME_ID_FULL_NAME:
1239                     if (FcDebug () & FC_DBG_SCANV)
1240                         printf ("found full   (n %2d p %d e %d l 0x%04x) %s\n",
1241                                 sname.name_id, sname.platform_id,
1242                                 sname.encoding_id, sname.language_id,
1243                                 utf8);
1244
1245                     elt = FC_FULLNAME;
1246                     eltlang = FC_FULLNAMELANG;
1247                     np = &nfullname;
1248                     nlangp = &nfullname_lang;
1249                     break;
1250 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1251                 case TT_NAME_ID_WWS_SUBFAMILY:
1252 #endif
1253                 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1254                 case TT_NAME_ID_FONT_SUBFAMILY:
1255                     if (utf8)
1256                     {
1257                         pp = utf8;
1258                         while (*pp == ' ')
1259                             pp++;
1260                         len = strlen ((const char *) pp);
1261                         memmove (utf8, pp, len + 1);
1262                         pp = utf8 + len - 1;
1263                         while (*pp == ' ')
1264                             pp--;
1265                         *(pp + 1) = 0;
1266                     }
1267                     if (FcDebug () & FC_DBG_SCANV)
1268                         printf ("found style  (n %2d p %d e %d l 0x%04x) %s\n",
1269                                 sname.name_id, sname.platform_id,
1270                                 sname.encoding_id, sname.language_id,
1271                                 utf8);
1272
1273                     elt = FC_STYLE;
1274                     eltlang = FC_STYLELANG;
1275                     np = &nstyle;
1276                     nlangp = &nstyle_lang;
1277                     break;
1278                 case TT_NAME_ID_TRADEMARK:
1279                 case TT_NAME_ID_MANUFACTURER:
1280                     /* If the foundry wasn't found in the OS/2 table, look here */
1281                     if(!foundry)
1282                         foundry = FcNoticeFoundry((FT_String *) utf8);
1283                     break;
1284                 }
1285                 if (elt)
1286                 {
1287                     if (FcStringInPatternElement (pat, elt, utf8))
1288                     {
1289                         free (utf8);
1290                         continue;
1291                     }
1292
1293                     /* add new element */
1294                     if (!FcPatternAddString (pat, elt, utf8))
1295                     {
1296                         free (utf8);
1297                         goto bail1;
1298                     }
1299                     free (utf8);
1300                     if (lang)
1301                     {
1302                         /* pad lang list with 'xx' to line up with elt */
1303                         while (*nlangp < *np)
1304                         {
1305                             if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
1306                                 goto bail1;
1307                             ++*nlangp;
1308                         }
1309                         if (!FcPatternAddString (pat, eltlang, lang))
1310                             goto bail1;
1311                         ++*nlangp;
1312                     }
1313                     ++*np;
1314                 }
1315                 else
1316                     free (utf8);
1317             }
1318         }
1319     }
1320
1321     if (!nfamily && face->family_name &&
1322         FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1323     {
1324         if (FcDebug () & FC_DBG_SCANV)
1325             printf ("using FreeType family \"%s\"\n", face->family_name);
1326         if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1327             goto bail1;
1328         ++nfamily;
1329     }
1330
1331     if (!nstyle && face->style_name &&
1332         FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1333     {
1334         if (FcDebug () & FC_DBG_SCANV)
1335             printf ("using FreeType style \"%s\"\n", face->style_name);
1336         if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1337             goto bail1;
1338         ++nstyle;
1339     }
1340
1341     if (!nfamily)
1342     {
1343         FcChar8 *start, *end;
1344         FcChar8 *family;
1345         
1346         start = (FcChar8 *) strrchr ((char *) file, '/');
1347         if (start)
1348             start++;
1349         else
1350             start = (FcChar8 *) file;
1351         end = (FcChar8 *) strrchr ((char *) start, '.');
1352         if (!end)
1353             end = start + strlen ((char *) start);
1354         /* freed below */
1355         family = malloc (end - start + 1);
1356         strncpy ((char *) family, (char *) start, end - start);
1357         family[end - start] = '\0';
1358         if (FcDebug () & FC_DBG_SCANV)
1359             printf ("using filename for family %s\n", family);
1360         if (!FcPatternAddString (pat, FC_FAMILY, family))
1361         {
1362             free (family);
1363             goto bail1;
1364         }
1365         free (family);
1366         ++nfamily;
1367     }
1368
1369     if (!FcPatternAddString (pat, FC_FILE, file))
1370         goto bail1;
1371
1372     if (!FcPatternAddInteger (pat, FC_INDEX, id))
1373         goto bail1;
1374
1375 #if 0
1376     /*
1377      * don't even try this -- CJK 'monospace' fonts are really
1378      * dual width, and most other fonts don't bother to set
1379      * the attribute.  Sigh.
1380      */
1381     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1382         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1383             goto bail1;
1384 #endif
1385
1386     /*
1387      * Find the font revision (if available)
1388      */
1389     head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1390     if (head)
1391     {
1392         if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1393             goto bail1;
1394     }
1395     else
1396     {
1397         if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1398             goto bail1;
1399     }
1400
1401     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1402     {
1403         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1404         {
1405             FT_ULong    bits;
1406             int         bit;
1407             if (FcCodePageRange[i].bit < 32)
1408             {
1409                 bits = os2->ulCodePageRange1;
1410                 bit = FcCodePageRange[i].bit;
1411             }
1412             else
1413             {
1414                 bits = os2->ulCodePageRange2;
1415                 bit = FcCodePageRange[i].bit - 32;
1416             }
1417             if (bits & (1 << bit))
1418             {
1419                 /*
1420                  * If the font advertises support for multiple
1421                  * "exclusive" languages, then include support
1422                  * for any language found to have coverage
1423                  */
1424                 if (exclusiveLang)
1425                 {
1426                     exclusiveLang = 0;
1427                     break;
1428                 }
1429                 exclusiveLang = FcCodePageRange[i].lang;
1430             }
1431         }
1432     }
1433
1434     if (os2 && os2->version != 0xffff)
1435     {
1436         if (os2->usWeightClass == 0)
1437             ;
1438         else if (os2->usWeightClass < 150)
1439             weight = FC_WEIGHT_THIN;
1440         else if (os2->usWeightClass < 250)
1441             weight = FC_WEIGHT_EXTRALIGHT;
1442         else if (os2->usWeightClass < 350)
1443             weight = FC_WEIGHT_LIGHT;
1444         else if (os2->usWeightClass < 450)
1445             weight = FC_WEIGHT_REGULAR;
1446         else if (os2->usWeightClass < 550)
1447             weight = FC_WEIGHT_MEDIUM;
1448         else if (os2->usWeightClass < 650)
1449             weight = FC_WEIGHT_SEMIBOLD;
1450         else if (os2->usWeightClass < 750)
1451             weight = FC_WEIGHT_BOLD;
1452         else if (os2->usWeightClass < 850)
1453             weight = FC_WEIGHT_EXTRABOLD;
1454         else if (os2->usWeightClass < 925)
1455             weight = FC_WEIGHT_BLACK;
1456         else if (os2->usWeightClass < 1000)
1457             weight = FC_WEIGHT_EXTRABLACK;
1458         if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1459             printf ("\tos2 weight class %d maps to weight %d\n",
1460                     os2->usWeightClass, weight);
1461
1462         switch (os2->usWidthClass) {
1463         case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1464         case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1465         case 3: width = FC_WIDTH_CONDENSED; break;
1466         case 4: width = FC_WIDTH_SEMICONDENSED; break;
1467         case 5: width = FC_WIDTH_NORMAL; break;
1468         case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1469         case 7: width = FC_WIDTH_EXPANDED; break;
1470         case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1471         case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1472         }
1473         if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1474             printf ("\tos2 width class %d maps to width %d\n",
1475                     os2->usWidthClass, width);
1476     }
1477     if (os2 && (complex_ = FcFontCapabilities(face)))
1478     {
1479         if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
1480         {
1481             free (complex_);
1482             goto bail1;
1483         }
1484         free (complex_);
1485     }
1486
1487     /*
1488      * Type 1: Check for FontInfo dictionary information
1489      * Code from g2@magestudios.net (Gerard Escalante)
1490      */
1491
1492 #if HAVE_FT_GET_PS_FONT_INFO
1493     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1494     {
1495         if (weight == -1 && psfontinfo.weight)
1496         {
1497             weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1498             if (FcDebug() & FC_DBG_SCANV)
1499                 printf ("\tType1 weight %s maps to %d\n",
1500                         psfontinfo.weight, weight);
1501         }
1502
1503 #if 0
1504         /*
1505          * Don't bother with italic_angle; FreeType already extracts that
1506          * information for us and sticks it into style_flags
1507          */
1508         if (psfontinfo.italic_angle)
1509             slant = FC_SLANT_ITALIC;
1510         else
1511             slant = FC_SLANT_ROMAN;
1512 #endif
1513
1514         if(!foundry)
1515             foundry = FcNoticeFoundry(psfontinfo.notice);
1516     }
1517 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1518
1519 #if HAVE_FT_GET_BDF_PROPERTY
1520     /*
1521      * Finally, look for a FOUNDRY BDF property if no other
1522      * mechanism has managed to locate a foundry
1523      */
1524
1525     if (!foundry)
1526     {
1527         int             rc;
1528         rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1529         if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1530             foundry = (FcChar8 *) prop.u.atom;
1531     }
1532
1533     if (width == -1)
1534     {
1535         if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1536             (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1537              prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1538         {
1539             FT_Int32    value;
1540         
1541             if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1542                 value = prop.u.integer;
1543             else
1544                 value = (FT_Int32) prop.u.cardinal;
1545             switch ((value + 5) / 10) {
1546             case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1547             case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1548             case 3: width = FC_WIDTH_CONDENSED; break;
1549             case 4: width = FC_WIDTH_SEMICONDENSED; break;
1550             case 5: width = FC_WIDTH_NORMAL; break;
1551             case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1552             case 7: width = FC_WIDTH_EXPANDED; break;
1553             case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1554             case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1555             }
1556         }
1557         if (width == -1 &&
1558             FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1559             prop.type == BDF_PROPERTY_TYPE_ATOM)
1560         {
1561             width = FcIsWidth ((FcChar8 *) prop.u.atom);
1562             if (FcDebug () & FC_DBG_SCANV)
1563                 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1564         }
1565     }
1566 #endif
1567
1568     /*
1569      * Look for weight, width and slant names in the style value
1570      */
1571     for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1572     {
1573         if (weight == -1)
1574         {
1575             weight = FcContainsWeight (style);
1576             if (FcDebug() & FC_DBG_SCANV)
1577                 printf ("\tStyle %s maps to weight %d\n", style, weight);
1578         }
1579         if (width == -1)
1580         {
1581             width = FcContainsWidth (style);
1582             if (FcDebug() & FC_DBG_SCANV)
1583                 printf ("\tStyle %s maps to width %d\n", style, width);
1584         }
1585         if (slant == -1)
1586         {
1587             slant = FcContainsSlant (style);
1588             if (FcDebug() & FC_DBG_SCANV)
1589                 printf ("\tStyle %s maps to slant %d\n", style, slant);
1590         }
1591         if (decorative == FcFalse)
1592         {
1593             decorative = FcContainsDecorative (style) > 0;
1594             if (FcDebug() & FC_DBG_SCANV)
1595                 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1596         }
1597     }
1598     /*
1599      * Pull default values from the FreeType flags if more
1600      * specific values not found above
1601      */
1602     if (slant == -1)
1603     {
1604         slant = FC_SLANT_ROMAN;
1605         if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1606             slant = FC_SLANT_ITALIC;
1607     }
1608
1609     if (weight == -1)
1610     {
1611         weight = FC_WEIGHT_MEDIUM;
1612         if (face->style_flags & FT_STYLE_FLAG_BOLD)
1613             weight = FC_WEIGHT_BOLD;
1614     }
1615
1616     if (width == -1)
1617         width = FC_WIDTH_NORMAL;
1618
1619     if (foundry == 0)
1620         foundry = (FcChar8 *) "unknown";
1621
1622     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1623         goto bail1;
1624
1625     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1626         goto bail1;
1627
1628     if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1629         goto bail1;
1630
1631     if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1632         goto bail1;
1633
1634     if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1635         goto bail1;
1636
1637     /*
1638      * Compute the unicode coverage for the font
1639      */
1640     cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1641     if (!cs)
1642         goto bail1;
1643
1644 #if HAVE_FT_GET_BDF_PROPERTY
1645     /* For PCF fonts, override the computed spacing with the one from
1646        the property */
1647     if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1648        prop.type == BDF_PROPERTY_TYPE_ATOM) {
1649         if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1650             spacing = FC_CHARCELL;
1651         else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1652             spacing = FC_MONO;
1653         else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1654             spacing = FC_PROPORTIONAL;
1655     }
1656 #endif
1657
1658     /*
1659      * Skip over PCF fonts that have no encoded characters; they're
1660      * usually just Unicode fonts transcoded to some legacy encoding
1661      * FT forces us to approximate whether a font is a PCF font
1662      * or not by whether it has any BDF properties.  Try PIXEL_SIZE;
1663      * I don't know how to get a list of BDF properties on the font. -PL
1664      */
1665     if (FcCharSetCount (cs) == 0)
1666     {
1667 #if HAVE_FT_GET_BDF_PROPERTY
1668         if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1669             goto bail2;
1670 #endif
1671     }
1672
1673     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1674         goto bail2;
1675
1676     ls = FcFreeTypeLangSet (cs, exclusiveLang);
1677     if (!ls)
1678         goto bail2;
1679
1680     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1681     {
1682         FcLangSetDestroy (ls);
1683         goto bail2;
1684     }
1685
1686     FcLangSetDestroy (ls);
1687
1688     if (spacing != FC_PROPORTIONAL)
1689         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1690             goto bail2;
1691
1692     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1693     {
1694         for (i = 0; i < face->num_fixed_sizes; i++)
1695             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1696                                      FcGetPixelSize (face, i)))
1697                 goto bail2;
1698         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1699             goto bail2;
1700     }
1701 #if HAVE_FT_GET_X11_FONT_FORMAT
1702     /*
1703      * Use the (not well documented or supported) X-specific function
1704      * from FreeType to figure out the font format
1705      */
1706     {
1707         const char *font_format = FT_Get_X11_Font_Format (face);
1708         if (font_format)
1709             FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
1710     }
1711 #endif
1712
1713     /*
1714      * Drop our reference to the charset
1715      */
1716     FcCharSetDestroy (cs);
1717
1718     return pat;
1719
1720 bail2:
1721     FcCharSetDestroy (cs);
1722 bail1:
1723     FcPatternDestroy (pat);
1724 bail0:
1725     return NULL;
1726 }
1727
1728 FcPattern *
1729 FcFreeTypeQuery(const FcChar8   *file,
1730                 int             id,
1731                 FcBlanks        *blanks,
1732                 int             *count)
1733 {
1734     FT_Face         face;
1735     FT_Library      ftLibrary;
1736     FcPattern       *pat = NULL;
1737
1738     if (FT_Init_FreeType (&ftLibrary))
1739         return NULL;
1740
1741     if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1742         goto bail;
1743
1744     *count = face->num_faces;
1745
1746     pat = FcFreeTypeQueryFace (face, file, id, blanks);
1747
1748     FT_Done_Face (face);
1749 bail:
1750     FT_Done_FreeType (ftLibrary);
1751     return pat;
1752 }
1753
1754 /*
1755  * For our purposes, this approximation is sufficient
1756  */
1757 #if !HAVE_FT_GET_NEXT_CHAR
1758 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1759                                           (*(gi) = 0), 0 : \
1760                                           (*(gi) = 1), (ucs4) + 1)
1761 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1762 #endif
1763
1764 typedef struct _FcCharEnt {
1765     FcChar16        bmp;
1766     unsigned char   encode;
1767 } FcCharEnt;
1768
1769 struct _FcCharMap {
1770     const FcCharEnt *ent;
1771     int             nent;
1772 };
1773
1774 typedef struct _FcFontDecode {
1775     FT_Encoding     encoding;
1776     const FcCharMap *map;
1777     FcChar32        max;
1778 } FcFontDecode;
1779
1780 static const FcCharEnt AdobeSymbolEnt[] = {
1781     { 0x0020, 0x20 }, /* SPACE  # space */
1782     { 0x0021, 0x21 }, /* EXCLAMATION MARK       # exclam */
1783     { 0x0023, 0x23 }, /* NUMBER SIGN    # numbersign */
1784     { 0x0025, 0x25 }, /* PERCENT SIGN   # percent */
1785     { 0x0026, 0x26 }, /* AMPERSAND      # ampersand */
1786     { 0x0028, 0x28 }, /* LEFT PARENTHESIS       # parenleft */
1787     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS      # parenright */
1788     { 0x002B, 0x2B }, /* PLUS SIGN      # plus */
1789     { 0x002C, 0x2C }, /* COMMA  # comma */
1790     { 0x002E, 0x2E }, /* FULL STOP      # period */
1791     { 0x002F, 0x2F }, /* SOLIDUS        # slash */
1792     { 0x0030, 0x30 }, /* DIGIT ZERO     # zero */
1793     { 0x0031, 0x31 }, /* DIGIT ONE      # one */
1794     { 0x0032, 0x32 }, /* DIGIT TWO      # two */
1795     { 0x0033, 0x33 }, /* DIGIT THREE    # three */
1796     { 0x0034, 0x34 }, /* DIGIT FOUR     # four */
1797     { 0x0035, 0x35 }, /* DIGIT FIVE     # five */
1798     { 0x0036, 0x36 }, /* DIGIT SIX      # six */
1799     { 0x0037, 0x37 }, /* DIGIT SEVEN    # seven */
1800     { 0x0038, 0x38 }, /* DIGIT EIGHT    # eight */
1801     { 0x0039, 0x39 }, /* DIGIT NINE     # nine */
1802     { 0x003A, 0x3A }, /* COLON  # colon */
1803     { 0x003B, 0x3B }, /* SEMICOLON      # semicolon */
1804     { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1805     { 0x003D, 0x3D }, /* EQUALS SIGN    # equal */
1806     { 0x003E, 0x3E }, /* GREATER-THAN SIGN      # greater */
1807     { 0x003F, 0x3F }, /* QUESTION MARK  # question */
1808     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET    # bracketleft */
1809     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET   # bracketright */
1810     { 0x005F, 0x5F }, /* LOW LINE       # underscore */
1811     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET     # braceleft */
1812     { 0x007C, 0x7C }, /* VERTICAL LINE  # bar */
1813     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET    # braceright */
1814     { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1815     { 0x00AC, 0xD8 }, /* NOT SIGN       # logicalnot */
1816     { 0x00B0, 0xB0 }, /* DEGREE SIGN    # degree */
1817     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN        # plusminus */
1818     { 0x00B5, 0x6D }, /* MICRO SIGN     # mu */
1819     { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN    # multiply */
1820     { 0x00F7, 0xB8 }, /* DIVISION SIGN  # divide */
1821     { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1822     { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA     # Alpha */
1823     { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA      # Beta */
1824     { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA     # Gamma */
1825     { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA     # Delta */
1826     { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON   # Epsilon */
1827     { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA      # Zeta */
1828     { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA       # Eta */
1829     { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA     # Theta */
1830     { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA      # Iota */
1831     { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA     # Kappa */
1832     { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA     # Lambda */
1833     { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU        # Mu */
1834     { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU        # Nu */
1835     { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI        # Xi */
1836     { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON   # Omicron */
1837     { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI        # Pi */
1838     { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO       # Rho */
1839     { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA     # Sigma */
1840     { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU       # Tau */
1841     { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON   # Upsilon */
1842     { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI       # Phi */
1843     { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI       # Chi */
1844     { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI       # Psi */
1845     { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA     # Omega */
1846     { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA       # alpha */
1847     { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA        # beta */
1848     { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA       # gamma */
1849     { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA       # delta */
1850     { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON     # epsilon */
1851     { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA        # zeta */
1852     { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1853     { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA       # theta */
1854     { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA        # iota */
1855     { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA       # kappa */
1856     { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA       # lambda */
1857     { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU  # mu */
1858     { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU  # nu */
1859     { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI  # xi */
1860     { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON     # omicron */
1861     { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI  # pi */
1862     { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1863     { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1864     { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA       # sigma */
1865     { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
1866     { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON     # upsilon */
1867     { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
1868     { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
1869     { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
1870     { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA       # omega */
1871     { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL     # theta1 */
1872     { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
1873     { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL       # phi1 */
1874     { 0x03D6, 0x76 }, /* GREEK PI SYMBOL        # omega1 */
1875     { 0x2022, 0xB7 }, /* BULLET # bullet */
1876     { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS    # ellipsis */
1877     { 0x2032, 0xA2 }, /* PRIME  # minute */
1878     { 0x2033, 0xB2 }, /* DOUBLE PRIME   # second */
1879     { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
1880     { 0x20AC, 0xA0 }, /* EURO SIGN      # Euro */
1881     { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
1882     { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P       # weierstrass */
1883     { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
1884     { 0x2126, 0x57 }, /* OHM SIGN       # Omega */
1885     { 0x2135, 0xC0 }, /* ALEF SYMBOL    # aleph */
1886     { 0x2190, 0xAC }, /* LEFTWARDS ARROW        # arrowleft */
1887     { 0x2191, 0xAD }, /* UPWARDS ARROW  # arrowup */
1888     { 0x2192, 0xAE }, /* RIGHTWARDS ARROW       # arrowright */
1889     { 0x2193, 0xAF }, /* DOWNWARDS ARROW        # arrowdown */
1890     { 0x2194, 0xAB }, /* LEFT RIGHT ARROW       # arrowboth */
1891     { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS  # carriagereturn */
1892     { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
1893     { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW   # arrowdblup */
1894     { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW        # arrowdblright */
1895     { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
1896     { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW        # arrowdblboth */
1897     { 0x2200, 0x22 }, /* FOR ALL        # universal */
1898     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL   # partialdiff */
1899     { 0x2203, 0x24 }, /* THERE EXISTS   # existential */
1900     { 0x2205, 0xC6 }, /* EMPTY SET      # emptyset */
1901     { 0x2206, 0x44 }, /* INCREMENT      # Delta */
1902     { 0x2207, 0xD1 }, /* NABLA  # gradient */
1903     { 0x2208, 0xCE }, /* ELEMENT OF     # element */
1904     { 0x2209, 0xCF }, /* NOT AN ELEMENT OF      # notelement */
1905     { 0x220B, 0x27 }, /* CONTAINS AS MEMBER     # suchthat */
1906     { 0x220F, 0xD5 }, /* N-ARY PRODUCT  # product */
1907     { 0x2211, 0xE5 }, /* N-ARY SUMMATION        # summation */
1908     { 0x2212, 0x2D }, /* MINUS SIGN     # minus */
1909     { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
1910     { 0x2217, 0x2A }, /* ASTERISK OPERATOR      # asteriskmath */
1911     { 0x221A, 0xD6 }, /* SQUARE ROOT    # radical */
1912     { 0x221D, 0xB5 }, /* PROPORTIONAL TO        # proportional */
1913     { 0x221E, 0xA5 }, /* INFINITY       # infinity */
1914     { 0x2220, 0xD0 }, /* ANGLE  # angle */
1915     { 0x2227, 0xD9 }, /* LOGICAL AND    # logicaland */
1916     { 0x2228, 0xDA }, /* LOGICAL OR     # logicalor */
1917     { 0x2229, 0xC7 }, /* INTERSECTION   # intersection */
1918     { 0x222A, 0xC8 }, /* UNION  # union */
1919     { 0x222B, 0xF2 }, /* INTEGRAL       # integral */
1920     { 0x2234, 0x5C }, /* THEREFORE      # therefore */
1921     { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
1922     { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
1923     { 0x2248, 0xBB }, /* ALMOST EQUAL TO        # approxequal */
1924     { 0x2260, 0xB9 }, /* NOT EQUAL TO   # notequal */
1925     { 0x2261, 0xBA }, /* IDENTICAL TO   # equivalence */
1926     { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO  # lessequal */
1927     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO       # greaterequal */
1928     { 0x2282, 0xCC }, /* SUBSET OF      # propersubset */
1929     { 0x2283, 0xC9 }, /* SUPERSET OF    # propersuperset */
1930     { 0x2284, 0xCB }, /* NOT A SUBSET OF        # notsubset */
1931     { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO  # reflexsubset */
1932     { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO        # reflexsuperset */
1933     { 0x2295, 0xC5 }, /* CIRCLED PLUS   # circleplus */
1934     { 0x2297, 0xC4 }, /* CIRCLED TIMES  # circlemultiply */
1935     { 0x22A5, 0x5E }, /* UP TACK        # perpendicular */
1936     { 0x22C5, 0xD7 }, /* DOT OPERATOR   # dotmath */
1937     { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL      # integraltp */
1938     { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL   # integralbt */
1939     { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET    # angleleft */
1940     { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET   # angleright */
1941     { 0x25CA, 0xE0 }, /* LOZENGE        # lozenge */
1942     { 0x2660, 0xAA }, /* BLACK SPADE SUIT       # spade */
1943     { 0x2663, 0xA7 }, /* BLACK CLUB SUIT        # club */
1944     { 0x2665, 0xA9 }, /* BLACK HEART SUIT       # heart */
1945     { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT     # diamond */
1946     { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF   # copyrightserif (CUS) */
1947     { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF  # registerserif (CUS) */
1948     { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF  # trademarkserif (CUS) */
1949     { 0xF8E5, 0x60 }, /* RADICAL EXTENDER       # radicalex (CUS) */
1950     { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER        # arrowvertex (CUS) */
1951     { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER      # arrowhorizex (CUS) */
1952     { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF     # registersans (CUS) */
1953     { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF      # copyrightsans (CUS) */
1954     { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF     # trademarksans (CUS) */
1955     { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
1956     { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER    # parenleftex (CUS) */
1957     { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM      # parenleftbt (CUS) */
1958     { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP        # bracketlefttp (CUS) */
1959     { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER   # bracketleftex (CUS) */
1960     { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM     # bracketleftbt (CUS) */
1961     { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
1962     { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
1963     { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM      # braceleftbt (CUS) */
1964     { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
1965     { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER      # integralex (CUS) */
1966     { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP        # parenrighttp (CUS) */
1967     { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER   # parenrightex (CUS) */
1968     { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM     # parenrightbt (CUS) */
1969     { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP       # bracketrighttp (CUS) */
1970     { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER  # bracketrightex (CUS) */
1971     { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM    # bracketrightbt (CUS) */
1972     { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP        # bracerighttp (CUS) */
1973     { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID        # bracerightmid (CUS) */
1974     { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM     # bracerightbt (CUS) */
1975 };
1976
1977 static const FcCharMap AdobeSymbol = {
1978     AdobeSymbolEnt,
1979     sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
1980 };
1981
1982 static const FcFontDecode fcFontDecoders[] = {
1983     { ft_encoding_unicode,      0,              (1 << 21) - 1 },
1984     { ft_encoding_symbol,       &AdobeSymbol,   (1 << 16) - 1 },
1985 };
1986
1987 #define NUM_DECODE  (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
1988
1989 static const FcChar32   prefer_unicode[] = {
1990     0x20ac,     /* EURO SIGN */
1991 };
1992
1993 #define NUM_PREFER_UNICODE  (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
1994
1995 FcChar32
1996 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
1997 {
1998     int         low, high, mid;
1999     FcChar16    bmp;
2000
2001     low = 0;
2002     high = map->nent - 1;
2003     if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2004         return ~0;
2005     while (low <= high)
2006     {
2007         mid = (high + low) >> 1;
2008         bmp = map->ent[mid].bmp;
2009         if (ucs4 == bmp)
2010             return (FT_ULong) map->ent[mid].encode;
2011         if (ucs4 < bmp)
2012             high = mid - 1;
2013         else
2014             low = mid + 1;
2015     }
2016     return ~0;
2017 }
2018
2019 FcChar32
2020 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2021 {
2022     int     i;
2023
2024     for (i = 0; i < map->nent; i++)
2025         if (map->ent[i].encode == private)
2026             return (FcChar32) map->ent[i].bmp;
2027     return ~0;
2028 }
2029
2030 const FcCharMap *
2031 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2032 {
2033     int i;
2034
2035     for (i = 0; i < NUM_DECODE; i++)
2036         if (fcFontDecoders[i].encoding == encoding)
2037             return fcFontDecoders[i].map;
2038     return 0;
2039 }
2040
2041 #include "../fc-glyphname/fcglyphname.h"
2042
2043 static FcChar32
2044 FcHashGlyphName (const FcChar8 *name)
2045 {
2046     FcChar32    h = 0;
2047     FcChar8     c;
2048
2049     while ((c = *name++))
2050     {
2051         h = ((h << 1) | (h >> 31)) ^ c;
2052     }
2053     return h;
2054 }
2055
2056 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2057 /*
2058  * Use Type1 glyph names for fonts which have reliable names
2059  * and which export an Adobe Custom mapping
2060  */
2061 static FcBool
2062 FcFreeTypeUseNames (FT_Face face)
2063 {
2064     FT_Int  map;
2065
2066     if (!FT_Has_PS_Glyph_Names (face))
2067         return FcFalse;
2068     for (map = 0; map < face->num_charmaps; map++)
2069         if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2070             return FcTrue;
2071     return FcFalse;
2072 }
2073
2074 static const FcChar8 *
2075 FcUcs4ToGlyphName (FcChar32 ucs4)
2076 {
2077     int         i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2078     int         r = 0;
2079     FcGlyphId   gn;
2080
2081     while ((gn = _fc_ucs_to_name[i]) != -1)
2082     {
2083         if (_fc_glyph_names[gn].ucs == ucs4)
2084             return _fc_glyph_names[gn].name;
2085         if (!r)
2086         {
2087             r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2088             if (!r)
2089                 r = 1;
2090         }
2091         i += r;
2092         if (i >= FC_GLYPHNAME_HASH)
2093             i -= FC_GLYPHNAME_HASH;
2094     }
2095     return 0;
2096 }
2097
2098 static FcChar32
2099 FcGlyphNameToUcs4 (FcChar8 *name)
2100 {
2101     FcChar32    h = FcHashGlyphName (name);
2102     int         i = (int) (h % FC_GLYPHNAME_HASH);
2103     int         r = 0;
2104     FcGlyphId   gn;
2105
2106     while ((gn = _fc_name_to_ucs[i]) != -1)
2107     {
2108         if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name))
2109             return _fc_glyph_names[gn].ucs;
2110         if (!r)
2111         {
2112             r = (int) (h % FC_GLYPHNAME_REHASH);
2113             if (!r)
2114                 r = 1;
2115         }
2116         i += r;
2117         if (i >= FC_GLYPHNAME_HASH)
2118             i -= FC_GLYPHNAME_HASH;
2119     }
2120     return 0xffff;
2121 }
2122
2123 /*
2124  * Work around a bug in some FreeType versions which fail
2125  * to correctly bounds check glyph name buffers and overwrite
2126  * the stack. As Postscript names have a limit of 127 characters,
2127  * this should be sufficient.
2128  */
2129
2130 #if FC_GLYPHNAME_MAXLEN < 127
2131 # define FC_GLYPHNAME_BUFLEN 127
2132 #else
2133 # define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2134 #endif
2135
2136 /*
2137  * Search through a font for a glyph by name.  This is
2138  * currently a linear search as there doesn't appear to be
2139  * any defined order within the font
2140  */
2141 static FT_UInt
2142 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2143 {
2144     FT_UInt gindex;
2145     FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2146
2147     for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2148     {
2149         if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2150             if (!strcmp ((char *) name, (char *) name_buf))
2151                 return gindex;
2152     }
2153     return 0;
2154 }
2155 #endif
2156
2157 /*
2158  * Map a UCS4 glyph to a glyph index.  Use all available encoding
2159  * tables to try and find one that works.  This information is expected
2160  * to be cached by higher levels, so performance isn't critical
2161  */
2162
2163 FT_UInt
2164 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2165 {
2166     int             initial, offset, decode;
2167     FT_UInt         glyphindex;
2168     FcChar32        charcode;
2169     int             p;
2170
2171     initial = 0;
2172
2173     if (!face)
2174         return 0;
2175
2176     /*
2177      * Find the current encoding
2178      */
2179     if (face->charmap)
2180     {
2181         for (; initial < NUM_DECODE; initial++)
2182             if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2183                 break;
2184         if (initial == NUM_DECODE)
2185             initial = 0;
2186     }
2187     for (p = 0; p < NUM_PREFER_UNICODE; p++)
2188         if (ucs4 == prefer_unicode[p])
2189         {
2190             initial = 0;
2191             break;
2192         }
2193     /*
2194      * Check each encoding for the glyph, starting with the current one
2195      */
2196     for (offset = 0; offset < NUM_DECODE; offset++)
2197     {
2198         decode = (initial + offset) % NUM_DECODE;
2199         if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2200             if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2201                 continue;
2202         if (fcFontDecoders[decode].map)
2203         {
2204             charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2205             if (charcode == ~0U)
2206                 continue;
2207         }
2208         else
2209             charcode = ucs4;
2210         glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2211         if (glyphindex)
2212             return glyphindex;
2213     }
2214 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2215     /*
2216      * Check postscript name table if present
2217      */
2218     if (FcFreeTypeUseNames (face))
2219     {
2220         const FcChar8   *name = FcUcs4ToGlyphName (ucs4);
2221         if (name)
2222         {
2223             glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2224             if (glyphindex)
2225                 return glyphindex;
2226         }
2227     }
2228 #endif
2229     return 0;
2230 }
2231
2232 static FcBool
2233 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2234                       FT_UInt glyph, FcBlanks *blanks,
2235                       FT_Pos *advance,
2236                       FcBool using_strike)
2237 {
2238     FT_Int          load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2239     FT_GlyphSlot    slot;
2240
2241     if (using_strike)
2242         load_flags &= ~FT_LOAD_NO_SCALE;
2243
2244     /*
2245      * When using scalable fonts, only report those glyphs
2246      * which can be scaled; otherwise those fonts will
2247      * only be available at some sizes, and never when
2248      * transformed.  Avoid this by simply reporting bitmap-only
2249      * glyphs as missing
2250      */
2251     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2252         load_flags |= FT_LOAD_NO_BITMAP;
2253
2254     if (FT_Load_Glyph (face, glyph, load_flags))
2255         return FcFalse;
2256
2257     slot = face->glyph;
2258     if (!glyph)
2259         return FcFalse;
2260
2261     *advance = slot->metrics.horiAdvance;
2262
2263     switch ((int) slot->format) {
2264     case ft_glyph_format_bitmap:
2265         /*
2266          * Bitmaps are assumed to be reasonable; if
2267          * this proves to be a rash assumption, this
2268          * code can be easily modified
2269          */
2270         return FcTrue;
2271     case ft_glyph_format_outline:
2272         /*
2273          * Glyphs with contours are always OK
2274          */
2275         if (slot->outline.n_contours != 0)
2276             return FcTrue;
2277         /*
2278          * Glyphs with no contours are only OK if
2279          * they're members of the Blanks set specified
2280          * in the configuration.  If blanks isn't set,
2281          * then allow any glyph to be blank
2282          */
2283         if (!blanks || FcBlanksIsMember (blanks, ucs4))
2284             return FcTrue;
2285         /* fall through ... */
2286     default:
2287         break;
2288     }
2289     return FcFalse;
2290 }
2291
2292 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2293
2294 static FcCharSet *
2295 FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index)
2296 {
2297     FcChar32        page, off, ucs4;
2298 #ifdef CHECK
2299     FcChar32        font_max = 0;
2300 #endif
2301     FcCharSet       *fcs;
2302     FcCharLeaf      *leaf;
2303     const FcCharMap *map;
2304     int             o;
2305     int             i;
2306     FT_UInt         glyph;
2307     FT_Pos          advance, advance_one = 0, advance_two = 0;
2308     FcBool          has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2309     FcBool          using_strike = FcFalse;
2310
2311     fcs = FcCharSetCreate ();
2312     if (!fcs)
2313         goto bail0;
2314
2315 #if HAVE_FT_SELECT_SIZE
2316     if (strike_index >= 0) {
2317         if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
2318             goto bail1;
2319         using_strike = FcTrue;
2320     }
2321 #endif
2322
2323 #ifdef CHECK
2324     printf ("Family %s style %s\n", face->family_name, face->style_name);
2325 #endif
2326     for (o = 0; o < NUM_DECODE; o++)
2327     {
2328         if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2329             continue;
2330         map = fcFontDecoders[o].map;
2331         if (map)
2332         {
2333             /*
2334              * Non-Unicode tables are easy; there's a list of all possible
2335              * characters
2336              */
2337             for (i = 0; i < map->nent; i++)
2338             {
2339                 ucs4 = map->ent[i].bmp;
2340                 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2341                 if (glyph &&
2342                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2343                 {
2344                     /*
2345                      * ignore glyphs with zero advance. They’re
2346                      * combining characters, and while their behaviour
2347                      * isn’t well defined for monospaced applications in
2348                      * Unicode, there are many fonts which include
2349                      * zero-width combining characters in otherwise
2350                      * monospaced fonts.
2351                      */
2352                     if (advance)
2353                     {
2354                         if (!has_advance)
2355                         {
2356                             has_advance = FcTrue;
2357                             advance_one = advance;
2358                         }
2359                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2360                         {
2361                             if (fixed_advance)
2362                             {
2363                                 dual_advance = FcTrue;
2364                                 fixed_advance = FcFalse;
2365                                 advance_two = advance;
2366                             }
2367                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2368                                 dual_advance = FcFalse;
2369                         }
2370                     }
2371
2372                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2373                     if (!leaf)
2374                         goto bail1;
2375                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2376 #ifdef CHECK
2377                     if (ucs4 > font_max)
2378                         font_max = ucs4;
2379 #endif
2380                 }
2381             }
2382         }
2383         else
2384         {
2385             page = ~0;
2386             leaf = NULL;
2387             ucs4 = FT_Get_First_Char (face, &glyph);
2388             while (glyph != 0)
2389             {
2390                 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2391                 {
2392                     if (advance)
2393                     {
2394                         if (!has_advance)
2395                         {
2396                             has_advance = FcTrue;
2397                             advance_one = advance;
2398                         }
2399                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2400                         {
2401                             if (fixed_advance)
2402                             {
2403                                 dual_advance = FcTrue;
2404                                 fixed_advance = FcFalse;
2405                                 advance_two = advance;
2406                             }
2407                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2408                                 dual_advance = FcFalse;
2409                         }
2410                     }
2411
2412                     if ((ucs4 >> 8) != page)
2413                     {
2414                         page = (ucs4 >> 8);
2415                         leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2416                         if (!leaf)
2417                             goto bail1;
2418                     }
2419                     off = ucs4 & 0xff;
2420                     leaf->map[off >> 5] |= (1 << (off & 0x1f));
2421 #ifdef CHECK
2422                     if (ucs4 > font_max)
2423                         font_max = ucs4;
2424 #endif
2425                 }
2426                 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2427             }
2428 #ifdef CHECK
2429             for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2430             {
2431                 FcBool      FT_Has, FC_Has;
2432
2433                 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2434                 FC_Has = FcCharSetHasChar (fcs, ucs4);
2435                 if (FT_Has != FC_Has)
2436                 {
2437                     printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2438                 }
2439             }
2440 #endif
2441         }
2442     }
2443 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2444     /*
2445      * Add mapping from PS glyph names if available
2446      */
2447     if (FcFreeTypeUseNames (face))
2448     {
2449         FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2450
2451         for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2452         {
2453             if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2454             {
2455                 ucs4 = FcGlyphNameToUcs4 (name_buf);
2456                 if (ucs4 != 0xffff &&
2457                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2458                 {
2459                     if (advance)
2460                     {
2461                         if (!has_advance)
2462                         {
2463                             has_advance = FcTrue;
2464                             advance_one = advance;
2465                         }
2466                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2467                         {
2468                             if (fixed_advance)
2469                             {
2470                                 dual_advance = FcTrue;
2471                                 fixed_advance = FcFalse;
2472                                 advance_two = advance;
2473                             }
2474                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2475                                 dual_advance = FcFalse;
2476                         }
2477                     }
2478                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2479                     if (!leaf)
2480                         goto bail1;
2481                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2482 #ifdef CHECK
2483                     if (ucs4 > font_max)
2484                         font_max = ucs4;
2485 #endif
2486                 }
2487             }
2488         }
2489     }
2490 #endif
2491 #ifdef CHECK
2492     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2493     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2494     {
2495         FcBool  has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2496         FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
2497
2498         if (has_char && !has_bit)
2499         {
2500             if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2501                 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2502             else
2503                 printf ("Bitmap missing char 0x%x\n", ucs4);
2504         }
2505         else if (!has_char && has_bit)
2506             printf ("Bitmap extra char 0x%x\n", ucs4);
2507     }
2508 #endif
2509     if (fixed_advance)
2510         *spacing = FC_MONO;
2511     else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2512         *spacing = FC_DUAL;
2513     else
2514         *spacing = FC_PROPORTIONAL;
2515     return fcs;
2516 bail1:
2517     FcCharSetDestroy (fcs);
2518 bail0:
2519     return 0;
2520 }
2521
2522 FcCharSet *
2523 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2524 {
2525     FcCharSet   *cs;
2526
2527     /*
2528      * Check for bitmap-only ttf fonts that are missing the glyf table.
2529      * In that case, pick a size and look for glyphs in that size instead
2530      */
2531     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
2532         face->num_fixed_sizes > 0 &&
2533         FT_Get_Sfnt_Table (face, ft_sfnt_head))
2534     {
2535         FT_Int  strike_index = 0;
2536         int         i;
2537
2538         /* Select the face closest to 16 pixels tall */
2539         for (i = 1; i < face->num_fixed_sizes; i++) {
2540             if (abs (face->available_sizes[i].height - 16) <
2541                 abs (face->available_sizes[strike_index].height - 16))
2542                 strike_index = i;
2543         }
2544         cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index);
2545     }
2546     else
2547         cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1);
2548     return cs;
2549 }
2550
2551 FcCharSet *
2552 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2553 {
2554     int spacing;
2555
2556     return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2557 }
2558
2559
2560 #define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2561 #define TTAG_GSUB  FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2562 #define TTAG_SILF  FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2563
2564 #define OTLAYOUT_HEAD       "otlayout:"
2565 #define OTLAYOUT_HEAD_LEN   9
2566 #define OTLAYOUT_ID_LEN     4
2567 /* space + head + id */
2568 #define OTLAYOUT_LEN        (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2569
2570 /*
2571  * This is a bit generous; the registry has only lower case and space
2572  * except for 'DFLT'.
2573  */
2574 #define FcIsSpace(x)        (040 == (x))
2575 #define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2576                         
2577 static void
2578 addtag(FcChar8 *complex_, FT_ULong tag)
2579 {
2580     FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2581
2582     tagstring[0] = (FcChar8)(tag >> 24),
2583     tagstring[1] = (FcChar8)(tag >> 16),
2584     tagstring[2] = (FcChar8)(tag >> 8),
2585     tagstring[3] = (FcChar8)(tag);
2586     tagstring[4] = '\0';
2587
2588     /* skip tags which aren't alphabetic, under the assumption that
2589      * they're probably broken
2590      */
2591     if (!FcIsValidScript(tagstring[0]) ||
2592         !FcIsValidScript(tagstring[1]) ||
2593         !FcIsValidScript(tagstring[2]) ||
2594         !FcIsValidScript(tagstring[3]))
2595         return;
2596
2597     if (*complex_ != '\0')
2598         strcat ((char *) complex_, " ");
2599     strcat ((char *) complex_, OTLAYOUT_HEAD);
2600     strcat ((char *) complex_, (char *) tagstring);
2601 }
2602
2603 static int
2604 compareulong (const void *a, const void *b)
2605 {
2606     const FT_ULong *ua = (const FT_ULong *) a;
2607     const FT_ULong *ub = (const FT_ULong *) b;
2608     return *ua - *ub;
2609 }
2610
2611
2612 static int
2613 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
2614 {
2615     FT_ULong   cur_offset, new_offset, base_offset;
2616     FT_Stream  stream = face->stream;
2617     FT_Error   error;
2618     FT_UShort  n, p;
2619     int        script_count;
2620
2621     if (!stream)
2622         return 0;
2623
2624     if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2625         return 0;
2626
2627     base_offset = ftglue_stream_pos ( stream );
2628
2629     /* skip version */
2630
2631     if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2632         return 0;
2633
2634     new_offset = GET_UShort() + base_offset;
2635
2636     ftglue_stream_frame_exit( stream );
2637
2638     cur_offset = ftglue_stream_pos( stream );
2639
2640     if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
2641         return 0;
2642
2643     base_offset = ftglue_stream_pos( stream );
2644
2645     if ( ftglue_stream_frame_enter( stream, 2L ) )
2646         return 0;
2647
2648     script_count = GET_UShort ();
2649
2650     ftglue_stream_frame_exit( stream );
2651
2652     *stags = malloc(script_count * sizeof (FT_ULong));
2653     if (!stags)
2654         return 0;
2655
2656     p = 0;
2657     for ( n = 0; n < script_count; n++ )
2658     {
2659         if ( ftglue_stream_frame_enter( stream, 6L ) )
2660             goto Fail;
2661
2662         (*stags)[p] = GET_ULong ();
2663         new_offset = GET_UShort () + base_offset;
2664
2665         ftglue_stream_frame_exit( stream );
2666
2667         cur_offset = ftglue_stream_pos( stream );
2668
2669         error = ftglue_stream_seek( stream, new_offset );
2670
2671         if ( error == FT_Err_Ok )
2672             p++;
2673
2674         (void)ftglue_stream_seek( stream, cur_offset );
2675     }
2676
2677     if (!p)
2678         goto Fail;
2679
2680     /* sort the tag list before returning it */
2681     qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
2682
2683     return script_count;
2684
2685 Fail:
2686     free(*stags);
2687     *stags = NULL;
2688     return 0;
2689 }
2690
2691 static FcChar8 *
2692 FcFontCapabilities(FT_Face face)
2693 {
2694     FcBool issilgraphitefont = 0;
2695     FT_Error err;
2696     FT_ULong len = 0;
2697     FT_ULong *gsubtags=NULL, *gpostags=NULL;
2698     FT_UShort gsub_count=0, gpos_count=0;
2699     FT_ULong maxsize;
2700     FcChar8 *complex_ = NULL;
2701     int indx1 = 0, indx2 = 0;
2702
2703     err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2704     issilgraphitefont = ( err == FT_Err_Ok);
2705
2706     gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
2707     gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
2708
2709     if (!issilgraphitefont && !gsub_count && !gpos_count)
2710         goto bail;
2711
2712     maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2713                (issilgraphitefont ? 13 : 0));
2714     complex_ = malloc (sizeof (FcChar8) * maxsize);
2715     if (!complex_)
2716         goto bail;
2717
2718     complex_[0] = '\0';
2719     if (issilgraphitefont)
2720         strcpy((char *) complex_, "ttable:Silf ");
2721
2722     while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2723         if (indx1 == gsub_count) {
2724             addtag(complex_, gpostags[indx2]);
2725             indx2++;
2726         } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2727             addtag(complex_, gsubtags[indx1]);
2728             indx1++;
2729         } else if (gsubtags[indx1] == gpostags[indx2]) {
2730             addtag(complex_, gsubtags[indx1]);
2731             indx1++;
2732             indx2++;
2733         } else {
2734             addtag(complex_, gpostags[indx2]);
2735             indx2++;
2736         }
2737     }
2738     if (FcDebug () & FC_DBG_SCANV)
2739         printf("complex_ features in this font: %s\n", complex_);
2740 bail:
2741     free(gsubtags);
2742     free(gpostags);
2743     return complex_;
2744 }
2745
2746 #define __fcfreetype__
2747 #include "fcaliastail.h"
2748 #include "fcftaliastail.h"
2749 #undef __fcfreetype__