2 * fontconfig/src/fcfreetype.c
4 * Copyright © 2001 Keith Packard
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 the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) 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.
26 Copyright © 2002-2003 by Juliusz Chroboczek
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:
35 The above copyright notice and this permission notice shall be included in
36 all copies or substantial portions of the Software.
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
53 #include FT_FREETYPE_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 #if HAVE_FT_GET_X11_FONT_FORMAT
61 #if HAVE_FT_GET_BDF_PROPERTY
68 #if HAVE_WARNING_CPP_DIRECTIVE
69 #if !HAVE_FT_GET_BDF_PROPERTY
70 #warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later"
73 #if !HAVE_FT_GET_PS_FONT_INFO
74 #warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
79 * Keep Han languages separated by eliminating languages
80 * that the codePageRange bits says aren't supported
85 const FcChar8 lang[6];
86 } FcCodePageRange[] = {
93 #define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
96 FcFreeTypeIsExclusiveLang (const FcChar8 *lang)
100 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
102 if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual)
109 const FT_UShort platform_id;
110 const FT_UShort encoding_id;
111 const char fromcode[12];
114 #define TT_ENCODING_DONT_CARE 0xffff
115 #define FC_ENCODING_MAC_ROMAN "MACINTOSH"
117 static const FcFtEncoding fcFtEncoding[] = {
118 { TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UTF-16BE" },
119 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" },
120 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" },
121 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, "UTF-16BE" },
122 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" },
123 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" },
124 { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB2312" },
125 { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" },
126 { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" },
127 { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" },
128 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UTF-16BE" },
129 { TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" },
130 { TT_PLATFORM_ISO, TT_ISO_ID_10646, "UTF-16BE" },
131 { TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" },
134 #define NUM_FC_FT_ENCODING (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
137 const FT_UShort platform_id;
138 const FT_UShort language_id;
142 #define TT_LANGUAGE_DONT_CARE 0xffff
144 static const FcFtLanguage fcFtLanguage[] = {
145 { TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" },
146 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" },
147 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" },
148 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" },
149 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" },
150 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" },
151 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" },
152 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" },
153 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" },
154 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" },
155 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" },
156 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" },
157 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" },
158 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" },
159 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" },
160 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" },
161 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" },
162 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" },
163 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" },
164 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" },
165 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" },
166 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" },
167 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" },
168 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" },
169 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" },
170 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" },
171 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" },
172 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" },
173 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" },
174 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" },
175 /* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */
176 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" },
177 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" },
178 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" },
179 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" },
180 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" },
181 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" },
182 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" },
183 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" },
184 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" },
185 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" },
186 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" },
187 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" },
188 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" },
189 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" },
190 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" },
191 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" },
192 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" },
193 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" },
194 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" },
195 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" },
196 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
197 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" },
198 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" },
199 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" },
200 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" },
201 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" },
202 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" },
203 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" },
204 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" },
205 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
206 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
207 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" },
208 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" },
209 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" },
210 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" },
211 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" },
212 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" },
213 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" },
214 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" },
215 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" },
216 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" },
217 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" },
218 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" },
219 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" },
220 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" },
221 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" },
222 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" },
223 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" },
224 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" },
225 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" },
226 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" },
227 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" },
228 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" },
229 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" },
230 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" },
231 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" },
232 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" },
233 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" },
234 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" },
235 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" },
236 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" },
237 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" },
238 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" },
239 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" },
240 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" },
241 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" },
242 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" },
243 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" },
244 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" },
245 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" },
246 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" },
247 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" },
248 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" },
249 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" },
250 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" },
251 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" },
252 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" },
253 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" },
254 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" },
256 #if 0 /* these seem to be errors that have been dropped */
258 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC },
259 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC },
263 /* The following codes are new as of 2000-03-10 */
264 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" },
265 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" },
266 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" },
267 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" },
268 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" },
269 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" },
270 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" },
271 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" },
272 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" },
273 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" },
274 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
276 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" },
277 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" },
278 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" },
279 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" },
280 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" },
281 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" },
282 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" },
283 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" },
284 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" },
285 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" },
286 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" },
287 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" },
288 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" },
289 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" },
290 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" },
291 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" },
292 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" },
293 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" },
294 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" },
295 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" },
296 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" },
297 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" },
299 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" },
301 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" },
302 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" },
303 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" },
304 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" },
305 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" },
306 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" },
307 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" },
308 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" },
309 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" },
310 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" },
311 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" },
312 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" },
313 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" },
314 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" },
315 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" },
316 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" },
317 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" },
318 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" },
319 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" },
320 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" },
321 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" },
322 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
323 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" },
324 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
325 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" },
326 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" },
327 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" },
328 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
329 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" },
330 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" },
331 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" },
332 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" },
333 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" },
334 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" },
335 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" },
336 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" },
337 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" },
338 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" },
339 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" },
340 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" },
341 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" },
342 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" },
343 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" },
344 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" },
345 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" },
346 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" },
347 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" },
348 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" },
349 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" },
350 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" },
351 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" },
352 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" },
353 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" },
354 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" },
355 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
356 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" },
357 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" },
358 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" },
359 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" },
360 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" },
361 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" },
362 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" },
363 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" },
364 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
365 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" },
366 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" },
367 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" },
368 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" },
369 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" },
370 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" },
371 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" },
372 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" },
373 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" },
374 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" },
375 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" },
376 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" },
377 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" },
378 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" },
379 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" },
380 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" },
381 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" },
382 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" },
383 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" },
384 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" },
385 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" },
386 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
388 #ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
389 /* this seems to be an error that have been dropped */
390 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" },
393 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" },
394 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" },
395 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" },
396 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" },
397 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
398 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" },
399 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" },
400 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" },
401 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" },
402 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" },
403 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" },
404 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" },
405 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" },
406 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" },
407 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" },
408 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" },
409 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" },
410 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" },
411 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" },
412 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" },
414 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
415 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" },
417 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" },
418 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" },
419 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" },
420 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" },
421 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" },
422 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
423 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" },
424 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" },
425 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" },
426 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" },
427 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" },
428 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" },
429 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" },
430 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" },
431 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" },
432 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" },
433 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" },
434 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" },
435 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" },
437 /* new as of 2001-01-01 */
438 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" },
439 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" },
440 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" },
441 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" },
442 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" },
443 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" },
445 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" },
446 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" },
447 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" },
448 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" },
449 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
450 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" },
451 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" },
452 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" },
453 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" },
455 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" },
456 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" },
458 /* the following seems to be inconsistent;
459 here is the current "official" way: */
460 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" },
461 /* and here is what is used by Passport SDK */
462 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" },
463 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" },
464 /* end of inconsistency */
466 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" },
467 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" },
468 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" },
469 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" },
470 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" },
471 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" },
472 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" },
473 /* the following one is only encountered in Microsoft RTF specification */
474 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" },
475 /* the following one is not in the Passport list, looks like an omission */
476 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" },
477 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" },
478 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" },
479 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" },
481 /* new as of 2001-03-01 (from Office Xp) */
482 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" },
483 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" },
484 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" },
485 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" },
486 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" },
487 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" },
488 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" },
489 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" },
490 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" },
492 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO },
493 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
495 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" },
496 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" },
497 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" },
499 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" },
500 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" },
501 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" },
503 /* New additions from Windows Xp/Passport SDK 2001-11-10. */
505 /* don't ask what this one means... It is commented out currently. */
507 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 },
510 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" },
511 /* The following two IDs blatantly violate MS specs by using a */
512 /* sublanguage >,. */
513 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" },
514 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" },
516 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" },
517 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" },
518 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" },
519 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" },
520 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
522 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA },
523 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA },
524 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA },
526 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" },
527 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" },
528 /* language codes from, to, are (still) unknown. */
529 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" },
530 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" },
531 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" },
532 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" },
533 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" },
534 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" },
536 /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
537 /* not written (but OTOH the peculiar writing system is worth */
539 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA },
541 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
544 #define NUM_FC_FT_LANGUAGE (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
547 FT_UShort language_id;
551 static const FcMacRomanFake fcMacRomanFake[] = {
552 { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" },
553 { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" },
557 FcFontCapabilities(FT_Face face);
559 #define NUM_FC_MAC_ROMAN_FAKE (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
566 * A shift-JIS will have many high bits turned on
569 FcLooksLikeSJIS (FcChar8 *string, int len)
571 int nhigh = 0, nlow = 0;
575 if (*string++ & 0x80) nhigh++;
579 * Heuristic -- if more than 1/3 of the bytes have the high-bit set,
580 * this is likely to be SJIS and not ROMAN
582 if (nhigh * 2 > nlow)
588 FcSfntNameTranscode (FT_SfntName *sname)
591 const char *fromcode;
597 for (i = 0; i < NUM_FC_FT_ENCODING; i++)
598 if (fcFtEncoding[i].platform_id == sname->platform_id &&
599 (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
600 fcFtEncoding[i].encoding_id == sname->encoding_id))
602 if (i == NUM_FC_FT_ENCODING)
604 fromcode = fcFtEncoding[i].fromcode;
607 * Many names encoded for TT_PLATFORM_MACINTOSH are broken
608 * in various ways. Kludge around them.
610 if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
612 if (sname->language_id == TT_MAC_LANGID_ENGLISH &&
613 FcLooksLikeSJIS (sname->string, sname->string_len))
617 else if (sname->language_id >= 0x100)
620 * "real" Mac language IDs are all less than 150.
621 * Names using one of the MS language IDs are assumed
622 * to use an associated encoding (Yes, this is a kludge)
627 for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
628 if (fcMacRomanFake[f].language_id == sname->language_id)
630 fromcode = fcMacRomanFake[f].fromcode;
637 if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
639 FcChar8 *src = sname->string;
640 int src_len = sname->string_len;
648 * Convert Utf16 to Utf8
651 if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
655 * Allocate plenty of space. Freed below
657 utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
663 while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
667 olen = FcUcs4ToUtf8 (ucs4, u8);
673 if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
675 FcChar8 *src = sname->string;
676 int src_len = sname->string_len;
682 * Convert Latin1 to Utf8. Freed below
684 utf8 = malloc (src_len * 2 + 1);
693 olen = FcUcs4ToUtf8 (ucs4, u8);
700 cd = iconv_open ("UTF-8", fromcode);
701 if (cd && cd != (iconv_t) (-1))
703 size_t in_bytes_left = sname->string_len;
704 size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
705 char *inbuf, *outbuf;
707 utf8 = malloc (out_bytes_left + 1);
714 outbuf = (char *) utf8;
715 inbuf = (char *) sname->string;
717 while (in_bytes_left)
719 size_t did = iconv (cd,
720 &inbuf, &in_bytes_left,
721 &outbuf, &out_bytes_left);
722 if (did == (size_t) (-1))
736 if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
744 static const FcChar8 *
745 FcSfntNameLanguage (FT_SfntName *sname)
748 FT_UShort platform_id = sname->platform_id;
749 FT_UShort language_id = sname->language_id;
752 * Many names encoded for TT_PLATFORM_MACINTOSH are broken
753 * in various ways. Kludge around them.
755 if (platform_id == TT_PLATFORM_MACINTOSH &&
756 sname->encoding_id == TT_MAC_ID_ROMAN &&
757 FcLooksLikeSJIS (sname->string, sname->string_len))
759 language_id = TT_MAC_LANGID_JAPANESE;
762 for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
763 if (fcFtLanguage[i].platform_id == platform_id &&
764 (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
765 fcFtLanguage[i].language_id == language_id))
767 if (fcFtLanguage[i].lang[0] == '\0')
770 return (FcChar8 *) fcFtLanguage[i].lang;
775 /* Order is significant. For example, some B&H fonts are hinted by
776 URW++, and both strings appear in the notice. */
778 static const char notice_foundry_data[] =
781 "Bitstream\0bitstream\0"
782 "Monotype\0monotype\0"
783 "Linotype\0linotype\0"
784 "LINOTYPE-HELL\0linotype\0"
787 "International Typeface Corporation\0itc\0"
788 "Tiro Typeworks\0tiro\0"
790 "Microsoft\0microsoft\0"
793 "HanYang System\0hanyang";
795 struct _notice_foundry {
796 /* these are the offsets into the
797 * notice_foundry_data array.
799 unsigned char notice_offset;
800 unsigned char foundry_offset;
803 static const struct _notice_foundry FcNoticeFoundries[] = {
821 #define NUM_NOTICE_FOUNDRIES (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
823 static const FcChar8 *
824 FcNoticeFoundry(const FT_String *notice)
829 for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
831 const struct _notice_foundry *nf = &FcNoticeFoundries[i];
832 const char *n = notice_foundry_data + nf->notice_offset;
833 const char *f = notice_foundry_data + nf->foundry_offset;
835 if (strstr ((const char *) notice, n))
836 return (const FcChar8 *) f;
842 FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
844 /* vendor is not necessarily NUL-terminated. */
847 len = strlen((char *) vendor_string);
848 if (memcmp(vendor, vendor_string, len) != 0)
850 for (i = len; i < 4; i++)
851 if (vendor[i] != ' ' && vendor[i] != '\0')
856 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
858 /* It should not contain useless entries (such as UNKN) nor duplicate
859 entries for padding both with spaces and NULs. */
861 static const struct {
862 const FT_Char vendor[5];
863 const FcChar8 foundry[13];
864 } FcVendorFoundries[] = {
870 { "ATEC", "alltype"},
872 { "BITS", "bitstream"},
874 { "DYNA", "dynalab"},
879 { "IMPR", "impress"},
880 { "LARA", "larabiefonts"},
881 { "LEAF", "interleaf"},
882 { "LETR", "letraset"},
883 { "LINO", "linotype"},
884 { "MACR", "macromedia"},
885 { "MONO", "monotype"},
886 { "MS", "microsoft"},
889 { "PARA", "paratype"},
896 #define NUM_VENDOR_FOUNDRIES (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
898 static const FcChar8 *
899 FcVendorFoundry(const FT_Char vendor[4])
904 for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
905 if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
906 return FcVendorFoundries[i].foundry;
910 typedef struct _FcStringConst {
916 FcStringIsConst (const FcChar8 *string,
917 const FcStringConst *c,
922 for (i = 0; i < nc; i++)
923 if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
929 FcStringContainsConst (const FcChar8 *string,
930 const FcStringConst *c,
935 for (i = 0; i < nc; i++)
937 if (c[i].name[0] == '<')
939 if (FcStrContainsWord (string, c[i].name + 1))
944 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
951 typedef FcChar8 *FC8;
953 static const FcStringConst weightConsts[] = {
954 { (FC8) "thin", FC_WEIGHT_THIN },
955 { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT },
956 { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT },
957 { (FC8) "light", FC_WEIGHT_LIGHT },
958 { (FC8) "book", FC_WEIGHT_BOOK },
959 { (FC8) "regular", FC_WEIGHT_REGULAR },
960 { (FC8) "normal", FC_WEIGHT_NORMAL },
961 { (FC8) "medium", FC_WEIGHT_MEDIUM },
962 { (FC8) "demibold", FC_WEIGHT_DEMIBOLD },
963 { (FC8) "demi", FC_WEIGHT_DEMIBOLD },
964 { (FC8) "semibold", FC_WEIGHT_SEMIBOLD },
965 { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD },
966 { (FC8) "superbold", FC_WEIGHT_EXTRABOLD },
967 { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD },
968 { (FC8) "bold", FC_WEIGHT_BOLD },
969 { (FC8) "ultrablack", FC_WEIGHT_ULTRABLACK },
970 { (FC8) "superblack", FC_WEIGHT_EXTRABLACK },
971 { (FC8) "extrablack", FC_WEIGHT_EXTRABLACK },
972 { (FC8) "<ultra", FC_WEIGHT_ULTRABOLD }, /* only if a word */
973 { (FC8) "black", FC_WEIGHT_BLACK },
974 { (FC8) "heavy", FC_WEIGHT_HEAVY },
977 #define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
979 #define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
980 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
982 static const FcStringConst widthConsts[] = {
983 { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED },
984 { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED },
985 { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED },
986 { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
987 { (FC8) "normal", FC_WIDTH_NORMAL },
988 { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED },
989 { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
990 { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
991 { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
992 { (FC8) "extended", FC_WIDTH_EXPANDED },
995 #define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
997 #define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
998 #define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
1000 static const FcStringConst slantConsts[] = {
1001 { (FC8) "italic", FC_SLANT_ITALIC },
1002 { (FC8) "kursiv", FC_SLANT_ITALIC },
1003 { (FC8) "oblique", FC_SLANT_OBLIQUE },
1006 #define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
1008 #define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
1010 static const FcStringConst decorativeConsts[] = {
1011 { (FC8) "shadow", FcTrue },
1012 { (FC8) "caps", FcTrue },
1013 { (FC8) "antiqua", FcTrue },
1014 { (FC8) "romansc", FcTrue },
1015 { (FC8) "embosed", FcTrue },
1016 { (FC8) "dunhill", FcTrue },
1019 #define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
1021 #define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1024 FcGetPixelSize (FT_Face face, int i)
1026 #if HAVE_FT_GET_BDF_PROPERTY
1027 if (face->num_fixed_sizes == 1)
1029 BDF_PropertyRec prop;
1032 rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
1033 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1034 return (double) prop.u.integer;
1037 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
1038 return (double) face->available_sizes[i].y_ppem / 64.0;
1040 return (double) face->available_sizes[i].height;
1045 FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
1049 for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1050 if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1057 static const FT_UShort platform_order[] = {
1058 TT_PLATFORM_MICROSOFT,
1059 TT_PLATFORM_APPLE_UNICODE,
1060 TT_PLATFORM_MACINTOSH,
1062 #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
1064 static const FT_UShort nameid_order[] = {
1065 #ifdef TT_NAME_ID_WWS_FAMILY
1066 TT_NAME_ID_WWS_FAMILY,
1068 TT_NAME_ID_PREFERRED_FAMILY,
1069 TT_NAME_ID_FONT_FAMILY,
1070 TT_NAME_ID_MAC_FULL_NAME,
1071 TT_NAME_ID_FULL_NAME,
1072 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1073 TT_NAME_ID_WWS_SUBFAMILY,
1075 TT_NAME_ID_PREFERRED_SUBFAMILY,
1076 TT_NAME_ID_FONT_SUBFAMILY,
1077 TT_NAME_ID_TRADEMARK,
1078 TT_NAME_ID_MANUFACTURER,
1081 #define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0]))
1083 FcFreeTypeQueryFace (const FT_Face face,
1084 const FcChar8 *file,
1092 FcBool decorative = FcFalse;
1097 FcChar8 *family = 0;
1100 const FcChar8 *foundry = 0;
1103 #if HAVE_FT_GET_PS_FONT_INFO
1104 PS_FontInfoRec psfontinfo;
1106 #if HAVE_FT_GET_BDF_PROPERTY
1107 BDF_PropertyRec prop;
1110 const FcChar8 *exclusiveLang = 0;
1112 FT_UInt snamei, snamec;
1115 int nfamily_lang = 0;
1117 int nstyle_lang = 0;
1119 int nfullname_lang = 0;
1121 int platform, nameid;
1126 pat = FcPatternCreate ();
1130 if (!FcPatternAddBool (pat, FC_OUTLINE,
1131 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1134 if (!FcPatternAddBool (pat, FC_SCALABLE,
1135 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1140 * Get the OS/2 table
1142 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1145 * Look first in the OS/2 table for the foundry, if
1146 * not found here, the various notices will be searched for
1147 * that information, either from the sfnt name tables or
1148 * the Postscript FontInfo dictionary. Finally, the
1149 * BDF properties will queried.
1152 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1153 foundry = FcVendorFoundry(os2->achVendID);
1155 if (FcDebug () & FC_DBG_SCANV)
1158 * Grub through the name table looking for family
1159 * and style names. FreeType makes quite a hash
1162 snamec = FT_Get_Sfnt_Name_Count (face);
1163 for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
1165 if (p < NUM_PLATFORM_ORDER)
1166 platform = platform_order[p];
1171 * Order nameids so preferred names appear first
1172 * in the resulting list
1174 for (n = 0; n < NUM_NAMEID_ORDER; n++)
1176 nameid = nameid_order[n];
1178 for (snamei = 0; snamei < snamec; snamei++)
1181 const FcChar8 *lang;
1182 const char *elt = 0, *eltlang = 0;
1183 int *np = 0, *nlangp = 0;
1186 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1188 if (sname.name_id != nameid)
1192 * Sort platforms in preference order, accepting
1193 * all other platforms last
1195 if (p < NUM_PLATFORM_ORDER)
1197 if (sname.platform_id != platform)
1204 for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1205 if (sname.platform_id == platform_order[sp])
1207 if (sp != NUM_PLATFORM_ORDER)
1210 utf8 = FcSfntNameTranscode (&sname);
1211 lang = FcSfntNameLanguage (&sname);
1216 switch (sname.name_id) {
1217 #ifdef TT_NAME_ID_WWS_FAMILY
1218 case TT_NAME_ID_WWS_FAMILY:
1220 case TT_NAME_ID_PREFERRED_FAMILY:
1221 case TT_NAME_ID_FONT_FAMILY:
1223 case TT_NAME_ID_PS_NAME:
1224 case TT_NAME_ID_UNIQUE_ID:
1226 if (FcDebug () & FC_DBG_SCANV)
1227 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1228 sname.name_id, sname.platform_id,
1229 sname.encoding_id, sname.language_id,
1233 eltlang = FC_FAMILYLANG;
1235 nlangp = &nfamily_lang;
1237 case TT_NAME_ID_MAC_FULL_NAME:
1238 case TT_NAME_ID_FULL_NAME:
1239 if (FcDebug () & FC_DBG_SCANV)
1240 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
1241 sname.name_id, sname.platform_id,
1242 sname.encoding_id, sname.language_id,
1246 eltlang = FC_FULLNAMELANG;
1248 nlangp = &nfullname_lang;
1250 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1251 case TT_NAME_ID_WWS_SUBFAMILY:
1253 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1254 case TT_NAME_ID_FONT_SUBFAMILY:
1260 len = strlen ((const char *) pp);
1261 memmove (utf8, pp, len + 1);
1262 pp = utf8 + len - 1;
1267 if (FcDebug () & FC_DBG_SCANV)
1268 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1269 sname.name_id, sname.platform_id,
1270 sname.encoding_id, sname.language_id,
1274 eltlang = FC_STYLELANG;
1276 nlangp = &nstyle_lang;
1278 case TT_NAME_ID_TRADEMARK:
1279 case TT_NAME_ID_MANUFACTURER:
1280 /* If the foundry wasn't found in the OS/2 table, look here */
1282 foundry = FcNoticeFoundry((FT_String *) utf8);
1287 if (FcStringInPatternElement (pat, elt, utf8))
1293 /* add new element */
1294 if (!FcPatternAddString (pat, elt, utf8))
1302 /* pad lang list with 'xx' to line up with elt */
1303 while (*nlangp < *np)
1305 if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
1309 if (!FcPatternAddString (pat, eltlang, lang))
1321 if (!nfamily && face->family_name &&
1322 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1324 if (FcDebug () & FC_DBG_SCANV)
1325 printf ("using FreeType family \"%s\"\n", face->family_name);
1326 if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1331 if (!nstyle && face->style_name &&
1332 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1334 if (FcDebug () & FC_DBG_SCANV)
1335 printf ("using FreeType style \"%s\"\n", face->style_name);
1336 if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1343 FcChar8 *start, *end;
1346 start = (FcChar8 *) strrchr ((char *) file, '/');
1350 start = (FcChar8 *) file;
1351 end = (FcChar8 *) strrchr ((char *) start, '.');
1353 end = start + strlen ((char *) start);
1355 family = malloc (end - start + 1);
1356 strncpy ((char *) family, (char *) start, end - start);
1357 family[end - start] = '\0';
1358 if (FcDebug () & FC_DBG_SCANV)
1359 printf ("using filename for family %s\n", family);
1360 if (!FcPatternAddString (pat, FC_FAMILY, family))
1369 if (!FcPatternAddString (pat, FC_FILE, file))
1372 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1377 * don't even try this -- CJK 'monospace' fonts are really
1378 * dual width, and most other fonts don't bother to set
1379 * the attribute. Sigh.
1381 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1382 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1387 * Find the font revision (if available)
1389 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1392 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1397 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1401 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1403 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1407 if (FcCodePageRange[i].bit < 32)
1409 bits = os2->ulCodePageRange1;
1410 bit = FcCodePageRange[i].bit;
1414 bits = os2->ulCodePageRange2;
1415 bit = FcCodePageRange[i].bit - 32;
1417 if (bits & (1 << bit))
1420 * If the font advertises support for multiple
1421 * "exclusive" languages, then include support
1422 * for any language found to have coverage
1429 exclusiveLang = FcCodePageRange[i].lang;
1434 if (os2 && os2->version != 0xffff)
1436 if (os2->usWeightClass == 0)
1438 else if (os2->usWeightClass < 150)
1439 weight = FC_WEIGHT_THIN;
1440 else if (os2->usWeightClass < 250)
1441 weight = FC_WEIGHT_EXTRALIGHT;
1442 else if (os2->usWeightClass < 350)
1443 weight = FC_WEIGHT_LIGHT;
1444 else if (os2->usWeightClass < 450)
1445 weight = FC_WEIGHT_REGULAR;
1446 else if (os2->usWeightClass < 550)
1447 weight = FC_WEIGHT_MEDIUM;
1448 else if (os2->usWeightClass < 650)
1449 weight = FC_WEIGHT_SEMIBOLD;
1450 else if (os2->usWeightClass < 750)
1451 weight = FC_WEIGHT_BOLD;
1452 else if (os2->usWeightClass < 850)
1453 weight = FC_WEIGHT_EXTRABOLD;
1454 else if (os2->usWeightClass < 925)
1455 weight = FC_WEIGHT_BLACK;
1456 else if (os2->usWeightClass < 1000)
1457 weight = FC_WEIGHT_EXTRABLACK;
1458 if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1459 printf ("\tos2 weight class %d maps to weight %d\n",
1460 os2->usWeightClass, weight);
1462 switch (os2->usWidthClass) {
1463 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1464 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1465 case 3: width = FC_WIDTH_CONDENSED; break;
1466 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1467 case 5: width = FC_WIDTH_NORMAL; break;
1468 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1469 case 7: width = FC_WIDTH_EXPANDED; break;
1470 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1471 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1473 if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1474 printf ("\tos2 width class %d maps to width %d\n",
1475 os2->usWidthClass, width);
1477 if (os2 && (complex_ = FcFontCapabilities(face)))
1479 if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
1488 * Type 1: Check for FontInfo dictionary information
1489 * Code from g2@magestudios.net (Gerard Escalante)
1492 #if HAVE_FT_GET_PS_FONT_INFO
1493 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1495 if (weight == -1 && psfontinfo.weight)
1497 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1498 if (FcDebug() & FC_DBG_SCANV)
1499 printf ("\tType1 weight %s maps to %d\n",
1500 psfontinfo.weight, weight);
1505 * Don't bother with italic_angle; FreeType already extracts that
1506 * information for us and sticks it into style_flags
1508 if (psfontinfo.italic_angle)
1509 slant = FC_SLANT_ITALIC;
1511 slant = FC_SLANT_ROMAN;
1515 foundry = FcNoticeFoundry(psfontinfo.notice);
1517 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1519 #if HAVE_FT_GET_BDF_PROPERTY
1521 * Finally, look for a FOUNDRY BDF property if no other
1522 * mechanism has managed to locate a foundry
1528 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1529 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1530 foundry = (FcChar8 *) prop.u.atom;
1535 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1536 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1537 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1541 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1542 value = prop.u.integer;
1544 value = (FT_Int32) prop.u.cardinal;
1545 switch ((value + 5) / 10) {
1546 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1547 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1548 case 3: width = FC_WIDTH_CONDENSED; break;
1549 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1550 case 5: width = FC_WIDTH_NORMAL; break;
1551 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1552 case 7: width = FC_WIDTH_EXPANDED; break;
1553 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1554 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1558 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1559 prop.type == BDF_PROPERTY_TYPE_ATOM)
1561 width = FcIsWidth ((FcChar8 *) prop.u.atom);
1562 if (FcDebug () & FC_DBG_SCANV)
1563 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1569 * Look for weight, width and slant names in the style value
1571 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1575 weight = FcContainsWeight (style);
1576 if (FcDebug() & FC_DBG_SCANV)
1577 printf ("\tStyle %s maps to weight %d\n", style, weight);
1581 width = FcContainsWidth (style);
1582 if (FcDebug() & FC_DBG_SCANV)
1583 printf ("\tStyle %s maps to width %d\n", style, width);
1587 slant = FcContainsSlant (style);
1588 if (FcDebug() & FC_DBG_SCANV)
1589 printf ("\tStyle %s maps to slant %d\n", style, slant);
1591 if (decorative == FcFalse)
1593 decorative = FcContainsDecorative (style) > 0;
1594 if (FcDebug() & FC_DBG_SCANV)
1595 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1599 * Pull default values from the FreeType flags if more
1600 * specific values not found above
1604 slant = FC_SLANT_ROMAN;
1605 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1606 slant = FC_SLANT_ITALIC;
1611 weight = FC_WEIGHT_MEDIUM;
1612 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1613 weight = FC_WEIGHT_BOLD;
1617 width = FC_WIDTH_NORMAL;
1620 foundry = (FcChar8 *) "unknown";
1622 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1625 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1628 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1631 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1634 if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1638 * Compute the unicode coverage for the font
1640 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1644 #if HAVE_FT_GET_BDF_PROPERTY
1645 /* For PCF fonts, override the computed spacing with the one from
1647 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1648 prop.type == BDF_PROPERTY_TYPE_ATOM) {
1649 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1650 spacing = FC_CHARCELL;
1651 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1653 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1654 spacing = FC_PROPORTIONAL;
1659 * Skip over PCF fonts that have no encoded characters; they're
1660 * usually just Unicode fonts transcoded to some legacy encoding
1661 * FT forces us to approximate whether a font is a PCF font
1662 * or not by whether it has any BDF properties. Try PIXEL_SIZE;
1663 * I don't know how to get a list of BDF properties on the font. -PL
1665 if (FcCharSetCount (cs) == 0)
1667 #if HAVE_FT_GET_BDF_PROPERTY
1668 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1673 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1676 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1680 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1682 FcLangSetDestroy (ls);
1686 FcLangSetDestroy (ls);
1688 if (spacing != FC_PROPORTIONAL)
1689 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1692 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1694 for (i = 0; i < face->num_fixed_sizes; i++)
1695 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1696 FcGetPixelSize (face, i)))
1698 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1701 #if HAVE_FT_GET_X11_FONT_FORMAT
1703 * Use the (not well documented or supported) X-specific function
1704 * from FreeType to figure out the font format
1707 const char *font_format = FT_Get_X11_Font_Format (face);
1709 FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
1714 * Drop our reference to the charset
1716 FcCharSetDestroy (cs);
1721 FcCharSetDestroy (cs);
1723 FcPatternDestroy (pat);
1729 FcFreeTypeQuery(const FcChar8 *file,
1735 FT_Library ftLibrary;
1736 FcPattern *pat = NULL;
1738 if (FT_Init_FreeType (&ftLibrary))
1741 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1744 *count = face->num_faces;
1746 pat = FcFreeTypeQueryFace (face, file, id, blanks);
1748 FT_Done_Face (face);
1750 FT_Done_FreeType (ftLibrary);
1755 * For our purposes, this approximation is sufficient
1757 #if !HAVE_FT_GET_NEXT_CHAR
1758 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1760 (*(gi) = 1), (ucs4) + 1)
1761 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1764 typedef struct _FcCharEnt {
1766 unsigned char encode;
1770 const FcCharEnt *ent;
1774 typedef struct _FcFontDecode {
1775 FT_Encoding encoding;
1776 const FcCharMap *map;
1780 static const FcCharEnt AdobeSymbolEnt[] = {
1781 { 0x0020, 0x20 }, /* SPACE # space */
1782 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
1783 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
1784 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
1785 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
1786 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
1787 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
1788 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
1789 { 0x002C, 0x2C }, /* COMMA # comma */
1790 { 0x002E, 0x2E }, /* FULL STOP # period */
1791 { 0x002F, 0x2F }, /* SOLIDUS # slash */
1792 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
1793 { 0x0031, 0x31 }, /* DIGIT ONE # one */
1794 { 0x0032, 0x32 }, /* DIGIT TWO # two */
1795 { 0x0033, 0x33 }, /* DIGIT THREE # three */
1796 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
1797 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
1798 { 0x0036, 0x36 }, /* DIGIT SIX # six */
1799 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
1800 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
1801 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
1802 { 0x003A, 0x3A }, /* COLON # colon */
1803 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
1804 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1805 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
1806 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
1807 { 0x003F, 0x3F }, /* QUESTION MARK # question */
1808 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
1809 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
1810 { 0x005F, 0x5F }, /* LOW LINE # underscore */
1811 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
1812 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
1813 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
1814 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1815 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
1816 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
1817 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
1818 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
1819 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
1820 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
1821 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1822 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
1823 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
1824 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
1825 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
1826 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
1827 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
1828 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
1829 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
1830 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
1831 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
1832 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
1833 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
1834 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
1835 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
1836 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
1837 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
1838 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
1839 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
1840 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
1841 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
1842 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
1843 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
1844 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
1845 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
1846 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
1847 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
1848 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
1849 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
1850 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
1851 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
1852 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1853 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
1854 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
1855 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
1856 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
1857 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
1858 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
1859 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
1860 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
1861 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
1862 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1863 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1864 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
1865 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
1866 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
1867 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
1868 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
1869 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
1870 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
1871 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
1872 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
1873 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
1874 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
1875 { 0x2022, 0xB7 }, /* BULLET # bullet */
1876 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
1877 { 0x2032, 0xA2 }, /* PRIME # minute */
1878 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
1879 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
1880 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
1881 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
1882 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
1883 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
1884 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
1885 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
1886 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
1887 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
1888 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
1889 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
1890 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
1891 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
1892 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
1893 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
1894 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
1895 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
1896 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
1897 { 0x2200, 0x22 }, /* FOR ALL # universal */
1898 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
1899 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
1900 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
1901 { 0x2206, 0x44 }, /* INCREMENT # Delta */
1902 { 0x2207, 0xD1 }, /* NABLA # gradient */
1903 { 0x2208, 0xCE }, /* ELEMENT OF # element */
1904 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
1905 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
1906 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
1907 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
1908 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
1909 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
1910 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
1911 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
1912 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
1913 { 0x221E, 0xA5 }, /* INFINITY # infinity */
1914 { 0x2220, 0xD0 }, /* ANGLE # angle */
1915 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
1916 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
1917 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
1918 { 0x222A, 0xC8 }, /* UNION # union */
1919 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
1920 { 0x2234, 0x5C }, /* THEREFORE # therefore */
1921 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
1922 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
1923 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
1924 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
1925 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
1926 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
1927 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
1928 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
1929 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
1930 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
1931 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
1932 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
1933 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
1934 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
1935 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
1936 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
1937 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
1938 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
1939 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
1940 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
1941 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
1942 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
1943 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
1944 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
1945 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
1946 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
1947 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
1948 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
1949 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
1950 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
1951 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
1952 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
1953 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
1954 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
1955 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
1956 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
1957 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
1958 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
1959 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
1960 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
1961 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
1962 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
1963 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
1964 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
1965 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
1966 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
1967 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
1968 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
1969 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
1970 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
1971 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
1972 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
1973 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
1974 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
1977 static const FcCharMap AdobeSymbol = {
1979 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
1982 static const FcFontDecode fcFontDecoders[] = {
1983 { ft_encoding_unicode, 0, (1 << 21) - 1 },
1984 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
1987 #define NUM_DECODE (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
1989 static const FcChar32 prefer_unicode[] = {
1990 0x20ac, /* EURO SIGN */
1993 #define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
1996 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2002 high = map->nent - 1;
2003 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2007 mid = (high + low) >> 1;
2008 bmp = map->ent[mid].bmp;
2010 return (FT_ULong) map->ent[mid].encode;
2020 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2024 for (i = 0; i < map->nent; i++)
2025 if (map->ent[i].encode == private)
2026 return (FcChar32) map->ent[i].bmp;
2031 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2035 for (i = 0; i < NUM_DECODE; i++)
2036 if (fcFontDecoders[i].encoding == encoding)
2037 return fcFontDecoders[i].map;
2041 #include "../fc-glyphname/fcglyphname.h"
2044 FcHashGlyphName (const FcChar8 *name)
2049 while ((c = *name++))
2051 h = ((h << 1) | (h >> 31)) ^ c;
2056 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2058 * Use Type1 glyph names for fonts which have reliable names
2059 * and which export an Adobe Custom mapping
2062 FcFreeTypeUseNames (FT_Face face)
2066 if (!FT_Has_PS_Glyph_Names (face))
2068 for (map = 0; map < face->num_charmaps; map++)
2069 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2074 static const FcChar8 *
2075 FcUcs4ToGlyphName (FcChar32 ucs4)
2077 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2081 while ((gn = _fc_ucs_to_name[i]) != -1)
2083 if (_fc_glyph_names[gn].ucs == ucs4)
2084 return _fc_glyph_names[gn].name;
2087 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2092 if (i >= FC_GLYPHNAME_HASH)
2093 i -= FC_GLYPHNAME_HASH;
2099 FcGlyphNameToUcs4 (FcChar8 *name)
2101 FcChar32 h = FcHashGlyphName (name);
2102 int i = (int) (h % FC_GLYPHNAME_HASH);
2106 while ((gn = _fc_name_to_ucs[i]) != -1)
2108 if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name))
2109 return _fc_glyph_names[gn].ucs;
2112 r = (int) (h % FC_GLYPHNAME_REHASH);
2117 if (i >= FC_GLYPHNAME_HASH)
2118 i -= FC_GLYPHNAME_HASH;
2124 * Work around a bug in some FreeType versions which fail
2125 * to correctly bounds check glyph name buffers and overwrite
2126 * the stack. As Postscript names have a limit of 127 characters,
2127 * this should be sufficient.
2130 #if FC_GLYPHNAME_MAXLEN < 127
2131 # define FC_GLYPHNAME_BUFLEN 127
2133 # define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2137 * Search through a font for a glyph by name. This is
2138 * currently a linear search as there doesn't appear to be
2139 * any defined order within the font
2142 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2145 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2147 for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2149 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2150 if (!strcmp ((char *) name, (char *) name_buf))
2158 * Map a UCS4 glyph to a glyph index. Use all available encoding
2159 * tables to try and find one that works. This information is expected
2160 * to be cached by higher levels, so performance isn't critical
2164 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2166 int initial, offset, decode;
2177 * Find the current encoding
2181 for (; initial < NUM_DECODE; initial++)
2182 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2184 if (initial == NUM_DECODE)
2187 for (p = 0; p < NUM_PREFER_UNICODE; p++)
2188 if (ucs4 == prefer_unicode[p])
2194 * Check each encoding for the glyph, starting with the current one
2196 for (offset = 0; offset < NUM_DECODE; offset++)
2198 decode = (initial + offset) % NUM_DECODE;
2199 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2200 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2202 if (fcFontDecoders[decode].map)
2204 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2205 if (charcode == ~0U)
2210 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2214 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2216 * Check postscript name table if present
2218 if (FcFreeTypeUseNames (face))
2220 const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
2223 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2233 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2234 FT_UInt glyph, FcBlanks *blanks,
2236 FcBool using_strike)
2238 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2242 load_flags &= ~FT_LOAD_NO_SCALE;
2245 * When using scalable fonts, only report those glyphs
2246 * which can be scaled; otherwise those fonts will
2247 * only be available at some sizes, and never when
2248 * transformed. Avoid this by simply reporting bitmap-only
2251 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2252 load_flags |= FT_LOAD_NO_BITMAP;
2254 if (FT_Load_Glyph (face, glyph, load_flags))
2261 *advance = slot->metrics.horiAdvance;
2263 switch ((int) slot->format) {
2264 case ft_glyph_format_bitmap:
2266 * Bitmaps are assumed to be reasonable; if
2267 * this proves to be a rash assumption, this
2268 * code can be easily modified
2271 case ft_glyph_format_outline:
2273 * Glyphs with contours are always OK
2275 if (slot->outline.n_contours != 0)
2278 * Glyphs with no contours are only OK if
2279 * they're members of the Blanks set specified
2280 * in the configuration. If blanks isn't set,
2281 * then allow any glyph to be blank
2283 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2285 /* fall through ... */
2292 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2295 FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index)
2297 FcChar32 page, off, ucs4;
2299 FcChar32 font_max = 0;
2303 const FcCharMap *map;
2307 FT_Pos advance, advance_one = 0, advance_two = 0;
2308 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2309 FcBool using_strike = FcFalse;
2311 fcs = FcCharSetCreate ();
2315 #if HAVE_FT_SELECT_SIZE
2316 if (strike_index >= 0) {
2317 if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
2319 using_strike = FcTrue;
2324 printf ("Family %s style %s\n", face->family_name, face->style_name);
2326 for (o = 0; o < NUM_DECODE; o++)
2328 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2330 map = fcFontDecoders[o].map;
2334 * Non-Unicode tables are easy; there's a list of all possible
2337 for (i = 0; i < map->nent; i++)
2339 ucs4 = map->ent[i].bmp;
2340 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2342 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2345 * ignore glyphs with zero advance. They’re
2346 * combining characters, and while their behaviour
2347 * isn’t well defined for monospaced applications in
2348 * Unicode, there are many fonts which include
2349 * zero-width combining characters in otherwise
2356 has_advance = FcTrue;
2357 advance_one = advance;
2359 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2363 dual_advance = FcTrue;
2364 fixed_advance = FcFalse;
2365 advance_two = advance;
2367 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2368 dual_advance = FcFalse;
2372 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2375 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2377 if (ucs4 > font_max)
2387 ucs4 = FT_Get_First_Char (face, &glyph);
2390 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2396 has_advance = FcTrue;
2397 advance_one = advance;
2399 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2403 dual_advance = FcTrue;
2404 fixed_advance = FcFalse;
2405 advance_two = advance;
2407 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2408 dual_advance = FcFalse;
2412 if ((ucs4 >> 8) != page)
2415 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2420 leaf->map[off >> 5] |= (1 << (off & 0x1f));
2422 if (ucs4 > font_max)
2426 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2429 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2431 FcBool FT_Has, FC_Has;
2433 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2434 FC_Has = FcCharSetHasChar (fcs, ucs4);
2435 if (FT_Has != FC_Has)
2437 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2443 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2445 * Add mapping from PS glyph names if available
2447 if (FcFreeTypeUseNames (face))
2449 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2451 for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2453 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2455 ucs4 = FcGlyphNameToUcs4 (name_buf);
2456 if (ucs4 != 0xffff &&
2457 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2463 has_advance = FcTrue;
2464 advance_one = advance;
2466 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2470 dual_advance = FcTrue;
2471 fixed_advance = FcFalse;
2472 advance_two = advance;
2474 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2475 dual_advance = FcFalse;
2478 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2481 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2483 if (ucs4 > font_max)
2492 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2493 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2495 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2496 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2498 if (has_char && !has_bit)
2500 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2501 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2503 printf ("Bitmap missing char 0x%x\n", ucs4);
2505 else if (!has_char && has_bit)
2506 printf ("Bitmap extra char 0x%x\n", ucs4);
2511 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2514 *spacing = FC_PROPORTIONAL;
2517 FcCharSetDestroy (fcs);
2523 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2528 * Check for bitmap-only ttf fonts that are missing the glyf table.
2529 * In that case, pick a size and look for glyphs in that size instead
2531 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
2532 face->num_fixed_sizes > 0 &&
2533 FT_Get_Sfnt_Table (face, ft_sfnt_head))
2535 FT_Int strike_index = 0;
2538 /* Select the face closest to 16 pixels tall */
2539 for (i = 1; i < face->num_fixed_sizes; i++) {
2540 if (abs (face->available_sizes[i].height - 16) <
2541 abs (face->available_sizes[strike_index].height - 16))
2544 cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index);
2547 cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1);
2552 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2556 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2560 #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2561 #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2562 #define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2564 #define OTLAYOUT_HEAD "otlayout:"
2565 #define OTLAYOUT_HEAD_LEN 9
2566 #define OTLAYOUT_ID_LEN 4
2567 /* space + head + id */
2568 #define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2571 * This is a bit generous; the registry has only lower case and space
2572 * except for 'DFLT'.
2574 #define FcIsSpace(x) (040 == (x))
2575 #define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2578 addtag(FcChar8 *complex_, FT_ULong tag)
2580 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2582 tagstring[0] = (FcChar8)(tag >> 24),
2583 tagstring[1] = (FcChar8)(tag >> 16),
2584 tagstring[2] = (FcChar8)(tag >> 8),
2585 tagstring[3] = (FcChar8)(tag);
2586 tagstring[4] = '\0';
2588 /* skip tags which aren't alphabetic, under the assumption that
2589 * they're probably broken
2591 if (!FcIsValidScript(tagstring[0]) ||
2592 !FcIsValidScript(tagstring[1]) ||
2593 !FcIsValidScript(tagstring[2]) ||
2594 !FcIsValidScript(tagstring[3]))
2597 if (*complex_ != '\0')
2598 strcat ((char *) complex_, " ");
2599 strcat ((char *) complex_, OTLAYOUT_HEAD);
2600 strcat ((char *) complex_, (char *) tagstring);
2604 compareulong (const void *a, const void *b)
2606 const FT_ULong *ua = (const FT_ULong *) a;
2607 const FT_ULong *ub = (const FT_ULong *) b;
2613 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
2615 FT_ULong cur_offset, new_offset, base_offset;
2616 FT_Stream stream = face->stream;
2624 if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2627 base_offset = ftglue_stream_pos ( stream );
2631 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2634 new_offset = GET_UShort() + base_offset;
2636 ftglue_stream_frame_exit( stream );
2638 cur_offset = ftglue_stream_pos( stream );
2640 if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
2643 base_offset = ftglue_stream_pos( stream );
2645 if ( ftglue_stream_frame_enter( stream, 2L ) )
2648 script_count = GET_UShort ();
2650 ftglue_stream_frame_exit( stream );
2652 *stags = malloc(script_count * sizeof (FT_ULong));
2657 for ( n = 0; n < script_count; n++ )
2659 if ( ftglue_stream_frame_enter( stream, 6L ) )
2662 (*stags)[p] = GET_ULong ();
2663 new_offset = GET_UShort () + base_offset;
2665 ftglue_stream_frame_exit( stream );
2667 cur_offset = ftglue_stream_pos( stream );
2669 error = ftglue_stream_seek( stream, new_offset );
2671 if ( error == FT_Err_Ok )
2674 (void)ftglue_stream_seek( stream, cur_offset );
2680 /* sort the tag list before returning it */
2681 qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
2683 return script_count;
2692 FcFontCapabilities(FT_Face face)
2694 FcBool issilgraphitefont = 0;
2697 FT_ULong *gsubtags=NULL, *gpostags=NULL;
2698 FT_UShort gsub_count=0, gpos_count=0;
2700 FcChar8 *complex_ = NULL;
2701 int indx1 = 0, indx2 = 0;
2703 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2704 issilgraphitefont = ( err == FT_Err_Ok);
2706 gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
2707 gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
2709 if (!issilgraphitefont && !gsub_count && !gpos_count)
2712 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2713 (issilgraphitefont ? 13 : 0));
2714 complex_ = malloc (sizeof (FcChar8) * maxsize);
2719 if (issilgraphitefont)
2720 strcpy((char *) complex_, "ttable:Silf ");
2722 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2723 if (indx1 == gsub_count) {
2724 addtag(complex_, gpostags[indx2]);
2726 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2727 addtag(complex_, gsubtags[indx1]);
2729 } else if (gsubtags[indx1] == gpostags[indx2]) {
2730 addtag(complex_, gsubtags[indx1]);
2734 addtag(complex_, gpostags[indx2]);
2738 if (FcDebug () & FC_DBG_SCANV)
2739 printf("complex_ features in this font: %s\n", complex_);
2746 #define __fcfreetype__
2747 #include "fcaliastail.h"
2748 #include "fcftaliastail.h"
2749 #undef __fcfreetype__