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 *FcNoticeFoundries[][2] =
782 {"Bitstream", "bitstream"},
785 {"HanYang System", "hanyang"},
788 {"International Typeface Corporation", "itc"},
789 {"Linotype", "linotype"},
790 {"LINOTYPE-HELL", "linotype"},
791 {"Microsoft", "microsoft"},
792 {"Monotype", "monotype"},
794 {"Tiro Typeworks", "tiro"},
796 {"XFree86", "xfree86"},
800 #define NUM_NOTICE_FOUNDRIES (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
802 static const FcChar8 *
803 FcNoticeFoundry(const FT_String *notice)
808 for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
810 const char *n = FcNoticeFoundries[i][0];
811 const char *f = FcNoticeFoundries[i][1];
813 if (strstr ((const char *) notice, n))
814 return (const FcChar8 *) f;
820 FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
822 /* vendor is not necessarily NUL-terminated. */
825 len = strlen((char *) vendor_string);
826 if (memcmp(vendor, vendor_string, len) != 0)
828 for (i = len; i < 4; i++)
829 if (vendor[i] != ' ' && vendor[i] != '\0')
834 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
836 /* It should not contain useless entries (such as UNKN) nor duplicate
837 entries for padding both with spaces and NULs. */
839 static const struct {
840 const FT_Char vendor[5];
841 const FcChar8 foundry[13];
842 } FcVendorFoundries[] = {
848 { "ATEC", "alltype"},
850 { "BITS", "bitstream"},
853 { "DYNA", "dynalab"},
858 { "IMPR", "impress"},
859 { "LARA", "larabiefonts"},
860 { "LEAF", "interleaf"},
861 { "LETR", "letraset"},
862 { "LINO", "linotype"},
863 { "MACR", "macromedia"},
864 { "MONO", "monotype"},
865 { "MS", "microsoft"},
868 { "PARA", "paratype"},
875 #define NUM_VENDOR_FOUNDRIES (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
877 static const FcChar8 *
878 FcVendorFoundry(const FT_Char vendor[4])
883 for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
884 if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
885 return FcVendorFoundries[i].foundry;
889 typedef struct _FcStringConst {
895 FcStringIsConst (const FcChar8 *string,
896 const FcStringConst *c,
901 for (i = 0; i < nc; i++)
902 if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
908 FcStringContainsConst (const FcChar8 *string,
909 const FcStringConst *c,
914 for (i = 0; i < nc; i++)
916 if (c[i].name[0] == '<')
918 if (FcStrContainsWord (string, c[i].name + 1))
923 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
930 typedef FcChar8 *FC8;
932 static const FcStringConst weightConsts[] = {
933 { (FC8) "thin", FC_WEIGHT_THIN },
934 { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT },
935 { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT },
936 { (FC8) "light", FC_WEIGHT_LIGHT },
937 { (FC8) "book", FC_WEIGHT_BOOK },
938 { (FC8) "regular", FC_WEIGHT_REGULAR },
939 { (FC8) "normal", FC_WEIGHT_NORMAL },
940 { (FC8) "medium", FC_WEIGHT_MEDIUM },
941 { (FC8) "demibold", FC_WEIGHT_DEMIBOLD },
942 { (FC8) "demi", FC_WEIGHT_DEMIBOLD },
943 { (FC8) "semibold", FC_WEIGHT_SEMIBOLD },
944 { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD },
945 { (FC8) "superbold", FC_WEIGHT_EXTRABOLD },
946 { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD },
947 { (FC8) "bold", FC_WEIGHT_BOLD },
948 { (FC8) "ultrablack", FC_WEIGHT_ULTRABLACK },
949 { (FC8) "superblack", FC_WEIGHT_EXTRABLACK },
950 { (FC8) "extrablack", FC_WEIGHT_EXTRABLACK },
951 { (FC8) "<ultra", FC_WEIGHT_ULTRABOLD }, /* only if a word */
952 { (FC8) "black", FC_WEIGHT_BLACK },
953 { (FC8) "heavy", FC_WEIGHT_HEAVY },
956 #define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
958 #define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
959 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
961 static const FcStringConst widthConsts[] = {
962 { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED },
963 { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED },
964 { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED },
965 { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
966 { (FC8) "normal", FC_WIDTH_NORMAL },
967 { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED },
968 { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
969 { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
970 { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
971 { (FC8) "extended", FC_WIDTH_EXPANDED },
974 #define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
976 #define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
977 #define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
979 static const FcStringConst slantConsts[] = {
980 { (FC8) "italic", FC_SLANT_ITALIC },
981 { (FC8) "kursiv", FC_SLANT_ITALIC },
982 { (FC8) "oblique", FC_SLANT_OBLIQUE },
985 #define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
987 #define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
989 static const FcStringConst decorativeConsts[] = {
990 { (FC8) "shadow", FcTrue },
991 { (FC8) "caps", FcTrue },
992 { (FC8) "antiqua", FcTrue },
993 { (FC8) "romansc", FcTrue },
994 { (FC8) "embosed", FcTrue },
995 { (FC8) "dunhill", FcTrue },
998 #define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
1000 #define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1003 FcGetPixelSize (FT_Face face, int i)
1005 #if HAVE_FT_GET_BDF_PROPERTY
1006 if (face->num_fixed_sizes == 1)
1008 BDF_PropertyRec prop;
1011 rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
1012 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1013 return (double) prop.u.integer;
1016 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
1017 return (double) face->available_sizes[i].y_ppem / 64.0;
1019 return (double) face->available_sizes[i].height;
1024 FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
1028 for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1029 if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1036 static const FT_UShort platform_order[] = {
1037 TT_PLATFORM_MICROSOFT,
1038 TT_PLATFORM_APPLE_UNICODE,
1039 TT_PLATFORM_MACINTOSH,
1041 #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
1043 static const FT_UShort nameid_order[] = {
1044 #ifdef TT_NAME_ID_WWS_FAMILY
1045 TT_NAME_ID_WWS_FAMILY,
1047 TT_NAME_ID_PREFERRED_FAMILY,
1048 TT_NAME_ID_FONT_FAMILY,
1049 TT_NAME_ID_MAC_FULL_NAME,
1050 TT_NAME_ID_FULL_NAME,
1051 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1052 TT_NAME_ID_WWS_SUBFAMILY,
1054 TT_NAME_ID_PREFERRED_SUBFAMILY,
1055 TT_NAME_ID_FONT_SUBFAMILY,
1056 TT_NAME_ID_TRADEMARK,
1057 TT_NAME_ID_MANUFACTURER,
1060 #define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0]))
1062 FcFreeTypeQueryFace (const FT_Face face,
1063 const FcChar8 *file,
1071 FcBool decorative = FcFalse;
1076 FcChar8 *family = 0;
1079 const FcChar8 *foundry = 0;
1082 #if HAVE_FT_GET_PS_FONT_INFO
1083 PS_FontInfoRec psfontinfo;
1085 #if HAVE_FT_GET_BDF_PROPERTY
1086 BDF_PropertyRec prop;
1089 const FcChar8 *exclusiveLang = 0;
1091 FT_UInt snamei, snamec;
1094 int nfamily_lang = 0;
1096 int nstyle_lang = 0;
1098 int nfullname_lang = 0;
1100 int platform, nameid;
1109 pat = FcPatternCreate ();
1113 if (!FcPatternAddBool (pat, FC_OUTLINE,
1114 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1117 if (!FcPatternAddBool (pat, FC_SCALABLE,
1118 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1123 * Get the OS/2 table
1125 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1128 * Look first in the OS/2 table for the foundry, if
1129 * not found here, the various notices will be searched for
1130 * that information, either from the sfnt name tables or
1131 * the Postscript FontInfo dictionary. Finally, the
1132 * BDF properties will queried.
1135 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1136 foundry = FcVendorFoundry(os2->achVendID);
1138 if (FcDebug () & FC_DBG_SCANV)
1141 * Grub through the name table looking for family
1142 * and style names. FreeType makes quite a hash
1145 snamec = FT_Get_Sfnt_Name_Count (face);
1146 for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
1148 if (p < NUM_PLATFORM_ORDER)
1149 platform = platform_order[p];
1154 * Order nameids so preferred names appear first
1155 * in the resulting list
1157 for (n = 0; n < NUM_NAMEID_ORDER; n++)
1159 nameid = nameid_order[n];
1161 for (snamei = 0; snamei < snamec; snamei++)
1164 const FcChar8 *lang;
1165 const char *elt = 0, *eltlang = 0;
1166 int *np = 0, *nlangp = 0;
1169 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1171 if (sname.name_id != nameid)
1175 * Sort platforms in preference order, accepting
1176 * all other platforms last
1178 if (p < NUM_PLATFORM_ORDER)
1180 if (sname.platform_id != platform)
1187 for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1188 if (sname.platform_id == platform_order[sp])
1190 if (sp != NUM_PLATFORM_ORDER)
1193 utf8 = FcSfntNameTranscode (&sname);
1194 lang = FcSfntNameLanguage (&sname);
1199 switch (sname.name_id) {
1200 #ifdef TT_NAME_ID_WWS_FAMILY
1201 case TT_NAME_ID_WWS_FAMILY:
1203 case TT_NAME_ID_PREFERRED_FAMILY:
1204 case TT_NAME_ID_FONT_FAMILY:
1206 case TT_NAME_ID_UNIQUE_ID:
1208 if (FcDebug () & FC_DBG_SCANV)
1209 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1210 sname.name_id, sname.platform_id,
1211 sname.encoding_id, sname.language_id,
1215 eltlang = FC_FAMILYLANG;
1217 nlangp = &nfamily_lang;
1219 case TT_NAME_ID_MAC_FULL_NAME:
1220 case TT_NAME_ID_FULL_NAME:
1221 if (FcDebug () & FC_DBG_SCANV)
1222 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
1223 sname.name_id, sname.platform_id,
1224 sname.encoding_id, sname.language_id,
1228 eltlang = FC_FULLNAMELANG;
1230 nlangp = &nfullname_lang;
1232 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1233 case TT_NAME_ID_WWS_SUBFAMILY:
1235 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1236 case TT_NAME_ID_FONT_SUBFAMILY:
1242 len = strlen ((const char *) pp);
1243 memmove (utf8, pp, len + 1);
1244 pp = utf8 + len - 1;
1249 if (FcDebug () & FC_DBG_SCANV)
1250 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1251 sname.name_id, sname.platform_id,
1252 sname.encoding_id, sname.language_id,
1256 eltlang = FC_STYLELANG;
1258 nlangp = &nstyle_lang;
1260 case TT_NAME_ID_TRADEMARK:
1261 case TT_NAME_ID_MANUFACTURER:
1262 /* If the foundry wasn't found in the OS/2 table, look here */
1264 foundry = FcNoticeFoundry((FT_String *) utf8);
1269 if (FcStringInPatternElement (pat, elt, utf8))
1275 /* add new element */
1276 if (!FcPatternAddString (pat, elt, utf8))
1284 /* pad lang list with 'xx' to line up with elt */
1285 while (*nlangp < *np)
1287 if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
1291 if (!FcPatternAddString (pat, eltlang, lang))
1303 if (!nfamily && face->family_name &&
1304 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1306 if (FcDebug () & FC_DBG_SCANV)
1307 printf ("using FreeType family \"%s\"\n", face->family_name);
1308 if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1313 if (!nstyle && face->style_name &&
1314 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1316 if (FcDebug () & FC_DBG_SCANV)
1317 printf ("using FreeType style \"%s\"\n", face->style_name);
1318 if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1325 FcChar8 *start, *end;
1328 start = (FcChar8 *) strrchr ((char *) file, '/');
1332 start = (FcChar8 *) file;
1333 end = (FcChar8 *) strrchr ((char *) start, '.');
1335 end = start + strlen ((char *) start);
1337 family = malloc (end - start + 1);
1338 strncpy ((char *) family, (char *) start, end - start);
1339 family[end - start] = '\0';
1340 if (FcDebug () & FC_DBG_SCANV)
1341 printf ("using filename for family %s\n", family);
1342 if (!FcPatternAddString (pat, FC_FAMILY, family))
1351 /* Add the PostScript name into the cache */
1352 tmp = FT_Get_Postscript_Name (face);
1355 FcChar8 *family, *familylang = NULL;
1359 /* Workaround when FT_Get_Postscript_Name didn't give any name.
1360 * try to find out the English family name and convert.
1362 while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch)
1364 if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0)
1372 if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
1374 len = strlen ((const char *)family);
1375 /* the literal name in PostScript Language is limited to 127 characters though,
1376 * It is the architectural limit. so assuming 255 characters may works enough.
1378 for (i = 0; i < len && i < 255; i++)
1380 /* those characters are not allowed to be the literal name in PostScript */
1381 static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n ";
1383 if (strchr(exclusive_chars, family[i]) != NULL)
1386 psname[i] = family[i];
1392 strcpy (psname, tmp);
1394 if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname))
1397 if (!FcPatternAddString (pat, FC_FILE, file))
1400 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1405 * don't even try this -- CJK 'monospace' fonts are really
1406 * dual width, and most other fonts don't bother to set
1407 * the attribute. Sigh.
1409 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1410 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1415 * Find the font revision (if available)
1417 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1420 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1425 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1429 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1431 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1435 if (FcCodePageRange[i].bit < 32)
1437 bits = os2->ulCodePageRange1;
1438 bit = FcCodePageRange[i].bit;
1442 bits = os2->ulCodePageRange2;
1443 bit = FcCodePageRange[i].bit - 32;
1445 if (bits & (1 << bit))
1448 * If the font advertises support for multiple
1449 * "exclusive" languages, then include support
1450 * for any language found to have coverage
1457 exclusiveLang = FcCodePageRange[i].lang;
1462 if (os2 && os2->version != 0xffff)
1464 if (os2->usWeightClass == 0)
1466 else if (os2->usWeightClass < 150)
1467 weight = FC_WEIGHT_THIN;
1468 else if (os2->usWeightClass < 250)
1469 weight = FC_WEIGHT_EXTRALIGHT;
1470 else if (os2->usWeightClass < 350)
1471 weight = FC_WEIGHT_LIGHT;
1472 else if (os2->usWeightClass < 450)
1473 weight = FC_WEIGHT_REGULAR;
1474 else if (os2->usWeightClass < 550)
1475 weight = FC_WEIGHT_MEDIUM;
1476 else if (os2->usWeightClass < 650)
1477 weight = FC_WEIGHT_SEMIBOLD;
1478 else if (os2->usWeightClass < 750)
1479 weight = FC_WEIGHT_BOLD;
1480 else if (os2->usWeightClass < 850)
1481 weight = FC_WEIGHT_EXTRABOLD;
1482 else if (os2->usWeightClass < 925)
1483 weight = FC_WEIGHT_BLACK;
1484 else if (os2->usWeightClass < 1000)
1485 weight = FC_WEIGHT_EXTRABLACK;
1486 if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1487 printf ("\tos2 weight class %d maps to weight %d\n",
1488 os2->usWeightClass, weight);
1490 switch (os2->usWidthClass) {
1491 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1492 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1493 case 3: width = FC_WIDTH_CONDENSED; break;
1494 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1495 case 5: width = FC_WIDTH_NORMAL; break;
1496 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1497 case 7: width = FC_WIDTH_EXPANDED; break;
1498 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1499 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1501 if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1502 printf ("\tos2 width class %d maps to width %d\n",
1503 os2->usWidthClass, width);
1505 if (os2 && (complex_ = FcFontCapabilities(face)))
1507 if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
1516 * Type 1: Check for FontInfo dictionary information
1517 * Code from g2@magestudios.net (Gerard Escalante)
1520 #if HAVE_FT_GET_PS_FONT_INFO
1521 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1523 if (weight == -1 && psfontinfo.weight)
1525 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1526 if (FcDebug() & FC_DBG_SCANV)
1527 printf ("\tType1 weight %s maps to %d\n",
1528 psfontinfo.weight, weight);
1533 * Don't bother with italic_angle; FreeType already extracts that
1534 * information for us and sticks it into style_flags
1536 if (psfontinfo.italic_angle)
1537 slant = FC_SLANT_ITALIC;
1539 slant = FC_SLANT_ROMAN;
1543 foundry = FcNoticeFoundry(psfontinfo.notice);
1545 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1547 #if HAVE_FT_GET_BDF_PROPERTY
1549 * Finally, look for a FOUNDRY BDF property if no other
1550 * mechanism has managed to locate a foundry
1556 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1557 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1558 foundry = (FcChar8 *) prop.u.atom;
1563 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1564 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1565 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1569 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1570 value = prop.u.integer;
1572 value = (FT_Int32) prop.u.cardinal;
1573 switch ((value + 5) / 10) {
1574 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1575 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1576 case 3: width = FC_WIDTH_CONDENSED; break;
1577 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1578 case 5: width = FC_WIDTH_NORMAL; break;
1579 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1580 case 7: width = FC_WIDTH_EXPANDED; break;
1581 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1582 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1586 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1587 prop.type == BDF_PROPERTY_TYPE_ATOM)
1589 width = FcIsWidth ((FcChar8 *) prop.u.atom);
1590 if (FcDebug () & FC_DBG_SCANV)
1591 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1597 * Look for weight, width and slant names in the style value
1599 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1603 weight = FcContainsWeight (style);
1604 if (FcDebug() & FC_DBG_SCANV)
1605 printf ("\tStyle %s maps to weight %d\n", style, weight);
1609 width = FcContainsWidth (style);
1610 if (FcDebug() & FC_DBG_SCANV)
1611 printf ("\tStyle %s maps to width %d\n", style, width);
1615 slant = FcContainsSlant (style);
1616 if (FcDebug() & FC_DBG_SCANV)
1617 printf ("\tStyle %s maps to slant %d\n", style, slant);
1619 if (decorative == FcFalse)
1621 decorative = FcContainsDecorative (style) > 0;
1622 if (FcDebug() & FC_DBG_SCANV)
1623 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1627 * Pull default values from the FreeType flags if more
1628 * specific values not found above
1632 slant = FC_SLANT_ROMAN;
1633 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1634 slant = FC_SLANT_ITALIC;
1639 weight = FC_WEIGHT_MEDIUM;
1640 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1641 weight = FC_WEIGHT_BOLD;
1645 width = FC_WIDTH_NORMAL;
1648 foundry = (FcChar8 *) "unknown";
1650 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1653 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1656 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1659 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1662 if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1665 hashstr = FcHashGetSHA256DigestFromFace (face);
1668 if (!FcPatternAddString (pat, FC_HASH, hashstr))
1673 * Compute the unicode coverage for the font
1675 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1679 #if HAVE_FT_GET_BDF_PROPERTY
1680 /* For PCF fonts, override the computed spacing with the one from
1682 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1683 prop.type == BDF_PROPERTY_TYPE_ATOM) {
1684 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1685 spacing = FC_CHARCELL;
1686 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1688 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1689 spacing = FC_PROPORTIONAL;
1694 * Skip over PCF fonts that have no encoded characters; they're
1695 * usually just Unicode fonts transcoded to some legacy encoding
1696 * FT forces us to approximate whether a font is a PCF font
1697 * or not by whether it has any BDF properties. Try PIXEL_SIZE;
1698 * I don't know how to get a list of BDF properties on the font. -PL
1700 if (FcCharSetCount (cs) == 0)
1702 #if HAVE_FT_GET_BDF_PROPERTY
1703 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1708 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1711 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1715 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1717 FcLangSetDestroy (ls);
1721 FcLangSetDestroy (ls);
1723 if (spacing != FC_PROPORTIONAL)
1724 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1727 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1729 for (i = 0; i < face->num_fixed_sizes; i++)
1730 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1731 FcGetPixelSize (face, i)))
1733 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1736 #if HAVE_FT_GET_X11_FONT_FORMAT
1738 * Use the (not well documented or supported) X-specific function
1739 * from FreeType to figure out the font format
1742 const char *font_format = FT_Get_X11_Font_Format (face);
1744 if (!FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format))
1750 * Drop our reference to the charset
1752 FcCharSetDestroy (cs);
1757 FcCharSetDestroy (cs);
1759 FcPatternDestroy (pat);
1765 FcFreeTypeQuery(const FcChar8 *file,
1771 FT_Library ftLibrary;
1772 FcPattern *pat = NULL;
1774 if (FT_Init_FreeType (&ftLibrary))
1777 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1780 *count = face->num_faces;
1782 pat = FcFreeTypeQueryFace (face, file, id, blanks);
1784 FT_Done_Face (face);
1786 FT_Done_FreeType (ftLibrary);
1791 * For our purposes, this approximation is sufficient
1793 #if !HAVE_FT_GET_NEXT_CHAR
1794 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1796 (*(gi) = 1), (ucs4) + 1)
1797 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1800 typedef struct _FcCharEnt {
1802 unsigned char encode;
1806 const FcCharEnt *ent;
1810 typedef struct _FcFontDecode {
1811 FT_Encoding encoding;
1812 const FcCharMap *map;
1816 static const FcCharEnt AdobeSymbolEnt[] = {
1817 { 0x0020, 0x20 }, /* SPACE # space */
1818 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
1819 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
1820 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
1821 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
1822 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
1823 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
1824 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
1825 { 0x002C, 0x2C }, /* COMMA # comma */
1826 { 0x002E, 0x2E }, /* FULL STOP # period */
1827 { 0x002F, 0x2F }, /* SOLIDUS # slash */
1828 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
1829 { 0x0031, 0x31 }, /* DIGIT ONE # one */
1830 { 0x0032, 0x32 }, /* DIGIT TWO # two */
1831 { 0x0033, 0x33 }, /* DIGIT THREE # three */
1832 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
1833 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
1834 { 0x0036, 0x36 }, /* DIGIT SIX # six */
1835 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
1836 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
1837 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
1838 { 0x003A, 0x3A }, /* COLON # colon */
1839 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
1840 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1841 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
1842 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
1843 { 0x003F, 0x3F }, /* QUESTION MARK # question */
1844 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
1845 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
1846 { 0x005F, 0x5F }, /* LOW LINE # underscore */
1847 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
1848 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
1849 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
1850 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1851 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
1852 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
1853 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
1854 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
1855 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
1856 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
1857 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1858 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
1859 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
1860 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
1861 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
1862 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
1863 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
1864 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
1865 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
1866 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
1867 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
1868 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
1869 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
1870 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
1871 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
1872 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
1873 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
1874 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
1875 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
1876 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
1877 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
1878 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
1879 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
1880 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
1881 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
1882 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
1883 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
1884 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
1885 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
1886 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
1887 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
1888 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1889 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
1890 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
1891 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
1892 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
1893 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
1894 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
1895 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
1896 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
1897 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
1898 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1899 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1900 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
1901 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
1902 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
1903 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
1904 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
1905 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
1906 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
1907 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
1908 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
1909 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
1910 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
1911 { 0x2022, 0xB7 }, /* BULLET # bullet */
1912 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
1913 { 0x2032, 0xA2 }, /* PRIME # minute */
1914 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
1915 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
1916 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
1917 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
1918 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
1919 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
1920 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
1921 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
1922 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
1923 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
1924 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
1925 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
1926 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
1927 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
1928 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
1929 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
1930 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
1931 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
1932 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
1933 { 0x2200, 0x22 }, /* FOR ALL # universal */
1934 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
1935 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
1936 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
1937 { 0x2206, 0x44 }, /* INCREMENT # Delta */
1938 { 0x2207, 0xD1 }, /* NABLA # gradient */
1939 { 0x2208, 0xCE }, /* ELEMENT OF # element */
1940 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
1941 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
1942 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
1943 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
1944 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
1945 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
1946 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
1947 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
1948 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
1949 { 0x221E, 0xA5 }, /* INFINITY # infinity */
1950 { 0x2220, 0xD0 }, /* ANGLE # angle */
1951 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
1952 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
1953 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
1954 { 0x222A, 0xC8 }, /* UNION # union */
1955 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
1956 { 0x2234, 0x5C }, /* THEREFORE # therefore */
1957 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
1958 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
1959 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
1960 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
1961 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
1962 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
1963 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
1964 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
1965 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
1966 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
1967 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
1968 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
1969 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
1970 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
1971 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
1972 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
1973 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
1974 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
1975 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
1976 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
1977 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
1978 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
1979 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
1980 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
1981 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
1982 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
1983 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
1984 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
1985 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
1986 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
1987 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
1988 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
1989 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
1990 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
1991 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
1992 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
1993 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
1994 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
1995 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
1996 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
1997 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
1998 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
1999 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
2000 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2001 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
2002 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
2003 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
2004 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
2005 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
2006 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
2007 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
2008 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
2009 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
2010 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
2013 static const FcCharMap AdobeSymbol = {
2015 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2018 static const FcFontDecode fcFontDecoders[] = {
2019 { ft_encoding_unicode, 0, (1 << 21) - 1 },
2020 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
2023 #define NUM_DECODE (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
2025 static const FcChar32 prefer_unicode[] = {
2026 0x20ac, /* EURO SIGN */
2029 #define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
2032 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2038 high = map->nent - 1;
2039 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2043 mid = (high + low) >> 1;
2044 bmp = map->ent[mid].bmp;
2046 return (FT_ULong) map->ent[mid].encode;
2056 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2060 for (i = 0; i < map->nent; i++)
2061 if (map->ent[i].encode == private)
2062 return (FcChar32) map->ent[i].bmp;
2067 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2071 for (i = 0; i < NUM_DECODE; i++)
2072 if (fcFontDecoders[i].encoding == encoding)
2073 return fcFontDecoders[i].map;
2077 #include "../fc-glyphname/fcglyphname.h"
2080 FcHashGlyphName (const FcChar8 *name)
2085 while ((c = *name++))
2087 h = ((h << 1) | (h >> 31)) ^ c;
2092 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2094 * Use Type1 glyph names for fonts which have reliable names
2095 * and which export an Adobe Custom mapping
2098 FcFreeTypeUseNames (FT_Face face)
2102 if (!FT_Has_PS_Glyph_Names (face))
2104 for (map = 0; map < face->num_charmaps; map++)
2105 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2110 static const FcChar8 *
2111 FcUcs4ToGlyphName (FcChar32 ucs4)
2113 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2117 while ((gn = _fc_ucs_to_name[i]) != -1)
2119 if (_fc_glyph_names[gn].ucs == ucs4)
2120 return _fc_glyph_names[gn].name;
2123 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2128 if (i >= FC_GLYPHNAME_HASH)
2129 i -= FC_GLYPHNAME_HASH;
2135 FcGlyphNameToUcs4 (FcChar8 *name)
2137 FcChar32 h = FcHashGlyphName (name);
2138 int i = (int) (h % FC_GLYPHNAME_HASH);
2142 while ((gn = _fc_name_to_ucs[i]) != -1)
2144 if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name))
2145 return _fc_glyph_names[gn].ucs;
2148 r = (int) (h % FC_GLYPHNAME_REHASH);
2153 if (i >= FC_GLYPHNAME_HASH)
2154 i -= FC_GLYPHNAME_HASH;
2160 * Work around a bug in some FreeType versions which fail
2161 * to correctly bounds check glyph name buffers and overwrite
2162 * the stack. As Postscript names have a limit of 127 characters,
2163 * this should be sufficient.
2166 #if FC_GLYPHNAME_MAXLEN < 127
2167 # define FC_GLYPHNAME_BUFLEN 127
2169 # define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2173 * Search through a font for a glyph by name. This is
2174 * currently a linear search as there doesn't appear to be
2175 * any defined order within the font
2178 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2181 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2183 for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2185 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2186 if (!strcmp ((char *) name, (char *) name_buf))
2194 * Map a UCS4 glyph to a glyph index. Use all available encoding
2195 * tables to try and find one that works. This information is expected
2196 * to be cached by higher levels, so performance isn't critical
2200 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2202 int initial, offset, decode;
2213 * Find the current encoding
2217 for (; initial < NUM_DECODE; initial++)
2218 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2220 if (initial == NUM_DECODE)
2223 for (p = 0; p < NUM_PREFER_UNICODE; p++)
2224 if (ucs4 == prefer_unicode[p])
2230 * Check each encoding for the glyph, starting with the current one
2232 for (offset = 0; offset < NUM_DECODE; offset++)
2234 decode = (initial + offset) % NUM_DECODE;
2235 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2236 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2238 if (fcFontDecoders[decode].map)
2240 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2241 if (charcode == ~0U)
2246 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2250 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2252 * Check postscript name table if present
2254 if (FcFreeTypeUseNames (face))
2256 const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
2259 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2269 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2270 FT_UInt glyph, FcBlanks *blanks,
2272 FcBool using_strike)
2274 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2278 load_flags &= ~FT_LOAD_NO_SCALE;
2281 * When using scalable fonts, only report those glyphs
2282 * which can be scaled; otherwise those fonts will
2283 * only be available at some sizes, and never when
2284 * transformed. Avoid this by simply reporting bitmap-only
2287 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2288 load_flags |= FT_LOAD_NO_BITMAP;
2290 if (FT_Load_Glyph (face, glyph, load_flags))
2297 *advance = slot->metrics.horiAdvance;
2299 switch ((int) slot->format) {
2300 case ft_glyph_format_bitmap:
2302 * Bitmaps are assumed to be reasonable; if
2303 * this proves to be a rash assumption, this
2304 * code can be easily modified
2307 case ft_glyph_format_outline:
2309 * Glyphs with contours are always OK
2311 if (slot->outline.n_contours != 0)
2314 * Glyphs with no contours are only OK if
2315 * they're members of the Blanks set specified
2316 * in the configuration. If blanks isn't set,
2317 * then allow any glyph to be blank
2319 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2321 /* fall through ... */
2328 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2331 FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index)
2333 FcChar32 page, off, ucs4;
2335 FcChar32 font_max = 0;
2339 const FcCharMap *map;
2343 FT_Pos advance, advance_one = 0, advance_two = 0;
2344 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2345 FcBool using_strike = FcFalse;
2347 fcs = FcCharSetCreate ();
2351 #if HAVE_FT_SELECT_SIZE
2352 if (strike_index >= 0) {
2353 if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
2355 using_strike = FcTrue;
2360 printf ("Family %s style %s\n", face->family_name, face->style_name);
2362 for (o = 0; o < NUM_DECODE; o++)
2364 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2366 map = fcFontDecoders[o].map;
2370 * Non-Unicode tables are easy; there's a list of all possible
2373 for (i = 0; i < map->nent; i++)
2375 ucs4 = map->ent[i].bmp;
2376 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2378 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2381 * ignore glyphs with zero advance. They’re
2382 * combining characters, and while their behaviour
2383 * isn’t well defined for monospaced applications in
2384 * Unicode, there are many fonts which include
2385 * zero-width combining characters in otherwise
2392 has_advance = FcTrue;
2393 advance_one = advance;
2395 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2399 dual_advance = FcTrue;
2400 fixed_advance = FcFalse;
2401 advance_two = advance;
2403 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2404 dual_advance = FcFalse;
2408 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2411 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2413 if (ucs4 > font_max)
2423 ucs4 = FT_Get_First_Char (face, &glyph);
2426 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2432 has_advance = FcTrue;
2433 advance_one = advance;
2435 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2439 dual_advance = FcTrue;
2440 fixed_advance = FcFalse;
2441 advance_two = advance;
2443 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2444 dual_advance = FcFalse;
2448 if ((ucs4 >> 8) != page)
2451 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2456 leaf->map[off >> 5] |= (1 << (off & 0x1f));
2458 if (ucs4 > font_max)
2462 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2465 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2467 FcBool FT_Has, FC_Has;
2469 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2470 FC_Has = FcCharSetHasChar (fcs, ucs4);
2471 if (FT_Has != FC_Has)
2473 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2479 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2481 * Add mapping from PS glyph names if available
2483 if (FcFreeTypeUseNames (face))
2485 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2487 for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2489 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2491 ucs4 = FcGlyphNameToUcs4 (name_buf);
2492 if (ucs4 != 0xffff &&
2493 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2499 has_advance = FcTrue;
2500 advance_one = advance;
2502 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2506 dual_advance = FcTrue;
2507 fixed_advance = FcFalse;
2508 advance_two = advance;
2510 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2511 dual_advance = FcFalse;
2514 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2517 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2519 if (ucs4 > font_max)
2528 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2529 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2531 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2532 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2534 if (has_char && !has_bit)
2536 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2537 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2539 printf ("Bitmap missing char 0x%x\n", ucs4);
2541 else if (!has_char && has_bit)
2542 printf ("Bitmap extra char 0x%x\n", ucs4);
2547 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2550 *spacing = FC_PROPORTIONAL;
2553 FcCharSetDestroy (fcs);
2559 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2564 * Check for bitmap-only ttf fonts that are missing the glyf table.
2565 * In that case, pick a size and look for glyphs in that size instead
2567 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
2568 face->num_fixed_sizes > 0 &&
2569 FT_Get_Sfnt_Table (face, ft_sfnt_head))
2571 FT_Int strike_index = 0;
2574 /* Select the face closest to 16 pixels tall */
2575 for (i = 1; i < face->num_fixed_sizes; i++) {
2576 if (abs (face->available_sizes[i].height - 16) <
2577 abs (face->available_sizes[strike_index].height - 16))
2580 cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index);
2583 cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1);
2588 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2592 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2596 #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2597 #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2598 #define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2600 #define OTLAYOUT_HEAD "otlayout:"
2601 #define OTLAYOUT_HEAD_LEN 9
2602 #define OTLAYOUT_ID_LEN 4
2603 /* space + head + id */
2604 #define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2607 * This is a bit generous; the registry has only lower case and space
2608 * except for 'DFLT'.
2610 #define FcIsSpace(x) (040 == (x))
2611 #define FcIsDigit(c) (('0' <= (c) && (c) <= '9'))
2612 #define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(x) || FcIsSpace(x))
2615 addtag(FcChar8 *complex_, FT_ULong tag)
2617 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2619 tagstring[0] = (FcChar8)(tag >> 24),
2620 tagstring[1] = (FcChar8)(tag >> 16),
2621 tagstring[2] = (FcChar8)(tag >> 8),
2622 tagstring[3] = (FcChar8)(tag);
2623 tagstring[4] = '\0';
2625 /* skip tags which aren't alphanumeric, under the assumption that
2626 * they're probably broken
2628 if (!FcIsValidScript(tagstring[0]) ||
2629 !FcIsValidScript(tagstring[1]) ||
2630 !FcIsValidScript(tagstring[2]) ||
2631 !FcIsValidScript(tagstring[3]))
2634 if (*complex_ != '\0')
2635 strcat ((char *) complex_, " ");
2636 strcat ((char *) complex_, OTLAYOUT_HEAD);
2637 strcat ((char *) complex_, (char *) tagstring);
2641 compareulong (const void *a, const void *b)
2643 const FT_ULong *ua = (const FT_ULong *) a;
2644 const FT_ULong *ub = (const FT_ULong *) b;
2650 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
2652 FT_ULong cur_offset, new_offset, base_offset;
2653 FT_Stream stream = face->stream;
2661 if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2664 base_offset = ftglue_stream_pos ( stream );
2668 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2671 new_offset = GET_UShort() + base_offset;
2673 ftglue_stream_frame_exit( stream );
2675 cur_offset = ftglue_stream_pos( stream );
2677 if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
2680 base_offset = ftglue_stream_pos( stream );
2682 if ( ftglue_stream_frame_enter( stream, 2L ) )
2685 script_count = GET_UShort ();
2687 ftglue_stream_frame_exit( stream );
2689 *stags = malloc(script_count * sizeof (FT_ULong));
2694 for ( n = 0; n < script_count; n++ )
2696 if ( ftglue_stream_frame_enter( stream, 6L ) )
2699 (*stags)[p] = GET_ULong ();
2700 new_offset = GET_UShort () + base_offset;
2702 ftglue_stream_frame_exit( stream );
2704 cur_offset = ftglue_stream_pos( stream );
2706 error = ftglue_stream_seek( stream, new_offset );
2708 if ( error == FT_Err_Ok )
2711 (void)ftglue_stream_seek( stream, cur_offset );
2717 /* sort the tag list before returning it */
2718 qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
2720 return script_count;
2729 FcFontCapabilities(FT_Face face)
2731 FcBool issilgraphitefont = 0;
2734 FT_ULong *gsubtags=NULL, *gpostags=NULL;
2735 FT_UShort gsub_count=0, gpos_count=0;
2737 FcChar8 *complex_ = NULL;
2738 int indx1 = 0, indx2 = 0;
2740 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2741 issilgraphitefont = ( err == FT_Err_Ok);
2743 gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
2744 gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
2746 if (!issilgraphitefont && !gsub_count && !gpos_count)
2749 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2750 (issilgraphitefont ? 13 : 0));
2751 complex_ = malloc (sizeof (FcChar8) * maxsize);
2756 if (issilgraphitefont)
2757 strcpy((char *) complex_, "ttable:Silf ");
2759 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2760 if (indx1 == gsub_count) {
2761 addtag(complex_, gpostags[indx2]);
2763 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2764 addtag(complex_, gsubtags[indx1]);
2766 } else if (gsubtags[indx1] == gpostags[indx2]) {
2767 addtag(complex_, gsubtags[indx1]);
2771 addtag(complex_, gpostags[indx2]);
2775 if (FcDebug () & FC_DBG_SCANV)
2776 printf("complex_ features in this font: %s\n", complex_);
2783 #define __fcfreetype__
2784 #include "fcaliastail.h"
2785 #include "fcftaliastail.h"
2786 #undef __fcfreetype__