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