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