]> git.wh0rd.org Git - fontconfig.git/blob - src/fcfreetype.c
Only add basename to patterns' FC_FILE element, not any part of the
[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 *)file)))
1292         goto bail1;
1293
1294     if (!FcPatternAddInteger (pat, FC_INDEX, id))
1295         goto bail1;
1296
1297 #if 0
1298     /*
1299      * don't even try this -- CJK 'monospace' fonts are really
1300      * dual width, and most other fonts don't bother to set
1301      * the attribute.  Sigh.
1302      */
1303     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1304         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1305             goto bail1;
1306 #endif
1307
1308     /*
1309      * Find the font revision (if available)
1310      */
1311     head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1312     if (head)
1313     {
1314         if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1315             goto bail1;
1316     }
1317     else
1318     {
1319         if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1320             goto bail1;
1321     }
1322
1323     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1324     {
1325         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1326         {
1327             FT_ULong    bits;
1328             int         bit;
1329             if (FcCodePageRange[i].bit < 32)
1330             {
1331                 bits = os2->ulCodePageRange1;
1332                 bit = FcCodePageRange[i].bit;
1333             }
1334             else
1335             {
1336                 bits = os2->ulCodePageRange2;
1337                 bit = FcCodePageRange[i].bit - 32;
1338             }
1339             if (bits & (1 << bit))
1340             {
1341                 /* 
1342                  * If the font advertises support for multiple
1343                  * "exclusive" languages, then include support
1344                  * for any language found to have coverage
1345                  */
1346                 if (exclusiveLang)
1347                 {
1348                     exclusiveLang = 0;
1349                     break;
1350                 }
1351                 exclusiveLang = FcCodePageRange[i].lang;
1352             }
1353         }
1354     }
1355
1356     if (os2 && os2->version != 0xffff)
1357     {
1358         if (os2->usWeightClass == 0)
1359             ;
1360         else if (os2->usWeightClass < 150)
1361             weight = FC_WEIGHT_THIN;
1362         else if (os2->usWeightClass < 250)
1363             weight = FC_WEIGHT_EXTRALIGHT;
1364         else if (os2->usWeightClass < 350)
1365             weight = FC_WEIGHT_LIGHT;
1366         else if (os2->usWeightClass < 450)
1367             weight = FC_WEIGHT_REGULAR;
1368         else if (os2->usWeightClass < 550)
1369             weight = FC_WEIGHT_MEDIUM;
1370         else if (os2->usWeightClass < 650)
1371             weight = FC_WEIGHT_SEMIBOLD;
1372         else if (os2->usWeightClass < 750)
1373             weight = FC_WEIGHT_BOLD;
1374         else if (os2->usWeightClass < 850)
1375             weight = FC_WEIGHT_EXTRABOLD;
1376         else if (os2->usWeightClass < 950)
1377             weight = FC_WEIGHT_BLACK;
1378
1379         switch (os2->usWidthClass) {
1380         case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1381         case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1382         case 3: width = FC_WIDTH_CONDENSED; break;
1383         case 4: width = FC_WIDTH_SEMICONDENSED; break;
1384         case 5: width = FC_WIDTH_NORMAL; break;
1385         case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1386         case 7: width = FC_WIDTH_EXPANDED; break;
1387         case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1388         case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1389         }
1390     }
1391     if (os2 && (complex = FcFontCapabilities(face)))
1392     {
1393         if (!FcPatternAddString (pat, FC_CAPABILITY, complex))
1394         {
1395             free (complex);
1396             goto bail1;
1397         }
1398         free (complex);
1399     }
1400
1401     /*
1402      * Type 1: Check for FontInfo dictionary information
1403      * Code from g2@magestudios.net (Gerard Escalante)
1404      */
1405     
1406 #if HAVE_FT_GET_PS_FONT_INFO
1407     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1408     {
1409         if (weight == -1 && psfontinfo.weight)
1410         {
1411             weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1412             if (FcDebug() & FC_DBG_SCANV)
1413                 printf ("\tType1 weight %s maps to %d\n",
1414                         psfontinfo.weight, weight);
1415         }
1416      
1417 #if 0
1418         /* 
1419          * Don't bother with italic_angle; FreeType already extracts that
1420          * information for us and sticks it into style_flags
1421          */
1422         if (psfontinfo.italic_angle)
1423             slant = FC_SLANT_ITALIC; 
1424         else
1425             slant = FC_SLANT_ROMAN; 
1426 #endif
1427
1428         if(!foundry)
1429             foundry = FcNoticeFoundry(psfontinfo.notice);
1430     }
1431 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1432     
1433 #if HAVE_FT_GET_BDF_PROPERTY
1434     /*
1435      * Finally, look for a FOUNDRY BDF property if no other
1436      * mechanism has managed to locate a foundry
1437      */
1438
1439     if (!foundry)
1440     {
1441         int             rc;
1442         BDF_PropertyRec prop;
1443         rc = MY_Get_BDF_Property(face, "FOUNDRY", &prop);
1444         if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1445             foundry = (FcChar8 *) prop.u.atom;
1446     }
1447
1448     if (width == -1)
1449     {
1450         if (MY_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1451             (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1452              prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1453         {
1454             FT_Int32    value;
1455             
1456             if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1457                 value = prop.u.integer;
1458             else
1459                 value = (FT_Int32) prop.u.cardinal;
1460             switch ((value + 5) / 10) {
1461             case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1462             case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1463             case 3: width = FC_WIDTH_CONDENSED; break;
1464             case 4: width = FC_WIDTH_SEMICONDENSED; break;
1465             case 5: width = FC_WIDTH_NORMAL; break;
1466             case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1467             case 7: width = FC_WIDTH_EXPANDED; break;
1468             case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1469             case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1470             }
1471         }
1472         if (width == -1 &&
1473             MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1474             prop.type == BDF_PROPERTY_TYPE_ATOM)
1475         {
1476             width = FcIsWidth ((FcChar8 *) prop.u.atom);
1477             if (FcDebug () & FC_DBG_SCANV)
1478                 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1479         }
1480     }
1481 #endif
1482
1483     /*
1484      * Look for weight, width and slant names in the style value
1485      */
1486     for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1487     {
1488         if (weight == -1)
1489         {
1490             weight = FcContainsWeight (style);
1491             if (FcDebug() & FC_DBG_SCANV)
1492                 printf ("\tStyle %s maps to weight %d\n", style, weight);
1493         }
1494         if (width == -1)
1495         {
1496             width = FcContainsWidth (style);
1497             if (FcDebug() & FC_DBG_SCANV)
1498                 printf ("\tStyle %s maps to width %d\n", style, width);
1499         }
1500         if (slant == -1)
1501         {
1502             slant = FcContainsSlant (style);
1503             if (FcDebug() & FC_DBG_SCANV)
1504                 printf ("\tStyle %s maps to slant %d\n", style, slant);
1505         }
1506     }
1507     /*
1508      * Pull default values from the FreeType flags if more
1509      * specific values not found above
1510      */
1511     if (slant == -1)
1512     {
1513         slant = FC_SLANT_ROMAN;
1514         if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1515             slant = FC_SLANT_ITALIC;
1516     }
1517
1518     if (weight == -1)
1519     {
1520         weight = FC_WEIGHT_MEDIUM;
1521         if (face->style_flags & FT_STYLE_FLAG_BOLD)
1522             weight = FC_WEIGHT_BOLD;
1523     }
1524
1525     if (width == -1)
1526         width = FC_WIDTH_NORMAL;
1527
1528     if (foundry == 0)
1529         foundry = (FcChar8 *) "unknown";
1530
1531     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1532         goto bail1;
1533
1534     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1535         goto bail1;
1536
1537     if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1538         goto bail1;
1539
1540     if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1541         goto bail1;
1542
1543     /*
1544      * Compute the unicode coverage for the font
1545      */
1546     cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1547     if (!cs)
1548         goto bail1;
1549
1550 #if HAVE_FT_GET_BDF_PROPERTY
1551     /* For PCF fonts, override the computed spacing with the one from
1552        the property */
1553     if(MY_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1554        prop.type == BDF_PROPERTY_TYPE_ATOM) {
1555         if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1556             spacing = FC_CHARCELL;
1557         else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1558             spacing = FC_MONO;
1559         else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1560             spacing = FC_PROPORTIONAL;
1561     }
1562 #endif
1563
1564     /*
1565      * Skip over PCF fonts that have no encoded characters; they're
1566      * usually just Unicode fonts transcoded to some legacy encoding
1567      */
1568     if (FcCharSetCount (cs) == 0)
1569     {
1570         if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
1571             goto bail2;
1572     }
1573
1574     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1575         goto bail2;
1576
1577     ls = FcFreeTypeLangSet (cs, exclusiveLang);
1578     if (!ls)
1579         goto bail2;
1580
1581     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1582     {
1583         FcLangSetDestroy (ls);
1584         goto bail2;
1585     }
1586
1587     FcLangSetDestroy (ls);
1588
1589     if (spacing != FC_PROPORTIONAL)
1590         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1591             goto bail2;
1592
1593     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1594     {
1595         for (i = 0; i < face->num_fixed_sizes; i++)
1596             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1597                                      FcGetPixelSize (face, i)))
1598                 goto bail1;
1599         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1600             goto bail1;
1601 #if HAVE_FT_GET_BDF_PROPERTY
1602         if(face->num_fixed_sizes == 1) {
1603             int rc;
1604             int value;
1605             BDF_PropertyRec prop;
1606
1607             rc = MY_Get_BDF_Property(face, "POINT_SIZE", &prop);
1608             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1609                 value = prop.u.integer;
1610             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1611                 value = prop.u.cardinal;
1612             else
1613                 goto nevermind;
1614             if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1615                 goto nevermind;
1616
1617             rc = MY_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
1618             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1619                 value = prop.u.integer;
1620             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1621                 value = prop.u.cardinal;
1622             else
1623                 goto nevermind;
1624             if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1625                 goto nevermind;
1626
1627         }
1628     nevermind:
1629         ;
1630 #endif
1631     }
1632 #if HAVE_FT_GET_X11_FONT_FORMAT
1633     /*
1634      * Use the (not well documented or supported) X-specific function
1635      * from FreeType to figure out the font format
1636      */
1637     {
1638         const char *font_format = FT_Get_X11_Font_Format (face);
1639         if (font_format)
1640             FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
1641     }
1642 #endif
1643
1644     /*
1645      * Drop our reference to the charset
1646      */
1647     FcCharSetDestroy (cs);
1648     
1649     /*
1650      * Deallocate family/style values
1651      */
1652     
1653     FT_Done_Face (face);
1654     FT_Done_FreeType (ftLibrary);
1655     return pat;
1656
1657 bail2:
1658     FcCharSetDestroy (cs);
1659 bail1:
1660     FcPatternDestroy (pat);
1661 bail0:
1662     FT_Done_Face (face);
1663 bail:
1664     FT_Done_FreeType (ftLibrary);
1665     return 0;
1666 }
1667
1668
1669 /*
1670  * For our purposes, this approximation is sufficient
1671  */
1672 #if !HAVE_FT_GET_NEXT_CHAR
1673 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1674                                           (*(gi) = 0), 0 : \
1675                                           (*(gi) = 1), (ucs4) + 1)
1676 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1677 #endif
1678
1679 typedef struct _FcCharEnt {
1680     FcChar16        bmp;
1681     unsigned char   encode;
1682 } FcCharEnt;
1683
1684 struct _FcCharMap {
1685     const FcCharEnt *ent;
1686     int             nent;
1687 };
1688
1689 typedef struct _FcFontDecode {
1690     FT_Encoding     encoding;
1691     const FcCharMap *map;
1692     FcChar32        max;
1693 } FcFontDecode;
1694
1695 static const FcCharEnt AppleRomanEnt[] = {
1696     { 0x0020, 0x20 }, /* SPACE */
1697     { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1698     { 0x0022, 0x22 }, /* QUOTATION MARK */
1699     { 0x0023, 0x23 }, /* NUMBER SIGN */
1700     { 0x0024, 0x24 }, /* DOLLAR SIGN */
1701     { 0x0025, 0x25 }, /* PERCENT SIGN */
1702     { 0x0026, 0x26 }, /* AMPERSAND */
1703     { 0x0027, 0x27 }, /* APOSTROPHE */
1704     { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1705     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1706     { 0x002A, 0x2A }, /* ASTERISK */
1707     { 0x002B, 0x2B }, /* PLUS SIGN */
1708     { 0x002C, 0x2C }, /* COMMA */
1709     { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1710     { 0x002E, 0x2E }, /* FULL STOP */
1711     { 0x002F, 0x2F }, /* SOLIDUS */
1712     { 0x0030, 0x30 }, /* DIGIT ZERO */
1713     { 0x0031, 0x31 }, /* DIGIT ONE */
1714     { 0x0032, 0x32 }, /* DIGIT TWO */
1715     { 0x0033, 0x33 }, /* DIGIT THREE */
1716     { 0x0034, 0x34 }, /* DIGIT FOUR */
1717     { 0x0035, 0x35 }, /* DIGIT FIVE */
1718     { 0x0036, 0x36 }, /* DIGIT SIX */
1719     { 0x0037, 0x37 }, /* DIGIT SEVEN */
1720     { 0x0038, 0x38 }, /* DIGIT EIGHT */
1721     { 0x0039, 0x39 }, /* DIGIT NINE */
1722     { 0x003A, 0x3A }, /* COLON */
1723     { 0x003B, 0x3B }, /* SEMICOLON */
1724     { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1725     { 0x003D, 0x3D }, /* EQUALS SIGN */
1726     { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1727     { 0x003F, 0x3F }, /* QUESTION MARK */
1728     { 0x0040, 0x40 }, /* COMMERCIAL AT */
1729     { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1730     { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1731     { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1732     { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1733     { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1734     { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1735     { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1736     { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1737     { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1738     { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1739     { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1740     { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1741     { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1742     { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1743     { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1744     { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1745     { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1746     { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1747     { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1748     { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1749     { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1750     { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1751     { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1752     { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1753     { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1754     { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1755     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1756     { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1757     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1758     { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1759     { 0x005F, 0x5F }, /* LOW LINE */
1760     { 0x0060, 0x60 }, /* GRAVE ACCENT */
1761     { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1762     { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1763     { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1764     { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1765     { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1766     { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1767     { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1768     { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1769     { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1770     { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1771     { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1772     { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1773     { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1774     { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1775     { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1776     { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1777     { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1778     { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1779     { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1780     { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1781     { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1782     { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1783     { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1784     { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1785     { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1786     { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1787     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1788     { 0x007C, 0x7C }, /* VERTICAL LINE */
1789     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1790     { 0x007E, 0x7E }, /* TILDE */
1791     { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1792     { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1793     { 0x00A2, 0xA2 }, /* CENT SIGN */
1794     { 0x00A3, 0xA3 }, /* POUND SIGN */
1795     { 0x00A5, 0xB4 }, /* YEN SIGN */
1796     { 0x00A7, 0xA4 }, /* SECTION SIGN */
1797     { 0x00A8, 0xAC }, /* DIAERESIS */
1798     { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1799     { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1800     { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1801     { 0x00AC, 0xC2 }, /* NOT SIGN */
1802     { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1803     { 0x00AF, 0xF8 }, /* MACRON */
1804     { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1805     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1806     { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1807     { 0x00B5, 0xB5 }, /* MICRO SIGN */
1808     { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1809     { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1810     { 0x00B8, 0xFC }, /* CEDILLA */
1811     { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1812     { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1813     { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1814     { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1815     { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1816     { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1817     { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1818     { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1819     { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1820     { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1821     { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1822     { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1823     { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1824     { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1825     { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1826     { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1827     { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1828     { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1829     { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1830     { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1831     { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1832     { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1833     { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1834     { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1835     { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1836     { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1837     { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1838     { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1839     { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1840     { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1841     { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1842     { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1843     { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1844     { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1845     { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1846     { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1847     { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1848     { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1849     { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1850     { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1851     { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1852     { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1853     { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1854     { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1855     { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1856     { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1857     { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1858     { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1859     { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1860     { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1861     { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1862     { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1863     { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1864     { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1865     { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1866     { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1867     { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1868     { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1869     { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1870     { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1871     { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1872     { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1873     { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1874     { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1875     { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1876     { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1877     { 0x02C7, 0xFF }, /* CARON */
1878     { 0x02D8, 0xF9 }, /* BREVE */
1879     { 0x02D9, 0xFA }, /* DOT ABOVE */
1880     { 0x02DA, 0xFB }, /* RING ABOVE */
1881     { 0x02DB, 0xFE }, /* OGONEK */
1882     { 0x02DC, 0xF7 }, /* SMALL TILDE */
1883     { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1884     { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1885     { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1886     { 0x2013, 0xD0 }, /* EN DASH */
1887     { 0x2014, 0xD1 }, /* EM DASH */
1888     { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1889     { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1890     { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1891     { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1892     { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1893     { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1894     { 0x2020, 0xA0 }, /* DAGGER */
1895     { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
1896     { 0x2022, 0xA5 }, /* BULLET */
1897     { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
1898     { 0x2030, 0xE4 }, /* PER MILLE SIGN */
1899     { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
1900     { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
1901     { 0x2044, 0xDA }, /* FRACTION SLASH */
1902     { 0x20AC, 0xDB }, /* EURO SIGN */
1903     { 0x2122, 0xAA }, /* TRADE MARK SIGN */
1904     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
1905     { 0x2206, 0xC6 }, /* INCREMENT */
1906     { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
1907     { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
1908     { 0x221A, 0xC3 }, /* SQUARE ROOT */
1909     { 0x221E, 0xB0 }, /* INFINITY */
1910     { 0x222B, 0xBA }, /* INTEGRAL */
1911     { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
1912     { 0x2260, 0xAD }, /* NOT EQUAL TO */
1913     { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
1914     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
1915     { 0x25CA, 0xD7 }, /* LOZENGE */
1916     { 0xF8FF, 0xF0 }, /* Apple logo */
1917     { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
1918     { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
1919 };
1920
1921 static const FcCharMap AppleRoman = {
1922     AppleRomanEnt,
1923     sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
1924 };
1925
1926 static const FcCharEnt AdobeSymbolEnt[] = {
1927     { 0x0020, 0x20 }, /* SPACE  # space */
1928     { 0x0021, 0x21 }, /* EXCLAMATION MARK       # exclam */
1929     { 0x0023, 0x23 }, /* NUMBER SIGN    # numbersign */
1930     { 0x0025, 0x25 }, /* PERCENT SIGN   # percent */
1931     { 0x0026, 0x26 }, /* AMPERSAND      # ampersand */
1932     { 0x0028, 0x28 }, /* LEFT PARENTHESIS       # parenleft */
1933     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS      # parenright */
1934     { 0x002B, 0x2B }, /* PLUS SIGN      # plus */
1935     { 0x002C, 0x2C }, /* COMMA  # comma */
1936     { 0x002E, 0x2E }, /* FULL STOP      # period */
1937     { 0x002F, 0x2F }, /* SOLIDUS        # slash */
1938     { 0x0030, 0x30 }, /* DIGIT ZERO     # zero */
1939     { 0x0031, 0x31 }, /* DIGIT ONE      # one */
1940     { 0x0032, 0x32 }, /* DIGIT TWO      # two */
1941     { 0x0033, 0x33 }, /* DIGIT THREE    # three */
1942     { 0x0034, 0x34 }, /* DIGIT FOUR     # four */
1943     { 0x0035, 0x35 }, /* DIGIT FIVE     # five */
1944     { 0x0036, 0x36 }, /* DIGIT SIX      # six */
1945     { 0x0037, 0x37 }, /* DIGIT SEVEN    # seven */
1946     { 0x0038, 0x38 }, /* DIGIT EIGHT    # eight */
1947     { 0x0039, 0x39 }, /* DIGIT NINE     # nine */
1948     { 0x003A, 0x3A }, /* COLON  # colon */
1949     { 0x003B, 0x3B }, /* SEMICOLON      # semicolon */
1950     { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1951     { 0x003D, 0x3D }, /* EQUALS SIGN    # equal */
1952     { 0x003E, 0x3E }, /* GREATER-THAN SIGN      # greater */
1953     { 0x003F, 0x3F }, /* QUESTION MARK  # question */
1954     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET    # bracketleft */
1955     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET   # bracketright */
1956     { 0x005F, 0x5F }, /* LOW LINE       # underscore */
1957     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET     # braceleft */
1958     { 0x007C, 0x7C }, /* VERTICAL LINE  # bar */
1959     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET    # braceright */
1960     { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1961     { 0x00AC, 0xD8 }, /* NOT SIGN       # logicalnot */
1962     { 0x00B0, 0xB0 }, /* DEGREE SIGN    # degree */
1963     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN        # plusminus */
1964     { 0x00B5, 0x6D }, /* MICRO SIGN     # mu */
1965     { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN    # multiply */
1966     { 0x00F7, 0xB8 }, /* DIVISION SIGN  # divide */
1967     { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1968     { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA     # Alpha */
1969     { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA      # Beta */
1970     { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA     # Gamma */
1971     { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA     # Delta */
1972     { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON   # Epsilon */
1973     { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA      # Zeta */
1974     { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA       # Eta */
1975     { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA     # Theta */
1976     { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA      # Iota */
1977     { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA     # Kappa */
1978     { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA     # Lambda */
1979     { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU        # Mu */
1980     { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU        # Nu */
1981     { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI        # Xi */
1982     { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON   # Omicron */
1983     { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI        # Pi */
1984     { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO       # Rho */
1985     { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA     # Sigma */
1986     { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU       # Tau */
1987     { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON   # Upsilon */
1988     { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI       # Phi */
1989     { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI       # Chi */
1990     { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI       # Psi */
1991     { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA     # Omega */
1992     { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA       # alpha */
1993     { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA        # beta */
1994     { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA       # gamma */
1995     { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA       # delta */
1996     { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON     # epsilon */
1997     { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA        # zeta */
1998     { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1999     { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA       # theta */
2000     { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA        # iota */
2001     { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA       # kappa */
2002     { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA       # lambda */
2003     { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU  # mu */
2004     { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU  # nu */
2005     { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI  # xi */
2006     { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON     # omicron */
2007     { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI  # pi */
2008     { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
2009     { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
2010     { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA       # sigma */
2011     { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
2012     { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON     # upsilon */
2013     { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
2014     { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
2015     { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
2016     { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA       # omega */
2017     { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL     # theta1 */
2018     { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
2019     { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL       # phi1 */
2020     { 0x03D6, 0x76 }, /* GREEK PI SYMBOL        # omega1 */
2021     { 0x2022, 0xB7 }, /* BULLET # bullet */
2022     { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS    # ellipsis */
2023     { 0x2032, 0xA2 }, /* PRIME  # minute */
2024     { 0x2033, 0xB2 }, /* DOUBLE PRIME   # second */
2025     { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
2026     { 0x20AC, 0xA0 }, /* EURO SIGN      # Euro */
2027     { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
2028     { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P       # weierstrass */
2029     { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
2030     { 0x2126, 0x57 }, /* OHM SIGN       # Omega */
2031     { 0x2135, 0xC0 }, /* ALEF SYMBOL    # aleph */
2032     { 0x2190, 0xAC }, /* LEFTWARDS ARROW        # arrowleft */
2033     { 0x2191, 0xAD }, /* UPWARDS ARROW  # arrowup */
2034     { 0x2192, 0xAE }, /* RIGHTWARDS ARROW       # arrowright */
2035     { 0x2193, 0xAF }, /* DOWNWARDS ARROW        # arrowdown */
2036     { 0x2194, 0xAB }, /* LEFT RIGHT ARROW       # arrowboth */
2037     { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS  # carriagereturn */
2038     { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
2039     { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW   # arrowdblup */
2040     { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW        # arrowdblright */
2041     { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
2042     { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW        # arrowdblboth */
2043     { 0x2200, 0x22 }, /* FOR ALL        # universal */
2044     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL   # partialdiff */
2045     { 0x2203, 0x24 }, /* THERE EXISTS   # existential */
2046     { 0x2205, 0xC6 }, /* EMPTY SET      # emptyset */
2047     { 0x2206, 0x44 }, /* INCREMENT      # Delta */
2048     { 0x2207, 0xD1 }, /* NABLA  # gradient */
2049     { 0x2208, 0xCE }, /* ELEMENT OF     # element */
2050     { 0x2209, 0xCF }, /* NOT AN ELEMENT OF      # notelement */
2051     { 0x220B, 0x27 }, /* CONTAINS AS MEMBER     # suchthat */
2052     { 0x220F, 0xD5 }, /* N-ARY PRODUCT  # product */
2053     { 0x2211, 0xE5 }, /* N-ARY SUMMATION        # summation */
2054     { 0x2212, 0x2D }, /* MINUS SIGN     # minus */
2055     { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
2056     { 0x2217, 0x2A }, /* ASTERISK OPERATOR      # asteriskmath */
2057     { 0x221A, 0xD6 }, /* SQUARE ROOT    # radical */
2058     { 0x221D, 0xB5 }, /* PROPORTIONAL TO        # proportional */
2059     { 0x221E, 0xA5 }, /* INFINITY       # infinity */
2060     { 0x2220, 0xD0 }, /* ANGLE  # angle */
2061     { 0x2227, 0xD9 }, /* LOGICAL AND    # logicaland */
2062     { 0x2228, 0xDA }, /* LOGICAL OR     # logicalor */
2063     { 0x2229, 0xC7 }, /* INTERSECTION   # intersection */
2064     { 0x222A, 0xC8 }, /* UNION  # union */
2065     { 0x222B, 0xF2 }, /* INTEGRAL       # integral */
2066     { 0x2234, 0x5C }, /* THEREFORE      # therefore */
2067     { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
2068     { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
2069     { 0x2248, 0xBB }, /* ALMOST EQUAL TO        # approxequal */
2070     { 0x2260, 0xB9 }, /* NOT EQUAL TO   # notequal */
2071     { 0x2261, 0xBA }, /* IDENTICAL TO   # equivalence */
2072     { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO  # lessequal */
2073     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO       # greaterequal */
2074     { 0x2282, 0xCC }, /* SUBSET OF      # propersubset */
2075     { 0x2283, 0xC9 }, /* SUPERSET OF    # propersuperset */
2076     { 0x2284, 0xCB }, /* NOT A SUBSET OF        # notsubset */
2077     { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO  # reflexsubset */
2078     { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO        # reflexsuperset */
2079     { 0x2295, 0xC5 }, /* CIRCLED PLUS   # circleplus */
2080     { 0x2297, 0xC4 }, /* CIRCLED TIMES  # circlemultiply */
2081     { 0x22A5, 0x5E }, /* UP TACK        # perpendicular */
2082     { 0x22C5, 0xD7 }, /* DOT OPERATOR   # dotmath */
2083     { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL      # integraltp */
2084     { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL   # integralbt */
2085     { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET    # angleleft */
2086     { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET   # angleright */
2087     { 0x25CA, 0xE0 }, /* LOZENGE        # lozenge */
2088     { 0x2660, 0xAA }, /* BLACK SPADE SUIT       # spade */
2089     { 0x2663, 0xA7 }, /* BLACK CLUB SUIT        # club */
2090     { 0x2665, 0xA9 }, /* BLACK HEART SUIT       # heart */
2091     { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT     # diamond */
2092     { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF   # copyrightserif (CUS) */
2093     { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF  # registerserif (CUS) */
2094     { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF  # trademarkserif (CUS) */
2095     { 0xF8E5, 0x60 }, /* RADICAL EXTENDER       # radicalex (CUS) */
2096     { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER        # arrowvertex (CUS) */
2097     { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER      # arrowhorizex (CUS) */
2098     { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF     # registersans (CUS) */
2099     { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF      # copyrightsans (CUS) */
2100     { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF     # trademarksans (CUS) */
2101     { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2102     { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER    # parenleftex (CUS) */
2103     { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM      # parenleftbt (CUS) */
2104     { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP        # bracketlefttp (CUS) */
2105     { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER   # bracketleftex (CUS) */
2106     { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM     # bracketleftbt (CUS) */
2107     { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2108     { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2109     { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM      # braceleftbt (CUS) */
2110     { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2111     { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER      # integralex (CUS) */
2112     { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP        # parenrighttp (CUS) */
2113     { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER   # parenrightex (CUS) */
2114     { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM     # parenrightbt (CUS) */
2115     { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP       # bracketrighttp (CUS) */
2116     { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER  # bracketrightex (CUS) */
2117     { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM    # bracketrightbt (CUS) */
2118     { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP        # bracerighttp (CUS) */
2119     { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID        # bracerightmid (CUS) */
2120     { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM     # bracerightbt (CUS) */
2121 };
2122
2123 static const FcCharMap AdobeSymbol = {
2124     AdobeSymbolEnt,
2125     sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2126 };
2127     
2128 static const FcFontDecode fcFontDecoders[] = {
2129     { ft_encoding_unicode,      0,              (1 << 21) - 1 },
2130     { ft_encoding_symbol,       &AdobeSymbol,   (1 << 16) - 1 },
2131     { ft_encoding_apple_roman,  &AppleRoman,    (1 << 16) - 1 },
2132 };
2133
2134 #define NUM_DECODE  (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
2135
2136 static const FcChar32   prefer_unicode[] = {
2137     0x20ac,     /* EURO SIGN */
2138 };
2139
2140 #define NUM_PREFER_UNICODE  (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
2141
2142 FcChar32
2143 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2144 {
2145     int         low, high, mid;
2146     FcChar16    bmp;
2147
2148     low = 0;
2149     high = map->nent - 1;
2150     if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2151         return ~0;
2152     while (low <= high)
2153     {
2154         mid = (high + low) >> 1;
2155         bmp = map->ent[mid].bmp;
2156         if (ucs4 == bmp)
2157             return (FT_ULong) map->ent[mid].encode;
2158         if (ucs4 < bmp)
2159             high = mid - 1;
2160         else
2161             low = mid + 1;
2162     }
2163     return ~0;
2164 }
2165
2166 FcChar32
2167 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2168 {
2169     int     i;
2170
2171     for (i = 0; i < map->nent; i++)
2172         if (map->ent[i].encode == private)
2173             return (FcChar32) map->ent[i].bmp;
2174     return ~0;
2175 }
2176
2177 const FcCharMap *
2178 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2179 {
2180     int i;
2181
2182     for (i = 0; i < NUM_DECODE; i++)
2183         if (fcFontDecoders[i].encoding == encoding)
2184             return fcFontDecoders[i].map;
2185     return 0;
2186 }
2187
2188 #include "../fc-glyphname/fcglyphname.h"
2189
2190 static FcChar32
2191 FcHashGlyphName (const FcChar8 *name)
2192 {
2193     FcChar32    h = 0;
2194     FcChar8     c;
2195
2196     while ((c = *name++))
2197     {
2198         h = ((h << 1) | (h >> 31)) ^ c;
2199     }
2200     return h;
2201 }
2202
2203 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2204 /*
2205  * Use Type1 glyph names for fonts which have reliable names
2206  * and which export an Adobe Custom mapping
2207  */
2208 static FcBool
2209 FcFreeTypeUseNames (FT_Face face)
2210 {
2211     FT_Int  map;
2212     
2213     if (!FT_Has_PS_Glyph_Names (face))
2214         return FcFalse;
2215     for (map = 0; map < face->num_charmaps; map++)
2216         if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2217             return FcTrue;
2218     return FcFalse;
2219 }
2220
2221 static const FcChar8 *
2222 FcUcs4ToGlyphName (FcChar32 ucs4)
2223 {
2224     int         i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2225     int         r = 0;
2226     const FcGlyphName   *gn;
2227
2228     while ((gn = ucs_to_name[i]))
2229     {
2230         if (gn->ucs == ucs4)
2231             return gn->name;
2232         if (!r) 
2233         {
2234             r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2235             if (!r)
2236                 r = 1;
2237         }
2238         i += r;
2239         if (i >= FC_GLYPHNAME_HASH)
2240             i -= FC_GLYPHNAME_HASH;
2241     }
2242     return 0;
2243 }
2244
2245 static FcChar32
2246 FcGlyphNameToUcs4 (FcChar8 *name)
2247 {
2248     FcChar32    h = FcHashGlyphName (name);
2249     int         i = (int) (h % FC_GLYPHNAME_HASH);
2250     int         r = 0;
2251     const FcGlyphName   *gn;
2252
2253     while ((gn = name_to_ucs[i]))
2254     {
2255         if (!strcmp ((char *) name, (char *) gn->name))
2256             return gn->ucs;
2257         if (!r) 
2258         {
2259             r = (int) (h % FC_GLYPHNAME_REHASH);
2260             if (!r)
2261                 r = 1;
2262         }
2263         i += r;
2264         if (i >= FC_GLYPHNAME_HASH)
2265             i -= FC_GLYPHNAME_HASH;
2266     }
2267     return 0xffff;
2268 }
2269
2270 /*
2271  * Search through a font for a glyph by name.  This is
2272  * currently a linear search as there doesn't appear to be
2273  * any defined order within the font
2274  */
2275 static FT_UInt
2276 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2277 {
2278     FT_UInt gindex;
2279     FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2280
2281     for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2282     {
2283         if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2284             if (!strcmp ((char *) name, (char *) name_buf))
2285                 return gindex;
2286     }
2287     return 0;
2288 }
2289 #endif
2290
2291 /*
2292  * Map a UCS4 glyph to a glyph index.  Use all available encoding
2293  * tables to try and find one that works.  This information is expected
2294  * to be cached by higher levels, so performance isn't critical
2295  */
2296
2297 FT_UInt
2298 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2299 {
2300     int             initial, offset, decode;
2301     FT_UInt         glyphindex;
2302     FcChar32        charcode;
2303     int             p;
2304
2305     initial = 0;
2306     /*
2307      * Find the current encoding
2308      */
2309     if (face->charmap)
2310     {
2311         for (; initial < NUM_DECODE; initial++)
2312             if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2313                 break;
2314         if (initial == NUM_DECODE)
2315             initial = 0;
2316     }
2317     for (p = 0; p < NUM_PREFER_UNICODE; p++)
2318         if (ucs4 == prefer_unicode[p])
2319         {
2320             initial = 0;
2321             break;
2322         }
2323     /*
2324      * Check each encoding for the glyph, starting with the current one
2325      */
2326     for (offset = 0; offset < NUM_DECODE; offset++)
2327     {
2328         decode = (initial + offset) % NUM_DECODE;
2329         if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2330             if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2331                 continue;
2332         if (fcFontDecoders[decode].map)
2333         {
2334             charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2335             if (charcode == ~0U)
2336                 continue;
2337         }
2338         else
2339             charcode = ucs4;
2340         glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2341         if (glyphindex)
2342             return glyphindex;
2343     }
2344 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2345     /*
2346      * Check postscript name table if present
2347      */
2348     if (FcFreeTypeUseNames (face))
2349     {
2350         const FcChar8   *name = FcUcs4ToGlyphName (ucs4);
2351         if (name)
2352         {
2353             glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2354             if (glyphindex)
2355                 return glyphindex;
2356         }
2357     }
2358 #endif
2359     return 0;
2360 }
2361
2362 static FcBool
2363 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, 
2364                       FT_UInt glyph, FcBlanks *blanks,
2365                       FT_Pos *advance)
2366 {
2367     FT_Int          load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2368     FT_GlyphSlot    slot;
2369     
2370     /*
2371      * When using scalable fonts, only report those glyphs
2372      * which can be scaled; otherwise those fonts will
2373      * only be available at some sizes, and never when
2374      * transformed.  Avoid this by simply reporting bitmap-only
2375      * glyphs as missing
2376      */
2377     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2378         load_flags |= FT_LOAD_NO_BITMAP;
2379     
2380     if (FT_Load_Glyph (face, glyph, load_flags))
2381         return FcFalse;
2382     
2383     slot = face->glyph;
2384     if (!glyph)
2385         return FcFalse;
2386     
2387     *advance = slot->metrics.horiAdvance;
2388
2389     switch (slot->format) {
2390     case ft_glyph_format_bitmap:
2391         /*
2392          * Bitmaps are assumed to be reasonable; if
2393          * this proves to be a rash assumption, this
2394          * code can be easily modified
2395          */
2396         return FcTrue;
2397     case ft_glyph_format_outline:
2398         /*
2399          * Glyphs with contours are always OK
2400          */
2401         if (slot->outline.n_contours != 0)
2402             return FcTrue;
2403         /*
2404          * Glyphs with no contours are only OK if
2405          * they're members of the Blanks set specified
2406          * in the configuration.  If blanks isn't set,
2407          * then allow any glyph to be blank
2408          */
2409         if (!blanks || FcBlanksIsMember (blanks, ucs4))
2410             return FcTrue;
2411         /* fall through ... */
2412     default:
2413         break;
2414     }
2415     return FcFalse;
2416 }
2417
2418 #define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
2419 #define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
2420 #define FC_ABS(a)   ((a) < 0 ? -(a) : (a))
2421 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2422
2423 FcCharSet *
2424 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2425 {
2426     FcChar32        page, off, max, ucs4;
2427 #ifdef CHECK
2428     FcChar32        font_max = 0;
2429 #endif
2430     FcCharSet       *fcs;
2431     FcCharLeaf      *leaf;
2432     const FcCharMap *map;
2433     int             o;
2434     int             i;
2435     FT_UInt         glyph;
2436     FT_Pos          advance, advance_one = 0, advance_two = 0;
2437     FcBool          has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2438
2439     fcs = FcCharSetCreate ();
2440     if (!fcs)
2441         goto bail0;
2442     
2443 #ifdef CHECK
2444     printf ("Family %s style %s\n", face->family_name, face->style_name);
2445 #endif
2446     for (o = 0; o < NUM_DECODE; o++)
2447     {
2448         if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2449             continue;
2450         map = fcFontDecoders[o].map;
2451         if (map)
2452         {
2453             /*
2454              * Non-Unicode tables are easy; there's a list of all possible
2455              * characters
2456              */
2457             for (i = 0; i < map->nent; i++)
2458             {
2459                 ucs4 = map->ent[i].bmp;
2460                 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2461                 if (glyph && 
2462                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2463                 {
2464                     /* 
2465                      * ignore glyphs with zero advance. They’re
2466                      * combining characters, and while their behaviour
2467                      * isn’t well defined for monospaced applications in
2468                      * Unicode, there are many fonts which include
2469                      * zero-width combining characters in otherwise
2470                      * monospaced fonts.
2471                      */
2472                     if (advance)
2473                     {
2474                         if (!has_advance)
2475                         {
2476                             has_advance = FcTrue;
2477                             advance_one = advance;
2478                         }
2479                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2480                         {
2481                             if (fixed_advance)
2482                             {
2483                                 dual_advance = FcTrue;
2484                                 fixed_advance = FcFalse;
2485                                 advance_two = advance;
2486                             }
2487                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2488                                 dual_advance = FcFalse;
2489                         }
2490                     }
2491
2492                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2493                     if (!leaf)
2494                         goto bail1;
2495                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2496 #ifdef CHECK
2497                     if (ucs4 > font_max)
2498                         font_max = ucs4;
2499 #endif
2500                 }
2501             }
2502         }
2503         else
2504         {
2505             FT_UInt gindex;
2506           
2507             max = fcFontDecoders[o].max;
2508             /*
2509              * Find the first encoded character in the font
2510              */
2511             if (FT_Get_Char_Index (face, 0))
2512             {
2513                 ucs4 = 0;
2514                 gindex = 1;
2515             }
2516             else
2517             {
2518                 ucs4 = FT_Get_Next_Char (face, 0, &gindex);
2519                 if (!ucs4)
2520                     gindex = 0;
2521             }
2522
2523             while (gindex)
2524             {
2525                 page = ucs4 >> 8;
2526                 leaf = 0;
2527                 while ((ucs4 >> 8) == page)
2528                 {
2529                     glyph = FT_Get_Char_Index (face, ucs4);
2530                     if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
2531                                                        glyph, blanks, &advance))
2532                     {
2533                         if (advance)
2534                         {
2535                             if (!has_advance)
2536                             {
2537                                 has_advance = FcTrue;
2538                                 advance_one = advance;
2539                             }
2540                             else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2541                             {
2542                                 if (fixed_advance)
2543                                 {
2544                                     dual_advance = FcTrue;
2545                                     fixed_advance = FcFalse;
2546                                     advance_two = advance;
2547                                 }
2548                                 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2549                                     dual_advance = FcFalse;
2550                             }
2551                         }
2552
2553                         if (!leaf)
2554                         {
2555                             leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2556                             if (!leaf)
2557                                 goto bail1;
2558                         }
2559                         off = ucs4 & 0xff;
2560                         leaf->map[off >> 5] |= (1 << (off & 0x1f));
2561 #ifdef CHECK
2562                         if (ucs4 > font_max)
2563                             font_max = ucs4;
2564 #endif
2565                     }
2566                     ucs4++;
2567                 }
2568                 ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
2569                 if (!ucs4)
2570                     gindex = 0;
2571             }
2572 #ifdef CHECK
2573             for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2574             {
2575                 FcBool      FT_Has, FC_Has;
2576
2577                 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2578                 FC_Has = FcCharSetHasChar (fcs, ucs4);
2579                 if (FT_Has != FC_Has)
2580                 {
2581                     printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2582                 }
2583             }
2584 #endif
2585         }
2586     }
2587 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2588     /*
2589      * Add mapping from PS glyph names if available
2590      */
2591     if (FcFreeTypeUseNames (face))
2592     {
2593         FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2594
2595         for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2596         {
2597             if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2598             {
2599                 ucs4 = FcGlyphNameToUcs4 (name_buf);
2600                 if (ucs4 != 0xffff && 
2601                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2602                 {
2603                     if (advance)
2604                     {
2605                         if (!has_advance)
2606                         {
2607                             has_advance = FcTrue;
2608                             advance_one = advance;
2609                         }
2610                         else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2611                         {
2612                             if (fixed_advance)
2613                             {
2614                                 dual_advance = FcTrue;
2615                                 fixed_advance = FcFalse;
2616                                 advance_two = advance;
2617                             }
2618                             else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2619                                 dual_advance = FcFalse;
2620                         }
2621                     }
2622                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2623                     if (!leaf)
2624                         goto bail1;
2625                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2626 #ifdef CHECK
2627                     if (ucs4 > font_max)
2628                         font_max = ucs4;
2629 #endif
2630                 }
2631             }
2632         }
2633     }
2634 #endif
2635 #ifdef CHECK
2636     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2637     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2638     {
2639         FcBool  has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2640         FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
2641
2642         if (has_char && !has_bit)
2643         {
2644             if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2645                 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2646             else
2647                 printf ("Bitmap missing char 0x%x\n", ucs4);
2648         }
2649         else if (!has_char && has_bit)
2650             printf ("Bitmap extra char 0x%x\n", ucs4);
2651     }
2652 #endif
2653     if (fixed_advance)
2654         *spacing = FC_MONO;
2655     else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2656         *spacing = FC_DUAL;
2657     else
2658         *spacing = FC_PROPORTIONAL;
2659     return fcs;
2660 bail1:
2661     FcCharSetDestroy (fcs);
2662 bail0:
2663     return 0;
2664 }
2665
2666 FcCharSet *
2667 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2668 {
2669     int spacing;
2670
2671     return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2672 }
2673
2674
2675 #define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2676 #define TTAG_GSUB  FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2677 #define TTAG_SILF  FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2678 #define TT_Err_Ok FT_Err_Ok
2679 #define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
2680 #define TTO_Err_Empty_Script              0x1005
2681 #define TTO_Err_Invalid_SubTable          0x1001
2682
2683 #define OTLAYOUT_HEAD       "otlayout:"
2684 #define OTLAYOUT_HEAD_LEN   9
2685 #define OTLAYOUT_ID_LEN     4
2686 /* space + head + id */
2687 #define OTLAYOUT_LEN        (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2688
2689 /*
2690  * This is a bit generous; the registry has only lower case and space
2691  * except for 'DFLT'.
2692  */
2693 #define FcIsSpace(x)        (040 == (x))
2694 #define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2695                              
2696 static void
2697 addtag(FcChar8 *complex, FT_ULong tag)
2698 {
2699     FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2700
2701     tagstring[0] = (FcChar8)(tag >> 24),
2702     tagstring[1] = (FcChar8)(tag >> 16),
2703     tagstring[2] = (FcChar8)(tag >> 8),
2704     tagstring[3] = (FcChar8)(tag);
2705     tagstring[4] = '\0';
2706     
2707     /* skip tags which aren't alphabetic, under the assumption that
2708      * they're probably broken
2709      */
2710     if (!FcIsValidScript(tagstring[0]) ||
2711         !FcIsValidScript(tagstring[1]) ||
2712         !FcIsValidScript(tagstring[2]) ||
2713         !FcIsValidScript(tagstring[3]))
2714         return;
2715
2716     if (*complex != '\0')
2717         strcat ((char *) complex, " ");
2718     strcat ((char *) complex, "otlayout:");
2719     strcat ((char *) complex, (char *) tagstring);
2720 }
2721
2722 static int
2723 compareulong (const void *a, const void *b)
2724 {
2725     const FT_ULong *ua = (const FT_ULong *) a;
2726     const FT_ULong *ub = (const FT_ULong *) b;
2727     return *ua - *ub;
2728 }
2729
2730
2731 static FT_Error
2732 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
2733 {
2734     FT_ULong         cur_offset, new_offset, base_offset;
2735     TT_Face          tt_face = (TT_Face)face;
2736     FT_Stream  stream = face->stream;
2737     FT_Error   error;
2738     FT_UShort          n, p;
2739     FT_Memory  memory = stream->memory;
2740
2741     if ( !stream )
2742         return TT_Err_Invalid_Face_Handle;
2743
2744     if (( error = tt_face->goto_table( tt_face, tabletag, stream, 0 ) ))
2745         return error;
2746
2747     base_offset = FT_STREAM_POS();
2748
2749     /* skip version */
2750
2751     if ( FT_STREAM_SEEK( base_offset + 4L ) || FT_FRAME_ENTER( 2L ) )
2752         return error;
2753
2754     new_offset = FT_GET_USHORT() + base_offset;
2755
2756     FT_FRAME_EXIT();
2757
2758     cur_offset = FT_STREAM_POS();
2759
2760     if ( FT_STREAM_SEEK( new_offset ) != TT_Err_Ok )
2761         return error;
2762
2763     base_offset = FT_STREAM_POS();
2764
2765     if ( FT_FRAME_ENTER( 2L ) )
2766         return error;
2767
2768     *script_count = FT_GET_USHORT();
2769
2770     FT_FRAME_EXIT();
2771
2772     if ( FT_SET_ERROR (FT_MEM_ALLOC_ARRAY( *stags, *script_count, FT_ULong )) )
2773         return error;
2774
2775     p = 0;
2776     for ( n = 0; n < *script_count; n++ )
2777     {
2778         if ( FT_FRAME_ENTER( 6L ) )
2779             goto Fail;
2780
2781         (*stags)[p] = FT_GET_ULONG();
2782         new_offset = FT_GET_USHORT() + base_offset;
2783
2784         FT_FRAME_EXIT();
2785
2786         cur_offset = FT_STREAM_POS();
2787
2788         if ( FT_STREAM_SEEK( new_offset ) )
2789             goto Fail;
2790
2791         if ( error == TT_Err_Ok )
2792             p++;
2793         else if ( error != TTO_Err_Empty_Script )
2794             goto Fail;
2795
2796         (void)FT_STREAM_SEEK( cur_offset );
2797     }
2798
2799     if (!p)
2800     {
2801         error = TTO_Err_Invalid_SubTable;
2802         goto Fail;
2803     }
2804
2805     // sort the tag list before returning it
2806     qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
2807
2808     return TT_Err_Ok;
2809
2810 Fail:
2811     *script_count = 0;
2812     FT_FREE( *stags );
2813     return error;
2814 }
2815
2816 static FcChar8 *
2817 FcFontCapabilities(FT_Face face)
2818 {
2819     FcBool issilgraphitefont = 0;
2820     FT_Error err;
2821     FT_ULong len = 0;
2822     FT_ULong *gsubtags=NULL, *gpostags=NULL;
2823     FT_UShort gsub_count=0, gpos_count=0;
2824     FT_ULong maxsize;
2825     FT_Memory  memory = face->stream->memory;
2826     FcChar8 *complex = NULL;
2827     int indx1 = 0, indx2 = 0;
2828
2829     err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2830     issilgraphitefont = ( err == FT_Err_Ok);
2831
2832     if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
2833         gpos_count = 0;
2834     if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
2835         gsub_count = 0;
2836     
2837     if (!issilgraphitefont && !gsub_count && !gpos_count)
2838         goto bail;
2839
2840     maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN + 
2841                (issilgraphitefont ? 13 : 0));
2842     complex = malloc (sizeof (FcChar8) * maxsize);
2843     if (!complex)
2844         goto bail;
2845
2846     complex[0] = '\0';
2847     if (issilgraphitefont)
2848         strcpy((char *) complex, "ttable:Silf ");
2849
2850     while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2851         if (indx1 == gsub_count) {
2852             addtag(complex, gpostags[indx2]);
2853             indx2++;
2854         } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2855             addtag(complex, gsubtags[indx1]);
2856             indx1++;
2857         } else if (gsubtags[indx1] == gpostags[indx2]) {
2858             addtag(complex, gsubtags[indx1]);
2859             indx1++;
2860             indx2++;
2861         } else {
2862             addtag(complex, gpostags[indx2]);
2863             indx2++;
2864         }
2865     }
2866     if (FcDebug () & FC_DBG_SCANV)
2867         printf("complex features in this font: %s\n", complex);
2868 bail:
2869     FT_FREE(gsubtags);
2870     FT_FREE(gpostags);
2871     return complex;
2872 }