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