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