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