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;
1107 FcChar8 *hashstr = NULL;
1109 FT_ULong len = 0, alen;
1111 pat = FcPatternCreate ();
1115 if (!FcPatternAddBool (pat, FC_OUTLINE,
1116 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1119 if (!FcPatternAddBool (pat, FC_SCALABLE,
1120 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1125 * Get the OS/2 table
1127 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1130 * Look first in the OS/2 table for the foundry, if
1131 * not found here, the various notices will be searched for
1132 * that information, either from the sfnt name tables or
1133 * the Postscript FontInfo dictionary. Finally, the
1134 * BDF properties will queried.
1137 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1138 foundry = FcVendorFoundry(os2->achVendID);
1140 if (FcDebug () & FC_DBG_SCANV)
1143 * Grub through the name table looking for family
1144 * and style names. FreeType makes quite a hash
1147 snamec = FT_Get_Sfnt_Name_Count (face);
1148 for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
1150 if (p < NUM_PLATFORM_ORDER)
1151 platform = platform_order[p];
1156 * Order nameids so preferred names appear first
1157 * in the resulting list
1159 for (n = 0; n < NUM_NAMEID_ORDER; n++)
1161 nameid = nameid_order[n];
1163 for (snamei = 0; snamei < snamec; snamei++)
1166 const FcChar8 *lang;
1167 const char *elt = 0, *eltlang = 0;
1168 int *np = 0, *nlangp = 0;
1171 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1173 if (sname.name_id != nameid)
1177 * Sort platforms in preference order, accepting
1178 * all other platforms last
1180 if (p < NUM_PLATFORM_ORDER)
1182 if (sname.platform_id != platform)
1189 for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1190 if (sname.platform_id == platform_order[sp])
1192 if (sp != NUM_PLATFORM_ORDER)
1195 utf8 = FcSfntNameTranscode (&sname);
1196 lang = FcSfntNameLanguage (&sname);
1201 switch (sname.name_id) {
1202 #ifdef TT_NAME_ID_WWS_FAMILY
1203 case TT_NAME_ID_WWS_FAMILY:
1205 case TT_NAME_ID_PREFERRED_FAMILY:
1206 case TT_NAME_ID_FONT_FAMILY:
1208 case TT_NAME_ID_UNIQUE_ID:
1210 if (FcDebug () & FC_DBG_SCANV)
1211 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1212 sname.name_id, sname.platform_id,
1213 sname.encoding_id, sname.language_id,
1217 eltlang = FC_FAMILYLANG;
1219 nlangp = &nfamily_lang;
1221 case TT_NAME_ID_MAC_FULL_NAME:
1222 case TT_NAME_ID_FULL_NAME:
1223 if (FcDebug () & FC_DBG_SCANV)
1224 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
1225 sname.name_id, sname.platform_id,
1226 sname.encoding_id, sname.language_id,
1230 eltlang = FC_FULLNAMELANG;
1232 nlangp = &nfullname_lang;
1234 #ifdef TT_NAME_ID_WWS_SUBFAMILY
1235 case TT_NAME_ID_WWS_SUBFAMILY:
1237 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1238 case TT_NAME_ID_FONT_SUBFAMILY:
1244 len = strlen ((const char *) pp);
1245 memmove (utf8, pp, len + 1);
1246 pp = utf8 + len - 1;
1251 if (FcDebug () & FC_DBG_SCANV)
1252 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1253 sname.name_id, sname.platform_id,
1254 sname.encoding_id, sname.language_id,
1258 eltlang = FC_STYLELANG;
1260 nlangp = &nstyle_lang;
1262 case TT_NAME_ID_TRADEMARK:
1263 case TT_NAME_ID_MANUFACTURER:
1264 /* If the foundry wasn't found in the OS/2 table, look here */
1266 foundry = FcNoticeFoundry((FT_String *) utf8);
1271 if (FcStringInPatternElement (pat, elt, utf8))
1277 /* add new element */
1278 if (!FcPatternAddString (pat, elt, utf8))
1286 /* pad lang list with 'xx' to line up with elt */
1287 while (*nlangp < *np)
1289 if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
1293 if (!FcPatternAddString (pat, eltlang, lang))
1305 if (!nfamily && face->family_name &&
1306 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1308 if (FcDebug () & FC_DBG_SCANV)
1309 printf ("using FreeType family \"%s\"\n", face->family_name);
1310 if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1315 if (!nstyle && face->style_name &&
1316 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1318 if (FcDebug () & FC_DBG_SCANV)
1319 printf ("using FreeType style \"%s\"\n", face->style_name);
1320 if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1327 FcChar8 *start, *end;
1330 start = (FcChar8 *) strrchr ((char *) file, '/');
1334 start = (FcChar8 *) file;
1335 end = (FcChar8 *) strrchr ((char *) start, '.');
1337 end = start + strlen ((char *) start);
1339 family = malloc (end - start + 1);
1340 strncpy ((char *) family, (char *) start, end - start);
1341 family[end - start] = '\0';
1342 if (FcDebug () & FC_DBG_SCANV)
1343 printf ("using filename for family %s\n", family);
1344 if (!FcPatternAddString (pat, FC_FAMILY, family))
1353 /* Add the PostScript name into the cache */
1354 tmp = FT_Get_Postscript_Name (face);
1357 FcChar8 *family, *familylang = NULL;
1361 /* Workaround when FT_Get_Postscript_Name didn't give any name.
1362 * try to find out the English family name and convert.
1364 while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch)
1366 if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0)
1374 if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
1376 len = strlen ((const char *)family);
1377 /* the literal name in PostScript Language is limited to 127 characters though,
1378 * It is the architectural limit. so assuming 255 characters may works enough.
1380 for (i = 0; i < len && i < 255; i++)
1382 /* those characters are not allowed to be the literal name in PostScript */
1383 static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n ";
1385 if (strchr(exclusive_chars, family[i]) != NULL)
1388 psname[i] = family[i];
1394 strcpy (psname, tmp);
1396 if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname))
1399 if (!FcPatternAddString (pat, FC_FILE, file))
1402 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1407 * don't even try this -- CJK 'monospace' fonts are really
1408 * dual width, and most other fonts don't bother to set
1409 * the attribute. Sigh.
1411 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1412 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1417 * Find the font revision (if available)
1419 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1422 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1427 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1431 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1433 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1437 if (FcCodePageRange[i].bit < 32)
1439 bits = os2->ulCodePageRange1;
1440 bit = FcCodePageRange[i].bit;
1444 bits = os2->ulCodePageRange2;
1445 bit = FcCodePageRange[i].bit - 32;
1447 if (bits & (1 << bit))
1450 * If the font advertises support for multiple
1451 * "exclusive" languages, then include support
1452 * for any language found to have coverage
1459 exclusiveLang = FcCodePageRange[i].lang;
1464 if (os2 && os2->version != 0xffff)
1466 if (os2->usWeightClass == 0)
1468 else if (os2->usWeightClass < 150)
1469 weight = FC_WEIGHT_THIN;
1470 else if (os2->usWeightClass < 250)
1471 weight = FC_WEIGHT_EXTRALIGHT;
1472 else if (os2->usWeightClass < 350)
1473 weight = FC_WEIGHT_LIGHT;
1474 else if (os2->usWeightClass < 450)
1475 weight = FC_WEIGHT_REGULAR;
1476 else if (os2->usWeightClass < 550)
1477 weight = FC_WEIGHT_MEDIUM;
1478 else if (os2->usWeightClass < 650)
1479 weight = FC_WEIGHT_SEMIBOLD;
1480 else if (os2->usWeightClass < 750)
1481 weight = FC_WEIGHT_BOLD;
1482 else if (os2->usWeightClass < 850)
1483 weight = FC_WEIGHT_EXTRABOLD;
1484 else if (os2->usWeightClass < 925)
1485 weight = FC_WEIGHT_BLACK;
1486 else if (os2->usWeightClass < 1000)
1487 weight = FC_WEIGHT_EXTRABLACK;
1488 if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1489 printf ("\tos2 weight class %d maps to weight %d\n",
1490 os2->usWeightClass, weight);
1492 switch (os2->usWidthClass) {
1493 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1494 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1495 case 3: width = FC_WIDTH_CONDENSED; break;
1496 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1497 case 5: width = FC_WIDTH_NORMAL; break;
1498 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1499 case 7: width = FC_WIDTH_EXPANDED; break;
1500 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1501 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1503 if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1504 printf ("\tos2 width class %d maps to width %d\n",
1505 os2->usWidthClass, width);
1507 if (os2 && (complex_ = FcFontCapabilities(face)))
1509 if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
1518 * Type 1: Check for FontInfo dictionary information
1519 * Code from g2@magestudios.net (Gerard Escalante)
1522 #if HAVE_FT_GET_PS_FONT_INFO
1523 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1525 if (weight == -1 && psfontinfo.weight)
1527 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1528 if (FcDebug() & FC_DBG_SCANV)
1529 printf ("\tType1 weight %s maps to %d\n",
1530 psfontinfo.weight, weight);
1535 * Don't bother with italic_angle; FreeType already extracts that
1536 * information for us and sticks it into style_flags
1538 if (psfontinfo.italic_angle)
1539 slant = FC_SLANT_ITALIC;
1541 slant = FC_SLANT_ROMAN;
1545 foundry = FcNoticeFoundry(psfontinfo.notice);
1547 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1549 #if HAVE_FT_GET_BDF_PROPERTY
1551 * Finally, look for a FOUNDRY BDF property if no other
1552 * mechanism has managed to locate a foundry
1558 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1559 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1560 foundry = (FcChar8 *) prop.u.atom;
1565 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1566 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1567 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1571 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1572 value = prop.u.integer;
1574 value = (FT_Int32) prop.u.cardinal;
1575 switch ((value + 5) / 10) {
1576 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1577 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1578 case 3: width = FC_WIDTH_CONDENSED; break;
1579 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1580 case 5: width = FC_WIDTH_NORMAL; break;
1581 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1582 case 7: width = FC_WIDTH_EXPANDED; break;
1583 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1584 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1588 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1589 prop.type == BDF_PROPERTY_TYPE_ATOM)
1591 width = FcIsWidth ((FcChar8 *) prop.u.atom);
1592 if (FcDebug () & FC_DBG_SCANV)
1593 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1599 * Look for weight, width and slant names in the style value
1601 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1605 weight = FcContainsWeight (style);
1606 if (FcDebug() & FC_DBG_SCANV)
1607 printf ("\tStyle %s maps to weight %d\n", style, weight);
1611 width = FcContainsWidth (style);
1612 if (FcDebug() & FC_DBG_SCANV)
1613 printf ("\tStyle %s maps to width %d\n", style, width);
1617 slant = FcContainsSlant (style);
1618 if (FcDebug() & FC_DBG_SCANV)
1619 printf ("\tStyle %s maps to slant %d\n", style, slant);
1621 if (decorative == FcFalse)
1623 decorative = FcContainsDecorative (style) > 0;
1624 if (FcDebug() & FC_DBG_SCANV)
1625 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1629 * Pull default values from the FreeType flags if more
1630 * specific values not found above
1634 slant = FC_SLANT_ROMAN;
1635 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1636 slant = FC_SLANT_ITALIC;
1641 weight = FC_WEIGHT_MEDIUM;
1642 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1643 weight = FC_WEIGHT_BOLD;
1647 width = FC_WIDTH_NORMAL;
1650 foundry = (FcChar8 *) "unknown";
1652 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1655 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1658 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1661 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1664 if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1667 err = FT_Load_Sfnt_Table (face, 0, 0, NULL, &len);
1668 if (err == FT_Err_Ok)
1672 alen = (len + 63) & ~63;
1673 fontdata = malloc (alen);
1676 err = FT_Load_Sfnt_Table (face, 0, 0, (FT_Byte *)fontdata, &len);
1677 if (err != FT_Err_Ok)
1682 memset (&fontdata[len], 0, alen - len);
1683 hashstr = FcHashGetSHA256DigestFromMemory (fontdata, len);
1686 else if (err == FT_Err_Invalid_Face_Handle)
1688 /* font may not support SFNT. falling back to
1689 * read the font data from file directly
1691 hashstr = FcHashGetSHA256DigestFromFile (file);
1699 if (!FcPatternAddString (pat, FC_HASH, hashstr))
1709 * Compute the unicode coverage for the font
1711 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1715 #if HAVE_FT_GET_BDF_PROPERTY
1716 /* For PCF fonts, override the computed spacing with the one from
1718 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1719 prop.type == BDF_PROPERTY_TYPE_ATOM) {
1720 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1721 spacing = FC_CHARCELL;
1722 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1724 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1725 spacing = FC_PROPORTIONAL;
1730 * Skip over PCF fonts that have no encoded characters; they're
1731 * usually just Unicode fonts transcoded to some legacy encoding
1732 * FT forces us to approximate whether a font is a PCF font
1733 * or not by whether it has any BDF properties. Try PIXEL_SIZE;
1734 * I don't know how to get a list of BDF properties on the font. -PL
1736 if (FcCharSetCount (cs) == 0)
1738 #if HAVE_FT_GET_BDF_PROPERTY
1739 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1744 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1747 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1751 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1753 FcLangSetDestroy (ls);
1757 FcLangSetDestroy (ls);
1759 if (spacing != FC_PROPORTIONAL)
1760 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1763 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1765 for (i = 0; i < face->num_fixed_sizes; i++)
1766 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1767 FcGetPixelSize (face, i)))
1769 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1772 #if HAVE_FT_GET_X11_FONT_FORMAT
1774 * Use the (not well documented or supported) X-specific function
1775 * from FreeType to figure out the font format
1778 const char *font_format = FT_Get_X11_Font_Format (face);
1780 if (!FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format))
1786 * Drop our reference to the charset
1788 FcCharSetDestroy (cs);
1793 FcCharSetDestroy (cs);
1795 FcPatternDestroy (pat);
1801 FcFreeTypeQuery(const FcChar8 *file,
1807 FT_Library ftLibrary;
1808 FcPattern *pat = NULL;
1810 if (FT_Init_FreeType (&ftLibrary))
1813 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1816 *count = face->num_faces;
1818 pat = FcFreeTypeQueryFace (face, file, id, blanks);
1820 FT_Done_Face (face);
1822 FT_Done_FreeType (ftLibrary);
1827 * For our purposes, this approximation is sufficient
1829 #if !HAVE_FT_GET_NEXT_CHAR
1830 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1832 (*(gi) = 1), (ucs4) + 1)
1833 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1836 typedef struct _FcCharEnt {
1838 unsigned char encode;
1842 const FcCharEnt *ent;
1846 typedef struct _FcFontDecode {
1847 FT_Encoding encoding;
1848 const FcCharMap *map;
1852 static const FcCharEnt AdobeSymbolEnt[] = {
1853 { 0x0020, 0x20 }, /* SPACE # space */
1854 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
1855 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
1856 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
1857 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
1858 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
1859 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
1860 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
1861 { 0x002C, 0x2C }, /* COMMA # comma */
1862 { 0x002E, 0x2E }, /* FULL STOP # period */
1863 { 0x002F, 0x2F }, /* SOLIDUS # slash */
1864 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
1865 { 0x0031, 0x31 }, /* DIGIT ONE # one */
1866 { 0x0032, 0x32 }, /* DIGIT TWO # two */
1867 { 0x0033, 0x33 }, /* DIGIT THREE # three */
1868 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
1869 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
1870 { 0x0036, 0x36 }, /* DIGIT SIX # six */
1871 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
1872 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
1873 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
1874 { 0x003A, 0x3A }, /* COLON # colon */
1875 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
1876 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1877 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
1878 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
1879 { 0x003F, 0x3F }, /* QUESTION MARK # question */
1880 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
1881 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
1882 { 0x005F, 0x5F }, /* LOW LINE # underscore */
1883 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
1884 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
1885 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
1886 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1887 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
1888 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
1889 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
1890 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
1891 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
1892 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
1893 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1894 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
1895 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
1896 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
1897 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
1898 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
1899 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
1900 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
1901 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
1902 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
1903 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
1904 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
1905 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
1906 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
1907 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
1908 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
1909 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
1910 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
1911 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
1912 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
1913 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
1914 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
1915 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
1916 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
1917 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
1918 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
1919 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
1920 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
1921 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
1922 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
1923 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
1924 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1925 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
1926 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
1927 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
1928 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
1929 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
1930 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
1931 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
1932 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
1933 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
1934 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1935 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1936 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
1937 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
1938 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
1939 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
1940 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
1941 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
1942 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
1943 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
1944 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
1945 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
1946 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
1947 { 0x2022, 0xB7 }, /* BULLET # bullet */
1948 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
1949 { 0x2032, 0xA2 }, /* PRIME # minute */
1950 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
1951 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
1952 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
1953 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
1954 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
1955 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
1956 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
1957 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
1958 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
1959 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
1960 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
1961 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
1962 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
1963 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
1964 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
1965 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
1966 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
1967 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
1968 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
1969 { 0x2200, 0x22 }, /* FOR ALL # universal */
1970 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
1971 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
1972 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
1973 { 0x2206, 0x44 }, /* INCREMENT # Delta */
1974 { 0x2207, 0xD1 }, /* NABLA # gradient */
1975 { 0x2208, 0xCE }, /* ELEMENT OF # element */
1976 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
1977 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
1978 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
1979 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
1980 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
1981 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
1982 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
1983 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
1984 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
1985 { 0x221E, 0xA5 }, /* INFINITY # infinity */
1986 { 0x2220, 0xD0 }, /* ANGLE # angle */
1987 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
1988 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
1989 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
1990 { 0x222A, 0xC8 }, /* UNION # union */
1991 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
1992 { 0x2234, 0x5C }, /* THEREFORE # therefore */
1993 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
1994 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
1995 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
1996 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
1997 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
1998 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
1999 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
2000 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
2001 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
2002 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
2003 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
2004 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
2005 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
2006 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
2007 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
2008 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
2009 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
2010 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
2011 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
2012 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
2013 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
2014 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
2015 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
2016 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
2017 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
2018 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
2019 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
2020 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
2021 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
2022 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
2023 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
2024 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
2025 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
2026 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
2027 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2028 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
2029 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
2030 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
2031 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
2032 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
2033 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2034 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2035 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
2036 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2037 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
2038 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
2039 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
2040 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
2041 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
2042 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
2043 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
2044 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
2045 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
2046 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
2049 static const FcCharMap AdobeSymbol = {
2051 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2054 static const FcFontDecode fcFontDecoders[] = {
2055 { ft_encoding_unicode, 0, (1 << 21) - 1 },
2056 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
2059 #define NUM_DECODE (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
2061 static const FcChar32 prefer_unicode[] = {
2062 0x20ac, /* EURO SIGN */
2065 #define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
2068 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2074 high = map->nent - 1;
2075 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2079 mid = (high + low) >> 1;
2080 bmp = map->ent[mid].bmp;
2082 return (FT_ULong) map->ent[mid].encode;
2092 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2096 for (i = 0; i < map->nent; i++)
2097 if (map->ent[i].encode == private)
2098 return (FcChar32) map->ent[i].bmp;
2103 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2107 for (i = 0; i < NUM_DECODE; i++)
2108 if (fcFontDecoders[i].encoding == encoding)
2109 return fcFontDecoders[i].map;
2113 #include "../fc-glyphname/fcglyphname.h"
2116 FcHashGlyphName (const FcChar8 *name)
2121 while ((c = *name++))
2123 h = ((h << 1) | (h >> 31)) ^ c;
2128 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2130 * Use Type1 glyph names for fonts which have reliable names
2131 * and which export an Adobe Custom mapping
2134 FcFreeTypeUseNames (FT_Face face)
2138 if (!FT_Has_PS_Glyph_Names (face))
2140 for (map = 0; map < face->num_charmaps; map++)
2141 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2146 static const FcChar8 *
2147 FcUcs4ToGlyphName (FcChar32 ucs4)
2149 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2153 while ((gn = _fc_ucs_to_name[i]) != -1)
2155 if (_fc_glyph_names[gn].ucs == ucs4)
2156 return _fc_glyph_names[gn].name;
2159 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2164 if (i >= FC_GLYPHNAME_HASH)
2165 i -= FC_GLYPHNAME_HASH;
2171 FcGlyphNameToUcs4 (FcChar8 *name)
2173 FcChar32 h = FcHashGlyphName (name);
2174 int i = (int) (h % FC_GLYPHNAME_HASH);
2178 while ((gn = _fc_name_to_ucs[i]) != -1)
2180 if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name))
2181 return _fc_glyph_names[gn].ucs;
2184 r = (int) (h % FC_GLYPHNAME_REHASH);
2189 if (i >= FC_GLYPHNAME_HASH)
2190 i -= FC_GLYPHNAME_HASH;
2196 * Work around a bug in some FreeType versions which fail
2197 * to correctly bounds check glyph name buffers and overwrite
2198 * the stack. As Postscript names have a limit of 127 characters,
2199 * this should be sufficient.
2202 #if FC_GLYPHNAME_MAXLEN < 127
2203 # define FC_GLYPHNAME_BUFLEN 127
2205 # define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2209 * Search through a font for a glyph by name. This is
2210 * currently a linear search as there doesn't appear to be
2211 * any defined order within the font
2214 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2217 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2219 for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2221 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2222 if (!strcmp ((char *) name, (char *) name_buf))
2230 * Map a UCS4 glyph to a glyph index. Use all available encoding
2231 * tables to try and find one that works. This information is expected
2232 * to be cached by higher levels, so performance isn't critical
2236 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2238 int initial, offset, decode;
2249 * Find the current encoding
2253 for (; initial < NUM_DECODE; initial++)
2254 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2256 if (initial == NUM_DECODE)
2259 for (p = 0; p < NUM_PREFER_UNICODE; p++)
2260 if (ucs4 == prefer_unicode[p])
2266 * Check each encoding for the glyph, starting with the current one
2268 for (offset = 0; offset < NUM_DECODE; offset++)
2270 decode = (initial + offset) % NUM_DECODE;
2271 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2272 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2274 if (fcFontDecoders[decode].map)
2276 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2277 if (charcode == ~0U)
2282 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2286 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2288 * Check postscript name table if present
2290 if (FcFreeTypeUseNames (face))
2292 const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
2295 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2305 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2306 FT_UInt glyph, FcBlanks *blanks,
2308 FcBool using_strike)
2310 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2314 load_flags &= ~FT_LOAD_NO_SCALE;
2317 * When using scalable fonts, only report those glyphs
2318 * which can be scaled; otherwise those fonts will
2319 * only be available at some sizes, and never when
2320 * transformed. Avoid this by simply reporting bitmap-only
2323 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2324 load_flags |= FT_LOAD_NO_BITMAP;
2326 if (FT_Load_Glyph (face, glyph, load_flags))
2333 *advance = slot->metrics.horiAdvance;
2335 switch ((int) slot->format) {
2336 case ft_glyph_format_bitmap:
2338 * Bitmaps are assumed to be reasonable; if
2339 * this proves to be a rash assumption, this
2340 * code can be easily modified
2343 case ft_glyph_format_outline:
2345 * Glyphs with contours are always OK
2347 if (slot->outline.n_contours != 0)
2350 * Glyphs with no contours are only OK if
2351 * they're members of the Blanks set specified
2352 * in the configuration. If blanks isn't set,
2353 * then allow any glyph to be blank
2355 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2357 /* fall through ... */
2364 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2367 FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index)
2369 FcChar32 page, off, ucs4;
2371 FcChar32 font_max = 0;
2375 const FcCharMap *map;
2379 FT_Pos advance, advance_one = 0, advance_two = 0;
2380 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2381 FcBool using_strike = FcFalse;
2383 fcs = FcCharSetCreate ();
2387 #if HAVE_FT_SELECT_SIZE
2388 if (strike_index >= 0) {
2389 if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
2391 using_strike = FcTrue;
2396 printf ("Family %s style %s\n", face->family_name, face->style_name);
2398 for (o = 0; o < NUM_DECODE; o++)
2400 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2402 map = fcFontDecoders[o].map;
2406 * Non-Unicode tables are easy; there's a list of all possible
2409 for (i = 0; i < map->nent; i++)
2411 ucs4 = map->ent[i].bmp;
2412 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2414 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2417 * ignore glyphs with zero advance. They’re
2418 * combining characters, and while their behaviour
2419 * isn’t well defined for monospaced applications in
2420 * Unicode, there are many fonts which include
2421 * zero-width combining characters in otherwise
2428 has_advance = FcTrue;
2429 advance_one = advance;
2431 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2435 dual_advance = FcTrue;
2436 fixed_advance = FcFalse;
2437 advance_two = advance;
2439 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2440 dual_advance = FcFalse;
2444 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2447 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2449 if (ucs4 > font_max)
2459 ucs4 = FT_Get_First_Char (face, &glyph);
2462 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2468 has_advance = FcTrue;
2469 advance_one = advance;
2471 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2475 dual_advance = FcTrue;
2476 fixed_advance = FcFalse;
2477 advance_two = advance;
2479 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2480 dual_advance = FcFalse;
2484 if ((ucs4 >> 8) != page)
2487 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2492 leaf->map[off >> 5] |= (1 << (off & 0x1f));
2494 if (ucs4 > font_max)
2498 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2501 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2503 FcBool FT_Has, FC_Has;
2505 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2506 FC_Has = FcCharSetHasChar (fcs, ucs4);
2507 if (FT_Has != FC_Has)
2509 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2515 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2517 * Add mapping from PS glyph names if available
2519 if (FcFreeTypeUseNames (face))
2521 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2523 for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2525 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2527 ucs4 = FcGlyphNameToUcs4 (name_buf);
2528 if (ucs4 != 0xffff &&
2529 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2535 has_advance = FcTrue;
2536 advance_one = advance;
2538 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2542 dual_advance = FcTrue;
2543 fixed_advance = FcFalse;
2544 advance_two = advance;
2546 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2547 dual_advance = FcFalse;
2550 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2553 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2555 if (ucs4 > font_max)
2564 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2565 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2567 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2568 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2570 if (has_char && !has_bit)
2572 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike))
2573 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2575 printf ("Bitmap missing char 0x%x\n", ucs4);
2577 else if (!has_char && has_bit)
2578 printf ("Bitmap extra char 0x%x\n", ucs4);
2583 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2586 *spacing = FC_PROPORTIONAL;
2589 FcCharSetDestroy (fcs);
2595 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2600 * Check for bitmap-only ttf fonts that are missing the glyf table.
2601 * In that case, pick a size and look for glyphs in that size instead
2603 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
2604 face->num_fixed_sizes > 0 &&
2605 FT_Get_Sfnt_Table (face, ft_sfnt_head))
2607 FT_Int strike_index = 0;
2610 /* Select the face closest to 16 pixels tall */
2611 for (i = 1; i < face->num_fixed_sizes; i++) {
2612 if (abs (face->available_sizes[i].height - 16) <
2613 abs (face->available_sizes[strike_index].height - 16))
2616 cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index);
2619 cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1);
2624 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2628 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2632 #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2633 #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2634 #define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2636 #define OTLAYOUT_HEAD "otlayout:"
2637 #define OTLAYOUT_HEAD_LEN 9
2638 #define OTLAYOUT_ID_LEN 4
2639 /* space + head + id */
2640 #define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2643 * This is a bit generous; the registry has only lower case and space
2644 * except for 'DFLT'.
2646 #define FcIsSpace(x) (040 == (x))
2647 #define FcIsDigit(c) (('0' <= (c) && (c) <= '9'))
2648 #define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(x) || FcIsSpace(x))
2651 addtag(FcChar8 *complex_, FT_ULong tag)
2653 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2655 tagstring[0] = (FcChar8)(tag >> 24),
2656 tagstring[1] = (FcChar8)(tag >> 16),
2657 tagstring[2] = (FcChar8)(tag >> 8),
2658 tagstring[3] = (FcChar8)(tag);
2659 tagstring[4] = '\0';
2661 /* skip tags which aren't alphanumeric, under the assumption that
2662 * they're probably broken
2664 if (!FcIsValidScript(tagstring[0]) ||
2665 !FcIsValidScript(tagstring[1]) ||
2666 !FcIsValidScript(tagstring[2]) ||
2667 !FcIsValidScript(tagstring[3]))
2670 if (*complex_ != '\0')
2671 strcat ((char *) complex_, " ");
2672 strcat ((char *) complex_, OTLAYOUT_HEAD);
2673 strcat ((char *) complex_, (char *) tagstring);
2677 compareulong (const void *a, const void *b)
2679 const FT_ULong *ua = (const FT_ULong *) a;
2680 const FT_ULong *ub = (const FT_ULong *) b;
2686 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
2688 FT_ULong cur_offset, new_offset, base_offset;
2689 FT_Stream stream = face->stream;
2697 if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2700 base_offset = ftglue_stream_pos ( stream );
2704 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2707 new_offset = GET_UShort() + base_offset;
2709 ftglue_stream_frame_exit( stream );
2711 cur_offset = ftglue_stream_pos( stream );
2713 if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
2716 base_offset = ftglue_stream_pos( stream );
2718 if ( ftglue_stream_frame_enter( stream, 2L ) )
2721 script_count = GET_UShort ();
2723 ftglue_stream_frame_exit( stream );
2725 *stags = malloc(script_count * sizeof (FT_ULong));
2730 for ( n = 0; n < script_count; n++ )
2732 if ( ftglue_stream_frame_enter( stream, 6L ) )
2735 (*stags)[p] = GET_ULong ();
2736 new_offset = GET_UShort () + base_offset;
2738 ftglue_stream_frame_exit( stream );
2740 cur_offset = ftglue_stream_pos( stream );
2742 error = ftglue_stream_seek( stream, new_offset );
2744 if ( error == FT_Err_Ok )
2747 (void)ftglue_stream_seek( stream, cur_offset );
2753 /* sort the tag list before returning it */
2754 qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
2756 return script_count;
2765 FcFontCapabilities(FT_Face face)
2767 FcBool issilgraphitefont = 0;
2770 FT_ULong *gsubtags=NULL, *gpostags=NULL;
2771 FT_UShort gsub_count=0, gpos_count=0;
2773 FcChar8 *complex_ = NULL;
2774 int indx1 = 0, indx2 = 0;
2776 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2777 issilgraphitefont = ( err == FT_Err_Ok);
2779 gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
2780 gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
2782 if (!issilgraphitefont && !gsub_count && !gpos_count)
2785 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2786 (issilgraphitefont ? 13 : 0));
2787 complex_ = malloc (sizeof (FcChar8) * maxsize);
2792 if (issilgraphitefont)
2793 strcpy((char *) complex_, "ttable:Silf ");
2795 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2796 if (indx1 == gsub_count) {
2797 addtag(complex_, gpostags[indx2]);
2799 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2800 addtag(complex_, gsubtags[indx1]);
2802 } else if (gsubtags[indx1] == gpostags[indx2]) {
2803 addtag(complex_, gsubtags[indx1]);
2807 addtag(complex_, gpostags[indx2]);
2811 if (FcDebug () & FC_DBG_SCANV)
2812 printf("complex_ features in this font: %s\n", complex_);
2819 #define __fcfreetype__
2820 #include "fcaliastail.h"
2821 #include "fcftaliastail.h"
2822 #undef __fcfreetype__