]> git.wh0rd.org - fontconfig.git/blob - src/fcfreetype.c
Create FC_FONTFORMAT from FT_Get_X11_Font_Format function where available.
[fontconfig.git] / src / fcfreetype.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcfreetype.c,v 1.11 2002/08/31 22:17:32 keithp Exp $
3 *
4 * Copyright © 2001 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 /*
26 Copyright © 2002-2003 by Juliusz Chroboczek
27
28 Permission is hereby granted, free of charge, to any person obtaining a copy
29 of this software and associated documentation files (the "Software"), to deal
30 in the Software without restriction, including without limitation the rights
31 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 copies of the Software, and to permit persons to whom the Software is
33 furnished to do so, subject to the following conditions:
34
35 The above copyright notice and this permission notice shall be included in
36 all copies or substantial portions of the Software.
37
38 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 THE SOFTWARE.
45 */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include "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
88 static 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
100 FcBool
101 FcFreeTypeIsExclusiveLang (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
113 typedef 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
122 static 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, "Johap" },
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
140 typedef 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
148 static 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
550 typedef struct {
551 FT_UShort language_id;
552 char *fromcode;
553 } FcMacRomanFake;
554
555 static const FcMacRomanFake fcMacRomanFake[] = {
556 { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" },
557 { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" },
558 };
559
560 static FcChar8 *
561 FcFontCapabilities(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
570 static FcChar8 *
571 FcSfntNameTranscode (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 USE_ICONV
610 cd = iconv_open ("UTF-8", fromcode);
611 if (cd)
612 {
613 size_t in_bytes_left = sname->string_len;
614 size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
615 char *inbuf, *outbuf;
616
617 utf8 = malloc (out_bytes_left + 1);
618 if (!utf8)
619 return 0;
620
621 outbuf = (char *) utf8;
622 inbuf = (char *) sname->string;
623
624 while (in_bytes_left)
625 {
626 size_t did = iconv (cd,
627 &inbuf, &in_bytes_left,
628 &outbuf, &out_bytes_left);
629 if (did == (size_t) (-1))
630 {
631 free (utf8);
632 return 0;
633 }
634 }
635 *outbuf = '\0';
636 goto done;
637 }
638 #endif
639 if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
640 {
641 FcChar8 *src = sname->string;
642 int src_len = sname->string_len;
643 int len;
644 int wchar;
645 int ilen, olen;
646 FcChar8 *u8;
647 FcChar32 ucs4;
648
649 /*
650 * Convert Utf16 to Utf8
651 */
652
653 if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
654 return 0;
655
656 /*
657 * Allocate plenty of space. Freed below
658 */
659 utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
660 if (!utf8)
661 return 0;
662
663 u8 = utf8;
664
665 while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
666 {
667 src_len -= ilen;
668 src += ilen;
669 olen = FcUcs4ToUtf8 (ucs4, u8);
670 u8 += olen;
671 }
672 *u8 = '\0';
673 goto done;
674 }
675 if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
676 {
677 FcChar8 *src = sname->string;
678 int src_len = sname->string_len;
679 int olen;
680 FcChar8 *u8;
681 FcChar32 ucs4;
682
683 /*
684 * Convert Latin1 to Utf8. Freed below
685 */
686 utf8 = malloc (src_len * 2 + 1);
687 if (!utf8)
688 return 0;
689
690 u8 = utf8;
691 while (src_len > 0)
692 {
693 ucs4 = *src++;
694 src_len--;
695 olen = FcUcs4ToUtf8 (ucs4, u8);
696 u8 += olen;
697 }
698 *u8 = '\0';
699 goto done;
700 }
701 if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
702 {
703 FcChar8 *u8;
704 const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
705 FcChar8 *src = (FcChar8 *) sname->string;
706 int src_len = sname->string_len;
707
708 /*
709 * Convert AppleRoman to Utf8
710 */
711 if (!map)
712 return 0;
713
714 utf8 = malloc (sname->string_len * 3 + 1);
715 if (!utf8)
716 return 0;
717
718 u8 = utf8;
719 while (src_len > 0)
720 {
721 FcChar32 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
722 int olen = FcUcs4ToUtf8 (ucs4, u8);
723 src_len--;
724 u8 += olen;
725 }
726 *u8 = '\0';
727 goto done;
728 }
729 return 0;
730 done:
731 if (FcStrCmpIgnoreBlanksAndCase (utf8, "") == 0)
732 {
733 free (utf8);
734 return 0;
735 }
736 return utf8;
737 }
738
739 static FcChar8 *
740 FcSfntNameLanguage (FT_SfntName *sname)
741 {
742 int i;
743 for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
744 if (fcFtLanguage[i].platform_id == sname->platform_id &&
745 (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
746 fcFtLanguage[i].language_id == sname->language_id))
747 return fcFtLanguage[i].lang;
748 return 0;
749 }
750
751 /* Order is significant. For example, some B&H fonts are hinted by
752 URW++, and both strings appear in the notice. */
753
754 static const struct {
755 const FT_String *notice;
756 const FcChar8 *foundry;
757 } FcNoticeFoundries[] = {
758 { (const FT_String *) "Bigelow", (const FcChar8 *) "b&h" },
759 { (const FT_String *) "Adobe", (const FcChar8 *) "adobe" },
760 { (const FT_String *) "Bitstream", (const FcChar8 *) "bitstream" },
761 { (const FT_String *) "Monotype", (const FcChar8 *) "monotype" },
762 { (const FT_String *) "Linotype", (const FcChar8 *) "linotype" },
763 { (const FT_String *) "LINOTYPE-HELL",
764 (const FcChar8 *) "linotype" },
765 { (const FT_String *) "IBM", (const FcChar8 *) "ibm" },
766 { (const FT_String *) "URW", (const FcChar8 *) "urw" },
767 { (const FT_String *) "International Typeface Corporation",
768 (const FcChar8 *) "itc" },
769 { (const FT_String *) "Tiro Typeworks",
770 (const FcChar8 *) "tiro" },
771 { (const FT_String *) "XFree86", (const FcChar8 *) "xfree86" },
772 { (const FT_String *) "Microsoft", (const FcChar8 *) "microsoft" },
773 { (const FT_String *) "Omega", (const FcChar8 *) "omega" },
774 { (const FT_String *) "Font21", (const FcChar8 *) "hwan" },
775 { (const FT_String *) "HanYang System",
776 (const FcChar8 *) "hanyang" }
777 };
778
779 #define NUM_NOTICE_FOUNDRIES (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
780
781 static const FcChar8 *
782 FcNoticeFoundry(const FT_String *notice)
783 {
784 int i;
785
786 if (notice)
787 for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
788 if (strstr ((const char *) notice, (const char *) FcNoticeFoundries[i].notice))
789 return FcNoticeFoundries[i].foundry;
790 return 0;
791 }
792
793 static FcBool
794 FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
795 {
796 /* vendor is not necessarily NUL-terminated. */
797 int i, len;
798
799 len = strlen(vendor_string);
800 if (memcmp(vendor, vendor_string, len) != 0)
801 return FcFalse;
802 for (i = len; i < 4; i++)
803 if (vendor[i] != ' ' && vendor[i] != '\0')
804 return FcFalse;
805 return FcTrue;
806 }
807
808 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
809
810 /* It should not contain useless entries (such as UNKN) nor duplicate
811 entries for padding both with spaces and NULs. */
812
813 static const struct {
814 const FT_Char *vendor;
815 const FcChar8 *foundry;
816 } FcVendorFoundries[] = {
817 { (const FT_Char *) "ADBE", (const FcChar8 *) "adobe"},
818 { (const FT_Char *) "AGFA", (const FcChar8 *) "agfa"},
819 { (const FT_Char *) "ALTS", (const FcChar8 *) "altsys"},
820 { (const FT_Char *) "APPL", (const FcChar8 *) "apple"},
821 { (const FT_Char *) "ARPH", (const FcChar8 *) "arphic"},
822 { (const FT_Char *) "ATEC", (const FcChar8 *) "alltype"},
823 { (const FT_Char *) "B&H", (const FcChar8 *) "b&h"},
824 { (const FT_Char *) "BITS", (const FcChar8 *) "bitstream"},
825 { (const FT_Char *) "CANO", (const FcChar8 *) "cannon"},
826 { (const FT_Char *) "DYNA", (const FcChar8 *) "dynalab"},
827 { (const FT_Char *) "EPSN", (const FcChar8 *) "epson"},
828 { (const FT_Char *) "FJ", (const FcChar8 *) "fujitsu"},
829 { (const FT_Char *) "IBM", (const FcChar8 *) "ibm"},
830 { (const FT_Char *) "ITC", (const FcChar8 *) "itc"},
831 { (const FT_Char *) "IMPR", (const FcChar8 *) "impress"},
832 { (const FT_Char *) "LARA", (const FcChar8 *) "larabiefonts"},
833 { (const FT_Char *) "LEAF", (const FcChar8 *) "interleaf"},
834 { (const FT_Char *) "LETR", (const FcChar8 *) "letraset"},
835 { (const FT_Char *) "LINO", (const FcChar8 *) "linotype"},
836 { (const FT_Char *) "MACR", (const FcChar8 *) "macromedia"},
837 { (const FT_Char *) "MONO", (const FcChar8 *) "monotype"},
838 { (const FT_Char *) "MS", (const FcChar8 *) "microsoft"},
839 { (const FT_Char *) "MT", (const FcChar8 *) "monotype"},
840 { (const FT_Char *) "NEC", (const FcChar8 *) "nec"},
841 { (const FT_Char *) "PARA", (const FcChar8 *) "paratype"},
842 { (const FT_Char *) "QMSI", (const FcChar8 *) "qms"},
843 { (const FT_Char *) "RICO", (const FcChar8 *) "ricoh"},
844 { (const FT_Char *) "URW", (const FcChar8 *) "urw"},
845 { (const FT_Char *) "Y&Y", (const FcChar8 *) "y&y"}
846 };
847
848 #define NUM_VENDOR_FOUNDRIES (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
849
850 static const FcChar8 *
851 FcVendorFoundry(const FT_Char vendor[4])
852 {
853 int i;
854
855 if (vendor)
856 for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
857 if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
858 return FcVendorFoundries[i].foundry;
859 return 0;
860 }
861
862 typedef struct _FcStringConst {
863 const FcChar8 *name;
864 int value;
865 } FcStringConst;
866
867 static int
868 FcStringIsConst (const FcChar8 *string,
869 const FcStringConst *c,
870 int nc)
871 {
872 int i;
873
874 for (i = 0; i < nc; i++)
875 if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
876 return c[i].value;
877 return -1;
878 }
879
880 static int
881 FcStringContainsConst (const FcChar8 *string,
882 const FcStringConst *c,
883 int nc)
884 {
885 int i;
886
887 for (i = 0; i < nc; i++)
888 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
889 return c[i].value;
890 return -1;
891 }
892
893 static const FcStringConst weightConsts[] = {
894 { "thin", FC_WEIGHT_THIN },
895 { "extralight", FC_WEIGHT_EXTRALIGHT },
896 { "ultralight", FC_WEIGHT_ULTRALIGHT },
897 { "light", FC_WEIGHT_LIGHT },
898 { "book", FC_WEIGHT_BOOK },
899 { "regular", FC_WEIGHT_REGULAR },
900 { "normal", FC_WEIGHT_NORMAL },
901 { "medium", FC_WEIGHT_MEDIUM },
902 { "demibold", FC_WEIGHT_DEMIBOLD },
903 { "demi", FC_WEIGHT_DEMIBOLD },
904 { "semibold", FC_WEIGHT_SEMIBOLD },
905 { "bold", FC_WEIGHT_BOLD },
906 { "extrabold", FC_WEIGHT_EXTRABOLD },
907 { "ultrabold", FC_WEIGHT_ULTRABOLD },
908 { "black", FC_WEIGHT_BLACK },
909 { "heavy", FC_WEIGHT_HEAVY },
910 };
911
912 #define NUM_WEIGHT_CONSTS (sizeof (weightConsts) / sizeof (weightConsts[0]))
913
914 #define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
915 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
916
917 static const FcStringConst widthConsts[] = {
918 { "ultracondensed", FC_WIDTH_ULTRACONDENSED },
919 { "extracondensed", FC_WIDTH_EXTRACONDENSED },
920 { "semicondensed", FC_WIDTH_SEMICONDENSED },
921 { "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
922 { "normal", FC_WIDTH_NORMAL },
923 { "semiexpanded", FC_WIDTH_SEMIEXPANDED },
924 { "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
925 { "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
926 { "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
927 };
928
929 #define NUM_WIDTH_CONSTS (sizeof (widthConsts) / sizeof (widthConsts[0]))
930
931 #define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
932 #define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
933
934 static const FcStringConst slantConsts[] = {
935 { "italic", FC_SLANT_ITALIC },
936 { "oblique", FC_SLANT_OBLIQUE },
937 };
938
939 #define NUM_SLANT_CONSTS (sizeof (slantConsts) / sizeof (slantConsts[0]))
940
941 #define FcIsSlant(s) FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
942 #define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
943
944 static double
945 FcGetPixelSize (FT_Face face, int i)
946 {
947 #if HAVE_FT_GET_BDF_PROPERTY
948 if (face->num_fixed_sizes == 1)
949 {
950 BDF_PropertyRec prop;
951 int rc;
952
953 rc = MY_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
954 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
955 return (double) prop.u.integer;
956 }
957 #endif
958 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
959 return (double) face->available_sizes[i].y_ppem / 64.0;
960 #else
961 return (double) face->available_sizes[i].height;
962 #endif
963 }
964
965 static FcBool
966 FcStringInPatternElement (FcPattern *pat, char *elt, FcChar8 *string)
967 {
968 int e;
969 FcChar8 *old;
970 for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
971 if (!FcStrCmpIgnoreBlanksAndCase (old, string))
972 {
973 return FcTrue;
974 break;
975 }
976 return FcFalse;
977 }
978
979 FcPattern *
980 FcFreeTypeQuery (const FcChar8 *file,
981 int id,
982 FcBlanks *blanks,
983 int *count)
984 {
985 FT_Face face;
986 FcPattern *pat;
987 int slant = -1;
988 int weight = -1;
989 int width = -1;
990 int i;
991 FcCharSet *cs;
992 FcLangSet *ls;
993 FT_Library ftLibrary;
994 #if 0
995 FcChar8 *family = 0;
996 #endif
997 FcChar8 *complex;
998 const FcChar8 *foundry = 0;
999 int spacing;
1000 TT_OS2 *os2;
1001 #if HAVE_FT_GET_PS_FONT_INFO
1002 PS_FontInfoRec psfontinfo;
1003 #endif
1004 #if HAVE_FT_GET_BDF_PROPERTY
1005 BDF_PropertyRec prop;
1006 #endif
1007 TT_Header *head;
1008 const FcChar8 *exclusiveLang = 0;
1009 FT_SfntName sname;
1010 FT_UInt snamei, snamec;
1011
1012 int nfamily = 0;
1013 int nfamily_lang = 0;
1014 int nstyle = 0;
1015 int nstyle_lang = 0;
1016 int nfullname = 0;
1017 int nfullname_lang = 0;
1018
1019 FcChar8 *style = 0;
1020 int st;
1021
1022 if (FT_Init_FreeType (&ftLibrary))
1023 return 0;
1024
1025 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1026 goto bail;
1027
1028 *count = face->num_faces;
1029
1030 pat = FcPatternCreate ();
1031 if (!pat)
1032 goto bail0;
1033
1034 if (!FcPatternAddBool (pat, FC_OUTLINE,
1035 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1036 goto bail1;
1037
1038 if (!FcPatternAddBool (pat, FC_SCALABLE,
1039 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1040 goto bail1;
1041
1042
1043 /*
1044 * Get the OS/2 table
1045 */
1046 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1047
1048 /*
1049 * Look first in the OS/2 table for the foundry, if
1050 * not found here, the various notices will be searched for
1051 * that information, either from the sfnt name tables or
1052 * the Postscript FontInfo dictionary. Finally, the
1053 * BDF properties will queried.
1054 */
1055
1056 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1057 foundry = FcVendorFoundry(os2->achVendID);
1058
1059 if (FcDebug () & FC_DBG_SCANV)
1060 printf ("\n");
1061 /*
1062 * Grub through the name table looking for family
1063 * and style names. FreeType makes quite a hash
1064 * of them
1065 */
1066 snamec = FT_Get_Sfnt_Name_Count (face);
1067 for (snamei = 0; snamei < snamec; snamei++)
1068 {
1069 FcChar8 *utf8;
1070 FcChar8 *lang;
1071 char *elt = 0, *eltlang = 0;
1072 int *np = 0, *nlangp = 0;
1073
1074 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1075 continue;
1076
1077 utf8 = FcSfntNameTranscode (&sname);
1078 lang = FcSfntNameLanguage (&sname);
1079
1080 if (!utf8)
1081 continue;
1082
1083 switch (sname.name_id) {
1084 case TT_NAME_ID_FONT_FAMILY:
1085 #if 0
1086 case TT_NAME_ID_PS_NAME:
1087 case TT_NAME_ID_UNIQUE_ID:
1088 #endif
1089 if (FcDebug () & FC_DBG_SCANV)
1090 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1091 sname.name_id, sname.platform_id,
1092 sname.encoding_id, sname.language_id,
1093 utf8);
1094
1095 elt = FC_FAMILY;
1096 eltlang = FC_FAMILYLANG;
1097 np = &nfamily;
1098 nlangp = &nfamily_lang;
1099 break;
1100 case TT_NAME_ID_FULL_NAME:
1101 case TT_NAME_ID_MAC_FULL_NAME:
1102 if (FcDebug () & FC_DBG_SCANV)
1103 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
1104 sname.name_id, sname.platform_id,
1105 sname.encoding_id, sname.language_id,
1106 utf8);
1107
1108 elt = FC_FULLNAME;
1109 eltlang = FC_FULLNAMELANG;
1110 np = &nfullname;
1111 nlangp = &nfullname_lang;
1112 break;
1113 case TT_NAME_ID_FONT_SUBFAMILY:
1114 if (FcDebug () & FC_DBG_SCANV)
1115 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1116 sname.name_id, sname.platform_id,
1117 sname.encoding_id, sname.language_id,
1118 utf8);
1119
1120 elt = FC_STYLE;
1121 eltlang = FC_STYLELANG;
1122 np = &nstyle;
1123 nlangp = &nstyle_lang;
1124 break;
1125 case TT_NAME_ID_TRADEMARK:
1126 case TT_NAME_ID_MANUFACTURER:
1127 /* If the foundry wasn't found in the OS/2 table, look here */
1128 if(!foundry)
1129 foundry = FcNoticeFoundry((FT_String *) utf8);
1130 break;
1131 }
1132 if (elt)
1133 {
1134 if (FcStringInPatternElement (pat, elt, utf8))
1135 {
1136 free (utf8);
1137 continue;
1138 }
1139
1140 /* add new element */
1141 if (!FcPatternAddString (pat, elt, utf8))
1142 {
1143 free (utf8);
1144 goto bail1;
1145 }
1146 free (utf8);
1147 if (lang)
1148 {
1149 /* pad lang list with 'xx' to line up with elt */
1150 while (*nlangp < *np)
1151 {
1152 if (!FcPatternAddString (pat, eltlang, "xx"))
1153 goto bail1;
1154 ++*nlangp;
1155 }
1156 if (!FcPatternAddString (pat, eltlang, lang))
1157 goto bail1;
1158 ++*nlangp;
1159 }
1160 ++*np;
1161 }
1162 else
1163 free (utf8);
1164 }
1165
1166 if (!nfamily && face->family_name)
1167 {
1168 if (FcDebug () & FC_DBG_SCANV)
1169 printf ("using FreeType family %s", face->family_name);
1170 if (!FcPatternAddString (pat, FC_FAMILY, face->family_name))
1171 goto bail1;
1172 ++nfamily;
1173 }
1174
1175 if (!nstyle && face->style_name)
1176 {
1177 if (FcDebug () & FC_DBG_SCANV)
1178 printf ("using FreeType style %s", face->family_name);
1179 if (!FcPatternAddString (pat, FC_STYLE, face->style_name))
1180 goto bail1;
1181 ++nstyle;
1182 }
1183
1184 if (!nfamily)
1185 {
1186 FcChar8 *start, *end;
1187 FcChar8 *family;
1188
1189 start = (FcChar8 *) strrchr ((char *) file, '/');
1190 if (start)
1191 start++;
1192 else
1193 start = (FcChar8 *) file;
1194 end = (FcChar8 *) strrchr ((char *) start, '.');
1195 if (!end)
1196 end = start + strlen ((char *) start);
1197 /* freed below */
1198 family = malloc (end - start + 1);
1199 strncpy ((char *) family, (char *) start, end - start);
1200 family[end - start] = '\0';
1201 if (FcDebug () & FC_DBG_SCANV)
1202 printf ("using filename for family %s", family);
1203 if (!FcPatternAddString (pat, FC_FAMILY, family))
1204 {
1205 free (family);
1206 goto bail1;
1207 }
1208 free (family);
1209 ++nfamily;
1210 }
1211
1212 /*
1213 * Walk through FC_FULLNAME entries eliding those in FC_FAMILY
1214 * or which are simply a FC_FAMILY and FC_STYLE glued together
1215 */
1216 {
1217 int fn, fa, st;
1218 FcChar8 *full;
1219 FcChar8 *fam;
1220 FcChar8 *style;
1221
1222 for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
1223 {
1224 FcBool remove = FcFalse;
1225 /*
1226 * Check each family
1227 */
1228 for (fa = 0; !remove &&
1229 FcPatternGetString (pat, FC_FAMILY,
1230 fa, &fam) == FcResultMatch;
1231 fa++)
1232 {
1233 /*
1234 * for exact match
1235 */
1236 if (!FcStrCmpIgnoreBlanksAndCase (full, fam))
1237 {
1238 remove = FcTrue;
1239 break;
1240 }
1241 /*
1242 * If the family is in the full name, check the
1243 * combination of this family with every style
1244 */
1245 if (!FcStrContainsIgnoreBlanksAndCase (full, fam))
1246 continue;
1247 for (st = 0; !remove &&
1248 FcPatternGetString (pat, FC_STYLE,
1249 st, &style) == FcResultMatch;
1250 st++)
1251 {
1252 FcChar8 *both = FcStrPlus (fam, style);
1253
1254 if (both)
1255 {
1256 if (FcStrCmpIgnoreBlanksAndCase (full, both) == 0)
1257 remove = FcTrue;
1258 free (both);
1259 }
1260 }
1261 }
1262 if (remove)
1263 {
1264 FcPatternRemove (pat, FC_FULLNAME, fn);
1265 FcPatternRemove (pat, FC_FULLNAMELANG, fn);
1266 fn--;
1267 nfullname--;
1268 nfullname_lang--;
1269 }
1270 }
1271 if (FcDebug () & FC_DBG_SCANV)
1272 for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
1273 printf ("Saving unique fullname %s\n", full);
1274 }
1275
1276 if (!FcPatternAddString (pat, FC_FILE, file))
1277 goto bail1;
1278
1279 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1280 goto bail1;
1281
1282 if (!FcPatternAddString (pat, FC_SOURCE, (FcChar8 *) "FreeType"))
1283 goto bail1;
1284
1285 #if 0
1286 /*
1287 * don't even try this -- CJK 'monospace' fonts are really
1288 * dual width, and most other fonts don't bother to set
1289 * the attribute. Sigh.
1290 */
1291 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1292 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1293 goto bail1;
1294 #endif
1295
1296 /*
1297 * Find the font revision (if available)
1298 */
1299 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1300 if (head)
1301 {
1302 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1303 goto bail1;
1304 }
1305 else
1306 {
1307 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1308 goto bail1;
1309 }
1310
1311 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1312 {
1313 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1314 {
1315 FT_ULong bits;
1316 int bit;
1317 if (FcCodePageRange[i].bit < 32)
1318 {
1319 bits = os2->ulCodePageRange1;
1320 bit = FcCodePageRange[i].bit;
1321 }
1322 else
1323 {
1324 bits = os2->ulCodePageRange2;
1325 bit = FcCodePageRange[i].bit - 32;
1326 }
1327 if (bits & (1 << bit))
1328 {
1329 /*
1330 * If the font advertises support for multiple
1331 * "exclusive" languages, then include support
1332 * for any language found to have coverage
1333 */
1334 if (exclusiveLang)
1335 {
1336 exclusiveLang = 0;
1337 break;
1338 }
1339 exclusiveLang = FcCodePageRange[i].lang;
1340 }
1341 }
1342 }
1343
1344 if (os2 && os2->version != 0xffff)
1345 {
1346 if (os2->usWeightClass == 0)
1347 ;
1348 else if (os2->usWeightClass < 150)
1349 weight = FC_WEIGHT_THIN;
1350 else if (os2->usWeightClass < 250)
1351 weight = FC_WEIGHT_EXTRALIGHT;
1352 else if (os2->usWeightClass < 350)
1353 weight = FC_WEIGHT_LIGHT;
1354 else if (os2->usWeightClass < 450)
1355 weight = FC_WEIGHT_REGULAR;
1356 else if (os2->usWeightClass < 550)
1357 weight = FC_WEIGHT_MEDIUM;
1358 else if (os2->usWeightClass < 650)
1359 weight = FC_WEIGHT_SEMIBOLD;
1360 else if (os2->usWeightClass < 750)
1361 weight = FC_WEIGHT_BOLD;
1362 else if (os2->usWeightClass < 850)
1363 weight = FC_WEIGHT_EXTRABOLD;
1364 else if (os2->usWeightClass < 950)
1365 weight = FC_WEIGHT_BLACK;
1366
1367 switch (os2->usWidthClass) {
1368 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1369 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1370 case 3: width = FC_WIDTH_CONDENSED; break;
1371 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1372 case 5: width = FC_WIDTH_NORMAL; break;
1373 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1374 case 7: width = FC_WIDTH_EXPANDED; break;
1375 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1376 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1377 }
1378 }
1379 if (os2 && (complex = FcFontCapabilities(face)))
1380 {
1381 if (!FcPatternAddString (pat, FC_CAPABILITY, complex))
1382 {
1383 free (complex);
1384 goto bail1;
1385 }
1386 free (complex);
1387 }
1388
1389 /*
1390 * Type 1: Check for FontInfo dictionary information
1391 * Code from g2@magestudios.net (Gerard Escalante)
1392 */
1393
1394 #if HAVE_FT_GET_PS_FONT_INFO
1395 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1396 {
1397 if (weight == -1 && psfontinfo.weight)
1398 {
1399 weight = FcIsWeight (psfontinfo.weight);
1400 if (FcDebug() & FC_DBG_SCANV)
1401 printf ("\tType1 weight %s maps to %d\n",
1402 psfontinfo.weight, weight);
1403 }
1404
1405 #if 0
1406 /*
1407 * Don't bother with italic_angle; FreeType already extracts that
1408 * information for us and sticks it into style_flags
1409 */
1410 if (psfontinfo.italic_angle)
1411 slant = FC_SLANT_ITALIC;
1412 else
1413 slant = FC_SLANT_ROMAN;
1414 #endif
1415
1416 if(!foundry)
1417 foundry = FcNoticeFoundry(psfontinfo.notice);
1418 }
1419 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1420
1421 #if HAVE_FT_GET_BDF_PROPERTY
1422 /*
1423 * Finally, look for a FOUNDRY BDF property if no other
1424 * mechanism has managed to locate a foundry
1425 */
1426
1427 if (!foundry)
1428 {
1429 int rc;
1430 BDF_PropertyRec prop;
1431 rc = MY_Get_BDF_Property(face, "FOUNDRY", &prop);
1432 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1433 foundry = prop.u.atom;
1434 }
1435
1436 if (width == -1)
1437 {
1438 if (MY_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1439 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1440 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1441 {
1442 FT_Int32 value;
1443
1444 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1445 value = prop.u.integer;
1446 else
1447 value = (FT_Int32) prop.u.cardinal;
1448 switch ((value + 5) / 10) {
1449 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1450 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1451 case 3: width = FC_WIDTH_CONDENSED; break;
1452 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1453 case 5: width = FC_WIDTH_NORMAL; break;
1454 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1455 case 7: width = FC_WIDTH_EXPANDED; break;
1456 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1457 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1458 }
1459 }
1460 if (width == -1 &&
1461 MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1462 prop.type == BDF_PROPERTY_TYPE_ATOM)
1463 {
1464 width = FcIsWidth (prop.u.atom);
1465 if (FcDebug () & FC_DBG_SCANV)
1466 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1467 }
1468 }
1469 #endif
1470
1471 /*
1472 * Look for weight, width and slant names in the style value
1473 */
1474 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1475 {
1476 if (weight == -1)
1477 {
1478 weight = FcContainsWeight (style);
1479 if (FcDebug() & FC_DBG_SCANV)
1480 printf ("\tStyle %s maps to weight %d\n", style, weight);
1481 }
1482 if (width == -1)
1483 {
1484 width = FcContainsWidth (style);
1485 if (FcDebug() & FC_DBG_SCANV)
1486 printf ("\tStyle %s maps to width %d\n", style, width);
1487 }
1488 if (slant == -1)
1489 {
1490 slant = FcContainsSlant (style);
1491 if (FcDebug() & FC_DBG_SCANV)
1492 printf ("\tStyle %s maps to slant %d\n", style, slant);
1493 }
1494 }
1495 /*
1496 * Pull default values from the FreeType flags if more
1497 * specific values not found above
1498 */
1499 if (slant == -1)
1500 {
1501 slant = FC_SLANT_ROMAN;
1502 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1503 slant = FC_SLANT_ITALIC;
1504 }
1505
1506 if (weight == -1)
1507 {
1508 weight = FC_WEIGHT_MEDIUM;
1509 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1510 weight = FC_WEIGHT_BOLD;
1511 }
1512
1513 if (width == -1)
1514 width = FC_WIDTH_NORMAL;
1515
1516 if (foundry == 0)
1517 foundry = "unknown";
1518
1519 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1520 goto bail1;
1521
1522 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1523 goto bail1;
1524
1525 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1526 goto bail1;
1527
1528 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1529 goto bail1;
1530
1531 /*
1532 * Compute the unicode coverage for the font
1533 */
1534 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1535 if (!cs)
1536 goto bail1;
1537
1538 #if HAVE_FT_GET_BDF_PROPERTY
1539 /* For PCF fonts, override the computed spacing with the one from
1540 the property */
1541 if(MY_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1542 prop.type == BDF_PROPERTY_TYPE_ATOM) {
1543 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1544 spacing = FC_CHARCELL;
1545 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1546 spacing = FC_MONO;
1547 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1548 spacing = FC_PROPORTIONAL;
1549 }
1550 #endif
1551
1552 /*
1553 * Skip over PCF fonts that have no encoded characters; they're
1554 * usually just Unicode fonts transcoded to some legacy encoding
1555 */
1556 if (FcCharSetCount (cs) == 0)
1557 {
1558 if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
1559 goto bail2;
1560 }
1561
1562 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1563 goto bail2;
1564
1565 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1566 if (!ls)
1567 goto bail2;
1568
1569 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1570 {
1571 FcLangSetDestroy (ls);
1572 goto bail2;
1573 }
1574
1575 FcLangSetDestroy (ls);
1576
1577 if (spacing != FC_PROPORTIONAL)
1578 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1579 goto bail2;
1580
1581 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1582 {
1583 for (i = 0; i < face->num_fixed_sizes; i++)
1584 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1585 FcGetPixelSize (face, i)))
1586 goto bail1;
1587 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1588 goto bail1;
1589 #if HAVE_FT_GET_BDF_PROPERTY
1590 if(face->num_fixed_sizes == 1) {
1591 int rc;
1592 int value;
1593 BDF_PropertyRec prop;
1594
1595 rc = MY_Get_BDF_Property(face, "POINT_SIZE", &prop);
1596 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1597 value = prop.u.integer;
1598 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1599 value = prop.u.cardinal;
1600 else
1601 goto nevermind;
1602 if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1603 goto nevermind;
1604
1605 rc = MY_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
1606 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1607 value = prop.u.integer;
1608 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1609 value = prop.u.cardinal;
1610 else
1611 goto nevermind;
1612 if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1613 goto nevermind;
1614
1615 }
1616 nevermind:
1617 ;
1618 #endif
1619 }
1620 #if HAVE_FT_GET_X11_FONT_FORMAT
1621 /*
1622 * Use the (not well documented or supported) X-specific function
1623 * from FreeType to figure out the font format
1624 */
1625 {
1626 const char *font_format = FT_Get_X11_Font_Format (face);
1627 if (font_format)
1628 FcPatternAddString (pat, FC_FONTFORMAT, font_format);
1629 }
1630 #endif
1631
1632 /*
1633 * Drop our reference to the charset
1634 */
1635 FcCharSetDestroy (cs);
1636
1637 /*
1638 * Deallocate family/style values
1639 */
1640
1641 FT_Done_Face (face);
1642 FT_Done_FreeType (ftLibrary);
1643 return pat;
1644
1645 bail2:
1646 FcCharSetDestroy (cs);
1647 bail1:
1648 FcPatternDestroy (pat);
1649 bail0:
1650 FT_Done_Face (face);
1651 bail:
1652 FT_Done_FreeType (ftLibrary);
1653 return 0;
1654 }
1655
1656
1657 /*
1658 * For our purposes, this approximation is sufficient
1659 */
1660 #if !HAVE_FT_GET_NEXT_CHAR
1661 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1662 (*(gi) = 0), 0 : \
1663 (*(gi) = 1), (ucs4) + 1)
1664 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1665 #endif
1666
1667 typedef struct _FcCharEnt {
1668 FcChar16 bmp;
1669 unsigned char encode;
1670 } FcCharEnt;
1671
1672 struct _FcCharMap {
1673 const FcCharEnt *ent;
1674 int nent;
1675 };
1676
1677 typedef struct _FcFontDecode {
1678 FT_Encoding encoding;
1679 const FcCharMap *map;
1680 FcChar32 max;
1681 } FcFontDecode;
1682
1683 static const FcCharEnt AppleRomanEnt[] = {
1684 { 0x0020, 0x20 }, /* SPACE */
1685 { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1686 { 0x0022, 0x22 }, /* QUOTATION MARK */
1687 { 0x0023, 0x23 }, /* NUMBER SIGN */
1688 { 0x0024, 0x24 }, /* DOLLAR SIGN */
1689 { 0x0025, 0x25 }, /* PERCENT SIGN */
1690 { 0x0026, 0x26 }, /* AMPERSAND */
1691 { 0x0027, 0x27 }, /* APOSTROPHE */
1692 { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1693 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1694 { 0x002A, 0x2A }, /* ASTERISK */
1695 { 0x002B, 0x2B }, /* PLUS SIGN */
1696 { 0x002C, 0x2C }, /* COMMA */
1697 { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1698 { 0x002E, 0x2E }, /* FULL STOP */
1699 { 0x002F, 0x2F }, /* SOLIDUS */
1700 { 0x0030, 0x30 }, /* DIGIT ZERO */
1701 { 0x0031, 0x31 }, /* DIGIT ONE */
1702 { 0x0032, 0x32 }, /* DIGIT TWO */
1703 { 0x0033, 0x33 }, /* DIGIT THREE */
1704 { 0x0034, 0x34 }, /* DIGIT FOUR */
1705 { 0x0035, 0x35 }, /* DIGIT FIVE */
1706 { 0x0036, 0x36 }, /* DIGIT SIX */
1707 { 0x0037, 0x37 }, /* DIGIT SEVEN */
1708 { 0x0038, 0x38 }, /* DIGIT EIGHT */
1709 { 0x0039, 0x39 }, /* DIGIT NINE */
1710 { 0x003A, 0x3A }, /* COLON */
1711 { 0x003B, 0x3B }, /* SEMICOLON */
1712 { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1713 { 0x003D, 0x3D }, /* EQUALS SIGN */
1714 { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1715 { 0x003F, 0x3F }, /* QUESTION MARK */
1716 { 0x0040, 0x40 }, /* COMMERCIAL AT */
1717 { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1718 { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1719 { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1720 { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1721 { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1722 { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1723 { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1724 { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1725 { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1726 { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1727 { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1728 { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1729 { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1730 { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1731 { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1732 { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1733 { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1734 { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1735 { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1736 { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1737 { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1738 { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1739 { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1740 { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1741 { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1742 { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1743 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1744 { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1745 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1746 { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1747 { 0x005F, 0x5F }, /* LOW LINE */
1748 { 0x0060, 0x60 }, /* GRAVE ACCENT */
1749 { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1750 { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1751 { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1752 { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1753 { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1754 { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1755 { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1756 { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1757 { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1758 { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1759 { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1760 { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1761 { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1762 { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1763 { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1764 { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1765 { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1766 { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1767 { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1768 { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1769 { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1770 { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1771 { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1772 { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1773 { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1774 { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1775 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1776 { 0x007C, 0x7C }, /* VERTICAL LINE */
1777 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1778 { 0x007E, 0x7E }, /* TILDE */
1779 { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1780 { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1781 { 0x00A2, 0xA2 }, /* CENT SIGN */
1782 { 0x00A3, 0xA3 }, /* POUND SIGN */
1783 { 0x00A5, 0xB4 }, /* YEN SIGN */
1784 { 0x00A7, 0xA4 }, /* SECTION SIGN */
1785 { 0x00A8, 0xAC }, /* DIAERESIS */
1786 { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1787 { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1788 { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1789 { 0x00AC, 0xC2 }, /* NOT SIGN */
1790 { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1791 { 0x00AF, 0xF8 }, /* MACRON */
1792 { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1793 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1794 { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1795 { 0x00B5, 0xB5 }, /* MICRO SIGN */
1796 { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1797 { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1798 { 0x00B8, 0xFC }, /* CEDILLA */
1799 { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1800 { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1801 { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1802 { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1803 { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1804 { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1805 { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1806 { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1807 { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1808 { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1809 { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1810 { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1811 { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1812 { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1813 { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1814 { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1815 { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1816 { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1817 { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1818 { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1819 { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1820 { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1821 { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1822 { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1823 { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1824 { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1825 { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1826 { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1827 { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1828 { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1829 { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1830 { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1831 { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1832 { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1833 { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1834 { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1835 { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1836 { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1837 { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1838 { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1839 { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1840 { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1841 { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1842 { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1843 { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1844 { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1845 { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1846 { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1847 { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1848 { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1849 { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1850 { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1851 { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1852 { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1853 { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1854 { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1855 { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1856 { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1857 { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1858 { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1859 { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1860 { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1861 { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1862 { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1863 { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1864 { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1865 { 0x02C7, 0xFF }, /* CARON */
1866 { 0x02D8, 0xF9 }, /* BREVE */
1867 { 0x02D9, 0xFA }, /* DOT ABOVE */
1868 { 0x02DA, 0xFB }, /* RING ABOVE */
1869 { 0x02DB, 0xFE }, /* OGONEK */
1870 { 0x02DC, 0xF7 }, /* SMALL TILDE */
1871 { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1872 { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1873 { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1874 { 0x2013, 0xD0 }, /* EN DASH */
1875 { 0x2014, 0xD1 }, /* EM DASH */
1876 { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1877 { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1878 { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1879 { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1880 { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1881 { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1882 { 0x2020, 0xA0 }, /* DAGGER */
1883 { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
1884 { 0x2022, 0xA5 }, /* BULLET */
1885 { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
1886 { 0x2030, 0xE4 }, /* PER MILLE SIGN */
1887 { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
1888 { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
1889 { 0x2044, 0xDA }, /* FRACTION SLASH */
1890 { 0x20AC, 0xDB }, /* EURO SIGN */
1891 { 0x2122, 0xAA }, /* TRADE MARK SIGN */
1892 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
1893 { 0x2206, 0xC6 }, /* INCREMENT */
1894 { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
1895 { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
1896 { 0x221A, 0xC3 }, /* SQUARE ROOT */
1897 { 0x221E, 0xB0 }, /* INFINITY */
1898 { 0x222B, 0xBA }, /* INTEGRAL */
1899 { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
1900 { 0x2260, 0xAD }, /* NOT EQUAL TO */
1901 { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
1902 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
1903 { 0x25CA, 0xD7 }, /* LOZENGE */
1904 { 0xF8FF, 0xF0 }, /* Apple logo */
1905 { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
1906 { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
1907 };
1908
1909 static const FcCharMap AppleRoman = {
1910 AppleRomanEnt,
1911 sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
1912 };
1913
1914 static const FcCharEnt AdobeSymbolEnt[] = {
1915 { 0x0020, 0x20 }, /* SPACE # space */
1916 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
1917 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
1918 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
1919 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
1920 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
1921 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
1922 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
1923 { 0x002C, 0x2C }, /* COMMA # comma */
1924 { 0x002E, 0x2E }, /* FULL STOP # period */
1925 { 0x002F, 0x2F }, /* SOLIDUS # slash */
1926 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
1927 { 0x0031, 0x31 }, /* DIGIT ONE # one */
1928 { 0x0032, 0x32 }, /* DIGIT TWO # two */
1929 { 0x0033, 0x33 }, /* DIGIT THREE # three */
1930 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
1931 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
1932 { 0x0036, 0x36 }, /* DIGIT SIX # six */
1933 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
1934 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
1935 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
1936 { 0x003A, 0x3A }, /* COLON # colon */
1937 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
1938 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1939 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
1940 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
1941 { 0x003F, 0x3F }, /* QUESTION MARK # question */
1942 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
1943 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
1944 { 0x005F, 0x5F }, /* LOW LINE # underscore */
1945 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
1946 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
1947 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
1948 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1949 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
1950 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
1951 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
1952 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
1953 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
1954 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
1955 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1956 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
1957 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
1958 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
1959 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
1960 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
1961 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
1962 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
1963 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
1964 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
1965 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
1966 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
1967 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
1968 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
1969 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
1970 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
1971 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
1972 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
1973 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
1974 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
1975 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
1976 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
1977 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
1978 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
1979 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
1980 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
1981 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
1982 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
1983 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
1984 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
1985 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
1986 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1987 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
1988 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
1989 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
1990 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
1991 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
1992 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
1993 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
1994 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
1995 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
1996 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1997 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1998 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
1999 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
2000 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
2001 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
2002 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
2003 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
2004 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
2005 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
2006 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
2007 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
2008 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
2009 { 0x2022, 0xB7 }, /* BULLET # bullet */
2010 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
2011 { 0x2032, 0xA2 }, /* PRIME # minute */
2012 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
2013 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
2014 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
2015 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
2016 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
2017 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
2018 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
2019 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
2020 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
2021 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
2022 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
2023 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
2024 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
2025 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
2026 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
2027 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
2028 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
2029 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
2030 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
2031 { 0x2200, 0x22 }, /* FOR ALL # universal */
2032 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
2033 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
2034 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
2035 { 0x2206, 0x44 }, /* INCREMENT # Delta */
2036 { 0x2207, 0xD1 }, /* NABLA # gradient */
2037 { 0x2208, 0xCE }, /* ELEMENT OF # element */
2038 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
2039 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
2040 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
2041 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
2042 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
2043 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
2044 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
2045 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
2046 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
2047 { 0x221E, 0xA5 }, /* INFINITY # infinity */
2048 { 0x2220, 0xD0 }, /* ANGLE # angle */
2049 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
2050 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
2051 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
2052 { 0x222A, 0xC8 }, /* UNION # union */
2053 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
2054 { 0x2234, 0x5C }, /* THEREFORE # therefore */
2055 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
2056 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
2057 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
2058 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
2059 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
2060 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
2061 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
2062 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
2063 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
2064 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
2065 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
2066 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
2067 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
2068 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
2069 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
2070 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
2071 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
2072 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
2073 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
2074 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
2075 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
2076 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
2077 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
2078 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
2079 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
2080 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
2081 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
2082 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
2083 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
2084 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
2085 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
2086 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
2087 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
2088 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
2089 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2090 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
2091 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
2092 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
2093 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
2094 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
2095 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2096 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2097 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
2098 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2099 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
2100 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
2101 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
2102 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
2103 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
2104 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
2105 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
2106 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
2107 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
2108 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
2109 };
2110
2111 static const FcCharMap AdobeSymbol = {
2112 AdobeSymbolEnt,
2113 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2114 };
2115
2116 static const FcFontDecode fcFontDecoders[] = {
2117 { ft_encoding_unicode, 0, (1 << 21) - 1 },
2118 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
2119 { ft_encoding_apple_roman, &AppleRoman, (1 << 16) - 1 },
2120 };
2121
2122 #define NUM_DECODE (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
2123
2124 FcChar32
2125 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2126 {
2127 int low, high, mid;
2128 FcChar16 bmp;
2129
2130 low = 0;
2131 high = map->nent - 1;
2132 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2133 return ~0;
2134 while (low <= high)
2135 {
2136 mid = (high + low) >> 1;
2137 bmp = map->ent[mid].bmp;
2138 if (ucs4 == bmp)
2139 return (FT_ULong) map->ent[mid].encode;
2140 if (ucs4 < bmp)
2141 high = mid - 1;
2142 else
2143 low = mid + 1;
2144 }
2145 return ~0;
2146 }
2147
2148 FcChar32
2149 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2150 {
2151 int i;
2152
2153 for (i = 0; i < map->nent; i++)
2154 if (map->ent[i].encode == private)
2155 return (FcChar32) map->ent[i].bmp;
2156 return ~0;
2157 }
2158
2159 const FcCharMap *
2160 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2161 {
2162 int i;
2163
2164 for (i = 0; i < NUM_DECODE; i++)
2165 if (fcFontDecoders[i].encoding == encoding)
2166 return fcFontDecoders[i].map;
2167 return 0;
2168 }
2169
2170 #include "../fc-glyphname/fcglyphname.h"
2171
2172 static FcChar32
2173 FcHashGlyphName (const FcChar8 *name)
2174 {
2175 FcChar32 h = 0;
2176 FcChar8 c;
2177
2178 while ((c = *name++))
2179 {
2180 h = ((h << 1) | (h >> 31)) ^ c;
2181 }
2182 return h;
2183 }
2184
2185 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2186 /*
2187 * Use Type1 glyph names for fonts which have reliable names
2188 * and which export an Adobe Custom mapping
2189 */
2190 static FcBool
2191 FcFreeTypeUseNames (FT_Face face)
2192 {
2193 FT_Int map;
2194
2195 if (!FT_Has_PS_Glyph_Names (face))
2196 return FcFalse;
2197 for (map = 0; map < face->num_charmaps; map++)
2198 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2199 return FcTrue;
2200 return FcFalse;
2201 }
2202
2203 static FcChar8 *
2204 FcUcs4ToGlyphName (FcChar32 ucs4)
2205 {
2206 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2207 int r = 0;
2208 FcGlyphName *gn;
2209
2210 while ((gn = ucs_to_name[i]))
2211 {
2212 if (gn->ucs == ucs4)
2213 return gn->name;
2214 if (!r)
2215 {
2216 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2217 if (!r)
2218 r = 1;
2219 }
2220 i += r;
2221 if (i >= FC_GLYPHNAME_HASH)
2222 i -= FC_GLYPHNAME_HASH;
2223 }
2224 return 0;
2225 }
2226
2227 static FcChar32
2228 FcGlyphNameToUcs4 (FcChar8 *name)
2229 {
2230 FcChar32 h = FcHashGlyphName (name);
2231 int i = (int) (h % FC_GLYPHNAME_HASH);
2232 int r = 0;
2233 FcGlyphName *gn;
2234
2235 while ((gn = name_to_ucs[i]))
2236 {
2237 if (!strcmp ((char *) name, (char *) gn->name))
2238 return gn->ucs;
2239 if (!r)
2240 {
2241 r = (int) (h % FC_GLYPHNAME_REHASH);
2242 if (!r)
2243 r = 1;
2244 }
2245 i += r;
2246 if (i >= FC_GLYPHNAME_HASH)
2247 i -= FC_GLYPHNAME_HASH;
2248 }
2249 return 0xffff;
2250 }
2251
2252 /*
2253 * Search through a font for a glyph by name. This is
2254 * currently a linear search as there doesn't appear to be
2255 * any defined order within the font
2256 */
2257 static FT_UInt
2258 FcFreeTypeGlyphNameIndex (FT_Face face, FcChar8 *name)
2259 {
2260 FT_UInt gindex;
2261 FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2262
2263 for (gindex = 0; gindex < face->num_glyphs; gindex++)
2264 {
2265 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2266 if (!strcmp ((char *) name, (char *) name_buf))
2267 return gindex;
2268 }
2269 return 0;
2270 }
2271 #endif
2272
2273 /*
2274 * Map a UCS4 glyph to a glyph index. Use all available encoding
2275 * tables to try and find one that works. This information is expected
2276 * to be cached by higher levels, so performance isn't critical
2277 */
2278
2279 FT_UInt
2280 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2281 {
2282 int initial, offset, decode;
2283 FT_UInt glyphindex;
2284 FcChar32 charcode;
2285
2286 initial = 0;
2287 /*
2288 * Find the current encoding
2289 */
2290 if (face->charmap)
2291 {
2292 for (; initial < NUM_DECODE; initial++)
2293 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2294 break;
2295 if (initial == NUM_DECODE)
2296 initial = 0;
2297 }
2298 /*
2299 * Check each encoding for the glyph, starting with the current one
2300 */
2301 for (offset = 0; offset < NUM_DECODE; offset++)
2302 {
2303 decode = (initial + offset) % NUM_DECODE;
2304 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2305 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2306 continue;
2307 if (fcFontDecoders[decode].map)
2308 {
2309 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2310 if (charcode == ~0)
2311 continue;
2312 }
2313 else
2314 charcode = ucs4;
2315 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2316 if (glyphindex)
2317 return glyphindex;
2318 }
2319 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2320 /*
2321 * Check postscript name table if present
2322 */
2323 if (FcFreeTypeUseNames (face))
2324 {
2325 FcChar8 *name = FcUcs4ToGlyphName (ucs4);
2326 if (name)
2327 {
2328 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2329 if (glyphindex)
2330 return glyphindex;
2331 }
2332 }
2333 #endif
2334 return 0;
2335 }
2336
2337 static FcBool
2338 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2339 FT_UInt glyph, FcBlanks *blanks,
2340 FT_Pos *advance)
2341 {
2342 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2343 FT_GlyphSlot slot;
2344
2345 /*
2346 * For bitmap-only fonts, assume that they're OK.
2347 */
2348 if ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
2349 return FcTrue;
2350
2351 /*
2352 * When using scalable fonts, only report those glyphs
2353 * which can be scaled; otherwise those fonts will
2354 * only be available at some sizes, and never when
2355 * transformed. Avoid this by simply reporting bitmap-only
2356 * glyphs as missing
2357 */
2358 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2359 load_flags |= FT_LOAD_NO_BITMAP;
2360
2361 if (FT_Load_Glyph (face, glyph, load_flags))
2362 return FcFalse;
2363
2364 slot = face->glyph;
2365 if (!glyph)
2366 return FcFalse;
2367
2368 *advance = slot->metrics.horiAdvance;
2369
2370 switch (slot->format) {
2371 case ft_glyph_format_bitmap:
2372 /*
2373 * Bitmaps are assumed to be reasonable; if
2374 * this proves to be a rash assumption, this
2375 * code can be easily modified
2376 */
2377 return FcTrue;
2378 case ft_glyph_format_outline:
2379 /*
2380 * Glyphs with contours are always OK
2381 */
2382 if (slot->outline.n_contours != 0)
2383 return FcTrue;
2384 /*
2385 * Glyphs with no contours are only OK if
2386 * they're members of the Blanks set specified
2387 * in the configuration. If blanks isn't set,
2388 * then allow any glyph to be blank
2389 */
2390 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2391 return FcTrue;
2392 /* fall through ... */
2393 default:
2394 break;
2395 }
2396 return FcFalse;
2397 }
2398
2399 #define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
2400 #define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
2401 #define FC_ABS(a) ((a) < 0 ? -(a) : (a))
2402 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2403
2404 FcCharSet *
2405 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2406 {
2407 FcChar32 page, off, max, ucs4;
2408 #ifdef CHECK
2409 FcChar32 font_max = 0;
2410 #endif
2411 FcCharSet *fcs;
2412 FcCharLeaf *leaf;
2413 const FcCharMap *map;
2414 int o;
2415 int i;
2416 FT_UInt glyph;
2417 FT_Pos advance, advance_one = 0, advance_two = 0;
2418 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2419
2420 fcs = FcCharSetCreate ();
2421 if (!fcs)
2422 goto bail0;
2423
2424 #ifdef CHECK
2425 printf ("Family %s style %s\n", face->family_name, face->style_name);
2426 #endif
2427 for (o = 0; o < NUM_DECODE; o++)
2428 {
2429 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2430 continue;
2431 map = fcFontDecoders[o].map;
2432 if (map)
2433 {
2434 /*
2435 * Non-Unicode tables are easy; there's a list of all possible
2436 * characters
2437 */
2438 for (i = 0; i < map->nent; i++)
2439 {
2440 ucs4 = map->ent[i].bmp;
2441 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2442 if (glyph &&
2443 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2444 {
2445 if (!has_advance)
2446 {
2447 has_advance = FcTrue;
2448 advance_one = advance;
2449 }
2450 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2451 {
2452 if (fixed_advance)
2453 {
2454 dual_advance = FcTrue;
2455 fixed_advance = FcFalse;
2456 advance_two = advance;
2457 }
2458 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2459 dual_advance = FcFalse;
2460 }
2461
2462 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2463 if (!leaf)
2464 goto bail1;
2465 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2466 #ifdef CHECK
2467 if (ucs4 > font_max)
2468 font_max = ucs4;
2469 #endif
2470 }
2471 }
2472 }
2473 else
2474 {
2475 FT_UInt gindex;
2476
2477 max = fcFontDecoders[o].max;
2478 /*
2479 * Find the first encoded character in the font
2480 */
2481 if (FT_Get_Char_Index (face, 0))
2482 {
2483 ucs4 = 0;
2484 gindex = 1;
2485 }
2486 else
2487 {
2488 ucs4 = FT_Get_Next_Char (face, 0, &gindex);
2489 if (!ucs4)
2490 gindex = 0;
2491 }
2492
2493 while (gindex)
2494 {
2495 page = ucs4 >> 8;
2496 leaf = 0;
2497 while ((ucs4 >> 8) == page)
2498 {
2499 glyph = FT_Get_Char_Index (face, ucs4);
2500 if (glyph && FcFreeTypeCheckGlyph (face, ucs4,
2501 glyph, blanks, &advance))
2502 {
2503 if (!has_advance)
2504 {
2505 has_advance = FcTrue;
2506 advance_one = advance;
2507 }
2508 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2509 {
2510 if (fixed_advance)
2511 {
2512 dual_advance = FcTrue;
2513 fixed_advance = FcFalse;
2514 advance_two = advance;
2515 }
2516 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2517 dual_advance = FcFalse;
2518 }
2519
2520 if (!leaf)
2521 {
2522 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2523 if (!leaf)
2524 goto bail1;
2525 }
2526 off = ucs4 & 0xff;
2527 leaf->map[off >> 5] |= (1 << (off & 0x1f));
2528 #ifdef CHECK
2529 if (ucs4 > font_max)
2530 font_max = ucs4;
2531 #endif
2532 }
2533 ucs4++;
2534 }
2535 ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
2536 if (!ucs4)
2537 gindex = 0;
2538 }
2539 #ifdef CHECK
2540 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2541 {
2542 FcBool FT_Has, FC_Has;
2543
2544 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2545 FC_Has = FcCharSetHasChar (fcs, ucs4);
2546 if (FT_Has != FC_Has)
2547 {
2548 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2549 }
2550 }
2551 #endif
2552 }
2553 }
2554 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2555 /*
2556 * Add mapping from PS glyph names if available
2557 */
2558 if (FcFreeTypeUseNames (face))
2559 {
2560 FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2561
2562 for (glyph = 0; glyph < face->num_glyphs; glyph++)
2563 {
2564 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2565 {
2566 ucs4 = FcGlyphNameToUcs4 (name_buf);
2567 if (ucs4 != 0xffff &&
2568 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2569 {
2570 if (!has_advance)
2571 {
2572 has_advance = FcTrue;
2573 advance_one = advance;
2574 }
2575 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2576 {
2577 if (fixed_advance)
2578 {
2579 dual_advance = FcTrue;
2580 fixed_advance = FcFalse;
2581 advance_two = advance;
2582 }
2583 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2584 dual_advance = FcFalse;
2585 }
2586 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2587 if (!leaf)
2588 goto bail1;
2589 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2590 #ifdef CHECK
2591 if (ucs4 > font_max)
2592 font_max = ucs4;
2593 #endif
2594 }
2595 }
2596 }
2597 }
2598 #endif
2599 #ifdef CHECK
2600 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2601 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2602 {
2603 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2604 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2605
2606 if (has_char && !has_bit)
2607 {
2608 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2609 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2610 else
2611 printf ("Bitmap missing char 0x%x\n", ucs4);
2612 }
2613 else if (!has_char && has_bit)
2614 printf ("Bitmap extra char 0x%x\n", ucs4);
2615 }
2616 #endif
2617 if (fixed_advance)
2618 *spacing = FC_MONO;
2619 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2620 *spacing = FC_DUAL;
2621 else
2622 *spacing = FC_PROPORTIONAL;
2623 return fcs;
2624 bail1:
2625 FcCharSetDestroy (fcs);
2626 bail0:
2627 return 0;
2628 }
2629
2630 FcCharSet *
2631 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2632 {
2633 int spacing;
2634
2635 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2636 }
2637
2638
2639 #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2640 #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2641 #define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2642 #define TT_Err_Ok FT_Err_Ok
2643 #define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
2644 #define TTO_Err_Empty_Script 0x1005
2645 #define TTO_Err_Invalid_SubTable 0x1001
2646
2647
2648 static void
2649 addtag(FcChar8 *complex, FT_ULong tag)
2650 {
2651 FcChar8 tagstring[15];
2652 sprintf (tagstring, "otlayout:%c%c%c%c ",
2653 (unsigned char)(tag >> 24),
2654 (unsigned char)((tag & 0xff0000) >> 16),
2655 (unsigned char)((tag & 0xff00) >> 8),
2656 (unsigned char)(tag & 0xff));
2657 strncat(complex, tagstring, 14);
2658 }
2659
2660 static int
2661 compareulong (const void *a, const void *b)
2662 {
2663 const FT_ULong *ua = (const FT_ULong *) a;
2664 const FT_ULong *ub = (const FT_ULong *) b;
2665 return *ua - *ub;
2666 }
2667
2668
2669 static FT_Error
2670 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
2671 {
2672 FT_ULong cur_offset, new_offset, base_offset;
2673 TT_Face tt_face = (TT_Face)face;
2674 FT_Stream stream = face->stream;
2675 FT_Error error;
2676 FT_UShort n, p;
2677 FT_Memory memory = stream->memory;
2678
2679 if ( !stream )
2680 return TT_Err_Invalid_Face_Handle;
2681
2682 if (( error = tt_face->goto_table( tt_face, tabletag, stream, 0 ) ))
2683 return error;
2684
2685 base_offset = FT_STREAM_POS();
2686
2687 /* skip version */
2688
2689 if ( FT_STREAM_SEEK( base_offset + 4L ) || FT_FRAME_ENTER( 2L ) )
2690 return error;
2691
2692 new_offset = FT_GET_USHORT() + base_offset;
2693
2694 FT_FRAME_EXIT();
2695
2696 cur_offset = FT_STREAM_POS();
2697
2698 if ( FT_STREAM_SEEK( new_offset ) != TT_Err_Ok )
2699 return error;
2700
2701 base_offset = FT_STREAM_POS();
2702
2703 if ( FT_FRAME_ENTER( 2L ) )
2704 return error;
2705
2706 *script_count = FT_GET_USHORT();
2707
2708 FT_FRAME_EXIT();
2709
2710 if ( FT_SET_ERROR (FT_MEM_ALLOC_ARRAY( *stags, *script_count, FT_ULong )) )
2711 return error;
2712
2713 p = 0;
2714 for ( n = 0; n < *script_count; n++ )
2715 {
2716 if ( FT_FRAME_ENTER( 6L ) )
2717 goto Fail;
2718
2719 (*stags)[p] = FT_GET_ULONG();
2720 new_offset = FT_GET_USHORT() + base_offset;
2721
2722 FT_FRAME_EXIT();
2723
2724 cur_offset = FT_STREAM_POS();
2725
2726 if ( FT_STREAM_SEEK( new_offset ) )
2727 goto Fail;
2728
2729 if ( error == TT_Err_Ok )
2730 p++;
2731 else if ( error != TTO_Err_Empty_Script )
2732 goto Fail;
2733
2734 (void)FT_STREAM_SEEK( cur_offset );
2735 }
2736
2737 if (!p)
2738 {
2739 error = TTO_Err_Invalid_SubTable;
2740 goto Fail;
2741 }
2742
2743 // sort the tag list before returning it
2744 qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
2745
2746 return TT_Err_Ok;
2747
2748 Fail:
2749 FT_FREE( *stags );
2750 return error;
2751 }
2752
2753 static FcChar8 *
2754 FcFontCapabilities(FT_Face face)
2755 {
2756 FcBool issilgraphitefont = 0;
2757 FT_Error err;
2758 FT_ULong len = 0;
2759 FT_ULong *gsubtags=NULL, *gpostags=NULL;
2760 FT_UShort gsub_count=0, gpos_count=0, maxsize;
2761 FT_Memory memory = face->stream->memory;
2762 FcChar8 *complex = NULL;
2763 int indx1 = 0, indx2 = 0;
2764
2765 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2766 issilgraphitefont = ( err == FT_Err_Ok);
2767
2768 err = GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count);
2769 err = GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count);
2770 if (!issilgraphitefont && !gsub_count && !gpos_count)
2771 {
2772 goto bail;
2773 }
2774
2775 maxsize = ((gpos_count + gsub_count) * 15) + (issilgraphitefont ? 13 : 0);
2776 complex = malloc (sizeof (FcChar8) * maxsize);
2777 if (issilgraphitefont)
2778 {
2779 strcpy(complex, "ttable:Silf ");
2780 }
2781 else
2782 {
2783 strcpy(complex, "");
2784 }
2785
2786 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2787 if (indx1 == gsub_count) {
2788 addtag(complex, gpostags[indx2]);
2789 indx2++;
2790 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2791 addtag(complex, gsubtags[indx1]);
2792 indx1++;
2793 } else if (gsubtags[indx1] == gpostags[indx2]) {
2794 addtag(complex, gsubtags[indx1]);
2795 indx1++;
2796 indx2++;
2797 } else {
2798 addtag(complex, gpostags[indx2]);
2799 indx2++;
2800 }
2801 }
2802 if (FcDebug () & FC_DBG_SCANV)
2803 printf("complex features in this font: %s\n", complex);
2804 bail:
2805 FT_FREE(gsubtags);
2806 FT_FREE(gpostags);
2807 return complex;
2808 }