source: trunk/poppler/fontconfig-2.3.2-os2/src/fcfreetype.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

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