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