]> git.wh0rd.org - fontconfig.git/blob - src/fcfreetype.c
Oops. Left debugging printf in previous commit.
[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 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
963 return c[i].value;
964 return -1;
965 }
966
967 typedef FcChar8 *FC8;
968
969 static const FcStringConst weightConsts[] = {
970 { (FC8) "thin", FC_WEIGHT_THIN },
971 { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT },
972 { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT },
973 { (FC8) "light", FC_WEIGHT_LIGHT },
974 { (FC8) "book", FC_WEIGHT_BOOK },
975 { (FC8) "regular", FC_WEIGHT_REGULAR },
976 { (FC8) "normal", FC_WEIGHT_NORMAL },
977 { (FC8) "medium", FC_WEIGHT_MEDIUM },
978 { (FC8) "demibold", FC_WEIGHT_DEMIBOLD },
979 { (FC8) "demi", FC_WEIGHT_DEMIBOLD },
980 { (FC8) "semibold", FC_WEIGHT_SEMIBOLD },
981 { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD },
982 { (FC8) "superbold", FC_WEIGHT_EXTRABOLD },
983 { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD },
984 { (FC8) "bold", FC_WEIGHT_BOLD },
985 { (FC8) "black", FC_WEIGHT_BLACK },
986 { (FC8) "heavy", FC_WEIGHT_HEAVY },
987 };
988
989 #define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
990
991 #define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
992 #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
993
994 static const FcStringConst widthConsts[] = {
995 { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED },
996 { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED },
997 { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED },
998 { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
999 { (FC8) "normal", FC_WIDTH_NORMAL },
1000 { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED },
1001 { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
1002 { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
1003 { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
1004 };
1005
1006 #define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
1007
1008 #define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
1009 #define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
1010
1011 static const FcStringConst slantConsts[] = {
1012 { (FC8) "italic", FC_SLANT_ITALIC },
1013 { (FC8) "kursiv", FC_SLANT_ITALIC },
1014 { (FC8) "oblique", FC_SLANT_OBLIQUE },
1015 };
1016
1017 #define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
1018
1019 #define FcIsSlant(s) FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
1020 #define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
1021
1022 static const FcStringConst decorativeConsts[] = {
1023 { (FC8) "shadow", FcTrue },
1024 { (FC8) "smallcaps", FcTrue },
1025 { (FC8) "antiqua", FcTrue },
1026 { (FC8) "romansc", FcTrue },
1027 { (FC8) "embosed", FcTrue },
1028 { (FC8) "romansmallcaps", FcTrue },
1029 };
1030
1031 #define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
1032
1033 #define FcIsDecorative(s) FcStringIsConst(s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1034 #define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1035
1036 static double
1037 FcGetPixelSize (FT_Face face, int i)
1038 {
1039 #if HAVE_FT_GET_BDF_PROPERTY
1040 if (face->num_fixed_sizes == 1)
1041 {
1042 BDF_PropertyRec prop;
1043 int rc;
1044
1045 rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
1046 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1047 return (double) prop.u.integer;
1048 }
1049 #endif
1050 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
1051 return (double) face->available_sizes[i].y_ppem / 64.0;
1052 #else
1053 return (double) face->available_sizes[i].height;
1054 #endif
1055 }
1056
1057 static FcBool
1058 FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
1059 {
1060 int e;
1061 FcChar8 *old;
1062 for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1063 if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1064 {
1065 return FcTrue;
1066 }
1067 return FcFalse;
1068 }
1069
1070 static const FT_UShort platform_order[] = {
1071 TT_PLATFORM_MICROSOFT,
1072 TT_PLATFORM_APPLE_UNICODE,
1073 TT_PLATFORM_MACINTOSH,
1074 };
1075 #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
1076
1077 static const FT_UShort nameid_order[] = {
1078 TT_NAME_ID_PREFERRED_FAMILY,
1079 TT_NAME_ID_FONT_FAMILY,
1080 TT_NAME_ID_MAC_FULL_NAME,
1081 TT_NAME_ID_FULL_NAME,
1082 TT_NAME_ID_PREFERRED_SUBFAMILY,
1083 TT_NAME_ID_FONT_SUBFAMILY,
1084 TT_NAME_ID_TRADEMARK,
1085 TT_NAME_ID_MANUFACTURER,
1086 };
1087
1088 #define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0]))
1089 FcPattern *
1090 FcFreeTypeQueryFace (const FT_Face face,
1091 const FcChar8 *file,
1092 int id,
1093 FcBlanks *blanks)
1094 {
1095 FcPattern *pat;
1096 int slant = -1;
1097 int weight = -1;
1098 int width = -1;
1099 FcBool decorative = FcFalse;
1100 int i;
1101 FcCharSet *cs;
1102 FcLangSet *ls;
1103 #if 0
1104 FcChar8 *family = 0;
1105 #endif
1106 FcChar8 *complex;
1107 const FcChar8 *foundry = 0;
1108 int spacing;
1109 TT_OS2 *os2;
1110 #if HAVE_FT_GET_PS_FONT_INFO
1111 PS_FontInfoRec psfontinfo;
1112 #endif
1113 #if HAVE_FT_GET_BDF_PROPERTY
1114 BDF_PropertyRec prop;
1115 #endif
1116 TT_Header *head;
1117 const FcChar8 *exclusiveLang = 0;
1118 FT_SfntName sname;
1119 FT_UInt snamei, snamec;
1120
1121 int nfamily = 0;
1122 int nfamily_lang = 0;
1123 int nstyle = 0;
1124 int nstyle_lang = 0;
1125 int nfullname = 0;
1126 int nfullname_lang = 0;
1127 int p, platform;
1128 int n, nameid;
1129
1130 FcChar8 *style = 0;
1131 int st;
1132
1133 pat = FcPatternCreate ();
1134 if (!pat)
1135 goto bail0;
1136
1137 if (!FcPatternAddBool (pat, FC_OUTLINE,
1138 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1139 goto bail1;
1140
1141 if (!FcPatternAddBool (pat, FC_SCALABLE,
1142 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1143 goto bail1;
1144
1145
1146 /*
1147 * Get the OS/2 table
1148 */
1149 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1150
1151 /*
1152 * Look first in the OS/2 table for the foundry, if
1153 * not found here, the various notices will be searched for
1154 * that information, either from the sfnt name tables or
1155 * the Postscript FontInfo dictionary. Finally, the
1156 * BDF properties will queried.
1157 */
1158
1159 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1160 foundry = FcVendorFoundry(os2->achVendID);
1161
1162 if (FcDebug () & FC_DBG_SCANV)
1163 printf ("\n");
1164 /*
1165 * Grub through the name table looking for family
1166 * and style names. FreeType makes quite a hash
1167 * of them
1168 */
1169 snamec = FT_Get_Sfnt_Name_Count (face);
1170 for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
1171 {
1172 if (p < NUM_PLATFORM_ORDER)
1173 platform = platform_order[p];
1174 else
1175 platform = 0xffff;
1176
1177 /*
1178 * Order nameids so preferred names appear first
1179 * in the resulting list
1180 */
1181 for (n = 0; n < NUM_NAMEID_ORDER; n++)
1182 {
1183 nameid = nameid_order[n];
1184
1185 for (snamei = 0; snamei < snamec; snamei++)
1186 {
1187 FcChar8 *utf8;
1188 const FcChar8 *lang;
1189 const char *elt = 0, *eltlang = 0;
1190 int *np = 0, *nlangp = 0;
1191
1192 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1193 continue;
1194 if (sname.name_id != nameid)
1195 continue;
1196
1197 /*
1198 * Sort platforms in preference order, accepting
1199 * all other platforms last
1200 */
1201 if (p < NUM_PLATFORM_ORDER)
1202 {
1203 if (sname.platform_id != platform)
1204 continue;
1205 }
1206 else
1207 {
1208 int sp;
1209
1210 for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1211 if (sname.platform_id == platform_order[sp])
1212 break;
1213 if (sp != NUM_PLATFORM_ORDER)
1214 continue;
1215 }
1216 utf8 = FcSfntNameTranscode (&sname);
1217 lang = FcSfntNameLanguage (&sname);
1218
1219 if (!utf8)
1220 continue;
1221
1222 switch (sname.name_id) {
1223 case TT_NAME_ID_PREFERRED_FAMILY:
1224 case TT_NAME_ID_FONT_FAMILY:
1225 #if 0
1226 case TT_NAME_ID_PS_NAME:
1227 case TT_NAME_ID_UNIQUE_ID:
1228 #endif
1229 if (FcDebug () & FC_DBG_SCANV)
1230 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1231 sname.name_id, sname.platform_id,
1232 sname.encoding_id, sname.language_id,
1233 utf8);
1234
1235 elt = FC_FAMILY;
1236 eltlang = FC_FAMILYLANG;
1237 np = &nfamily;
1238 nlangp = &nfamily_lang;
1239 break;
1240 case TT_NAME_ID_MAC_FULL_NAME:
1241 case TT_NAME_ID_FULL_NAME:
1242 if (FcDebug () & FC_DBG_SCANV)
1243 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
1244 sname.name_id, sname.platform_id,
1245 sname.encoding_id, sname.language_id,
1246 utf8);
1247
1248 elt = FC_FULLNAME;
1249 eltlang = FC_FULLNAMELANG;
1250 np = &nfullname;
1251 nlangp = &nfullname_lang;
1252 break;
1253 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1254 case TT_NAME_ID_FONT_SUBFAMILY:
1255 if (FcDebug () & FC_DBG_SCANV)
1256 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1257 sname.name_id, sname.platform_id,
1258 sname.encoding_id, sname.language_id,
1259 utf8);
1260
1261 elt = FC_STYLE;
1262 eltlang = FC_STYLELANG;
1263 np = &nstyle;
1264 nlangp = &nstyle_lang;
1265 break;
1266 case TT_NAME_ID_TRADEMARK:
1267 case TT_NAME_ID_MANUFACTURER:
1268 /* If the foundry wasn't found in the OS/2 table, look here */
1269 if(!foundry)
1270 foundry = FcNoticeFoundry((FT_String *) utf8);
1271 break;
1272 }
1273 if (elt)
1274 {
1275 if (FcStringInPatternElement (pat, elt, utf8))
1276 {
1277 free (utf8);
1278 continue;
1279 }
1280
1281 /* add new element */
1282 if (!FcPatternAddString (pat, elt, utf8))
1283 {
1284 free (utf8);
1285 goto bail1;
1286 }
1287 free (utf8);
1288 if (lang)
1289 {
1290 /* pad lang list with 'xx' to line up with elt */
1291 while (*nlangp < *np)
1292 {
1293 if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
1294 goto bail1;
1295 ++*nlangp;
1296 }
1297 if (!FcPatternAddString (pat, eltlang, lang))
1298 goto bail1;
1299 ++*nlangp;
1300 }
1301 ++*np;
1302 }
1303 else
1304 free (utf8);
1305 }
1306 }
1307 }
1308
1309 if (!nfamily && face->family_name &&
1310 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1311 {
1312 if (FcDebug () & FC_DBG_SCANV)
1313 printf ("using FreeType family \"%s\"\n", face->family_name);
1314 if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1315 goto bail1;
1316 ++nfamily;
1317 }
1318
1319 if (!nstyle && face->style_name &&
1320 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1321 {
1322 if (FcDebug () & FC_DBG_SCANV)
1323 printf ("using FreeType style \"%s\"\n", face->style_name);
1324 if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1325 goto bail1;
1326 ++nstyle;
1327 }
1328
1329 if (!nfamily)
1330 {
1331 FcChar8 *start, *end;
1332 FcChar8 *family;
1333
1334 start = (FcChar8 *) strrchr ((char *) file, '/');
1335 if (start)
1336 start++;
1337 else
1338 start = (FcChar8 *) file;
1339 end = (FcChar8 *) strrchr ((char *) start, '.');
1340 if (!end)
1341 end = start + strlen ((char *) start);
1342 /* freed below */
1343 family = malloc (end - start + 1);
1344 strncpy ((char *) family, (char *) start, end - start);
1345 family[end - start] = '\0';
1346 if (FcDebug () & FC_DBG_SCANV)
1347 printf ("using filename for family %s\n", family);
1348 if (!FcPatternAddString (pat, FC_FAMILY, family))
1349 {
1350 free (family);
1351 goto bail1;
1352 }
1353 free (family);
1354 ++nfamily;
1355 }
1356
1357 if (!FcPatternAddString (pat, FC_FILE, file))
1358 goto bail1;
1359
1360 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1361 goto bail1;
1362
1363 #if 0
1364 /*
1365 * don't even try this -- CJK 'monospace' fonts are really
1366 * dual width, and most other fonts don't bother to set
1367 * the attribute. Sigh.
1368 */
1369 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1370 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1371 goto bail1;
1372 #endif
1373
1374 /*
1375 * Find the font revision (if available)
1376 */
1377 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1378 if (head)
1379 {
1380 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1381 goto bail1;
1382 }
1383 else
1384 {
1385 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1386 goto bail1;
1387 }
1388
1389 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1390 {
1391 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1392 {
1393 FT_ULong bits;
1394 int bit;
1395 if (FcCodePageRange[i].bit < 32)
1396 {
1397 bits = os2->ulCodePageRange1;
1398 bit = FcCodePageRange[i].bit;
1399 }
1400 else
1401 {
1402 bits = os2->ulCodePageRange2;
1403 bit = FcCodePageRange[i].bit - 32;
1404 }
1405 if (bits & (1 << bit))
1406 {
1407 /*
1408 * If the font advertises support for multiple
1409 * "exclusive" languages, then include support
1410 * for any language found to have coverage
1411 */
1412 if (exclusiveLang)
1413 {
1414 exclusiveLang = 0;
1415 break;
1416 }
1417 exclusiveLang = FcCodePageRange[i].lang;
1418 }
1419 }
1420 }
1421
1422 if (os2 && os2->version != 0xffff)
1423 {
1424 if (os2->usWeightClass == 0)
1425 ;
1426 else if (os2->usWeightClass < 150)
1427 weight = FC_WEIGHT_THIN;
1428 else if (os2->usWeightClass < 250)
1429 weight = FC_WEIGHT_EXTRALIGHT;
1430 else if (os2->usWeightClass < 350)
1431 weight = FC_WEIGHT_LIGHT;
1432 else if (os2->usWeightClass < 450)
1433 weight = FC_WEIGHT_REGULAR;
1434 else if (os2->usWeightClass < 550)
1435 weight = FC_WEIGHT_MEDIUM;
1436 else if (os2->usWeightClass < 650)
1437 weight = FC_WEIGHT_SEMIBOLD;
1438 else if (os2->usWeightClass < 750)
1439 weight = FC_WEIGHT_BOLD;
1440 else if (os2->usWeightClass < 850)
1441 weight = FC_WEIGHT_EXTRABOLD;
1442 else if (os2->usWeightClass < 950)
1443 weight = FC_WEIGHT_BLACK;
1444 if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1445 printf ("\tos2 weight class %d maps to weight %d\n",
1446 os2->usWeightClass, weight);
1447
1448 switch (os2->usWidthClass) {
1449 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1450 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1451 case 3: width = FC_WIDTH_CONDENSED; break;
1452 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1453 case 5: width = FC_WIDTH_NORMAL; break;
1454 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1455 case 7: width = FC_WIDTH_EXPANDED; break;
1456 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1457 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1458 }
1459 if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1460 printf ("\tos2 width class %d maps to width %d\n",
1461 os2->usWidthClass, width);
1462 }
1463 if (os2 && (complex = FcFontCapabilities(face)))
1464 {
1465 if (!FcPatternAddString (pat, FC_CAPABILITY, complex))
1466 {
1467 free (complex);
1468 goto bail1;
1469 }
1470 free (complex);
1471 }
1472
1473 /*
1474 * Type 1: Check for FontInfo dictionary information
1475 * Code from g2@magestudios.net (Gerard Escalante)
1476 */
1477
1478 #if HAVE_FT_GET_PS_FONT_INFO
1479 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1480 {
1481 if (weight == -1 && psfontinfo.weight)
1482 {
1483 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1484 if (FcDebug() & FC_DBG_SCANV)
1485 printf ("\tType1 weight %s maps to %d\n",
1486 psfontinfo.weight, weight);
1487 }
1488
1489 #if 0
1490 /*
1491 * Don't bother with italic_angle; FreeType already extracts that
1492 * information for us and sticks it into style_flags
1493 */
1494 if (psfontinfo.italic_angle)
1495 slant = FC_SLANT_ITALIC;
1496 else
1497 slant = FC_SLANT_ROMAN;
1498 #endif
1499
1500 if(!foundry)
1501 foundry = FcNoticeFoundry(psfontinfo.notice);
1502 }
1503 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1504
1505 #if HAVE_FT_GET_BDF_PROPERTY
1506 /*
1507 * Finally, look for a FOUNDRY BDF property if no other
1508 * mechanism has managed to locate a foundry
1509 */
1510
1511 if (!foundry)
1512 {
1513 int rc;
1514 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1515 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1516 foundry = (FcChar8 *) prop.u.atom;
1517 }
1518
1519 if (width == -1)
1520 {
1521 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1522 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1523 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1524 {
1525 FT_Int32 value;
1526
1527 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1528 value = prop.u.integer;
1529 else
1530 value = (FT_Int32) prop.u.cardinal;
1531 switch ((value + 5) / 10) {
1532 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1533 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1534 case 3: width = FC_WIDTH_CONDENSED; break;
1535 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1536 case 5: width = FC_WIDTH_NORMAL; break;
1537 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1538 case 7: width = FC_WIDTH_EXPANDED; break;
1539 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1540 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1541 }
1542 }
1543 if (width == -1 &&
1544 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1545 prop.type == BDF_PROPERTY_TYPE_ATOM)
1546 {
1547 width = FcIsWidth ((FcChar8 *) prop.u.atom);
1548 if (FcDebug () & FC_DBG_SCANV)
1549 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
1550 }
1551 }
1552 #endif
1553
1554 /*
1555 * Look for weight, width and slant names in the style value
1556 */
1557 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1558 {
1559 if (weight == -1)
1560 {
1561 weight = FcContainsWeight (style);
1562 if (FcDebug() & FC_DBG_SCANV)
1563 printf ("\tStyle %s maps to weight %d\n", style, weight);
1564 }
1565 if (width == -1)
1566 {
1567 width = FcContainsWidth (style);
1568 if (FcDebug() & FC_DBG_SCANV)
1569 printf ("\tStyle %s maps to width %d\n", style, width);
1570 }
1571 if (slant == -1)
1572 {
1573 slant = FcContainsSlant (style);
1574 if (FcDebug() & FC_DBG_SCANV)
1575 printf ("\tStyle %s maps to slant %d\n", style, slant);
1576 }
1577 if (decorative == FcFalse)
1578 {
1579 decorative = FcContainsDecorative (style) > 0;
1580 if (FcDebug() & FC_DBG_SCANV)
1581 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1582 }
1583 }
1584 /*
1585 * Pull default values from the FreeType flags if more
1586 * specific values not found above
1587 */
1588 if (slant == -1)
1589 {
1590 slant = FC_SLANT_ROMAN;
1591 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1592 slant = FC_SLANT_ITALIC;
1593 }
1594
1595 if (weight == -1)
1596 {
1597 weight = FC_WEIGHT_MEDIUM;
1598 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1599 weight = FC_WEIGHT_BOLD;
1600 }
1601
1602 if (width == -1)
1603 width = FC_WIDTH_NORMAL;
1604
1605 if (foundry == 0)
1606 foundry = (FcChar8 *) "unknown";
1607
1608 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1609 goto bail1;
1610
1611 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1612 goto bail1;
1613
1614 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1615 goto bail1;
1616
1617 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1618 goto bail1;
1619
1620 if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1621 goto bail1;
1622
1623 /*
1624 * Compute the unicode coverage for the font
1625 */
1626 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1627 if (!cs)
1628 goto bail1;
1629
1630 #if HAVE_FT_GET_BDF_PROPERTY
1631 /* For PCF fonts, override the computed spacing with the one from
1632 the property */
1633 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1634 prop.type == BDF_PROPERTY_TYPE_ATOM) {
1635 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1636 spacing = FC_CHARCELL;
1637 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1638 spacing = FC_MONO;
1639 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1640 spacing = FC_PROPORTIONAL;
1641 }
1642 #endif
1643
1644 /*
1645 * Skip over PCF fonts that have no encoded characters; they're
1646 * usually just Unicode fonts transcoded to some legacy encoding
1647 * ftglue.c forces us to approximate whether a font is a PCF font
1648 * or not by whether it has any BDF properties. Try PIXEL_SIZE;
1649 * I don't know how to get a list of BDF properties on the font. -PL
1650 */
1651 if (FcCharSetCount (cs) == 0)
1652 {
1653 #if HAVE_FT_GET_BDF_PROPERTY
1654 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1655 goto bail2;
1656 #endif
1657 }
1658
1659 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1660 goto bail2;
1661
1662 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1663 if (!ls)
1664 goto bail2;
1665
1666 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1667 {
1668 FcLangSetDestroy (ls);
1669 goto bail2;
1670 }
1671
1672 FcLangSetDestroy (ls);
1673
1674 if (spacing != FC_PROPORTIONAL)
1675 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1676 goto bail2;
1677
1678 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1679 {
1680 for (i = 0; i < face->num_fixed_sizes; i++)
1681 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1682 FcGetPixelSize (face, i)))
1683 goto bail2;
1684 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1685 goto bail2;
1686 #if HAVE_FT_GET_BDF_PROPERTY
1687 if(face->num_fixed_sizes == 1) {
1688 int rc;
1689 int value;
1690
1691 /* skip bitmap fonts which do not even have a family name */
1692 rc = FT_Get_BDF_Property(face, "FAMILY_NAME", &prop);
1693 if (rc != 0 || prop.type != BDF_PROPERTY_TYPE_ATOM)
1694 goto bail2;
1695
1696 rc = FT_Get_BDF_Property(face, "POINT_SIZE", &prop);
1697 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1698 value = prop.u.integer;
1699 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1700 value = prop.u.cardinal;
1701 else
1702 goto nevermind;
1703 if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1704 goto nevermind;
1705
1706 rc = FT_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
1707 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1708 value = prop.u.integer;
1709 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1710 value = prop.u.cardinal;
1711 else
1712 goto nevermind;
1713 if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1714 goto nevermind;
1715
1716 }
1717 nevermind:
1718 ;
1719 #endif
1720 }
1721 #if HAVE_FT_GET_X11_FONT_FORMAT
1722 /*
1723 * Use the (not well documented or supported) X-specific function
1724 * from FreeType to figure out the font format
1725 */
1726 {
1727 const char *font_format = FT_Get_X11_Font_Format (face);
1728 if (font_format)
1729 FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
1730 }
1731 #endif
1732
1733 /*
1734 * Drop our reference to the charset
1735 */
1736 FcCharSetDestroy (cs);
1737
1738 return pat;
1739
1740 bail2:
1741 FcCharSetDestroy (cs);
1742 bail1:
1743 FcPatternDestroy (pat);
1744 bail0:
1745 return NULL;
1746 }
1747
1748 FcPattern *
1749 FcFreeTypeQuery(const FcChar8 *file,
1750 int id,
1751 FcBlanks *blanks,
1752 int *count)
1753 {
1754 FT_Face face;
1755 FT_Library ftLibrary;
1756 FcPattern *pat = NULL;
1757
1758 if (FT_Init_FreeType (&ftLibrary))
1759 return NULL;
1760
1761 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1762 goto bail;
1763
1764 *count = face->num_faces;
1765
1766 pat = FcFreeTypeQueryFace (face, file, id, blanks);
1767
1768 FT_Done_Face (face);
1769 bail:
1770 FT_Done_FreeType (ftLibrary);
1771 return pat;
1772 }
1773
1774 /*
1775 * For our purposes, this approximation is sufficient
1776 */
1777 #if !HAVE_FT_GET_NEXT_CHAR
1778 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1779 (*(gi) = 0), 0 : \
1780 (*(gi) = 1), (ucs4) + 1)
1781 #warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
1782 #endif
1783
1784 typedef struct _FcCharEnt {
1785 FcChar16 bmp;
1786 unsigned char encode;
1787 } FcCharEnt;
1788
1789 struct _FcCharMap {
1790 const FcCharEnt *ent;
1791 int nent;
1792 };
1793
1794 typedef struct _FcFontDecode {
1795 FT_Encoding encoding;
1796 const FcCharMap *map;
1797 FcChar32 max;
1798 } FcFontDecode;
1799
1800 static const FcCharEnt AppleRomanEnt[] = {
1801 { 0x0020, 0x20 }, /* SPACE */
1802 { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1803 { 0x0022, 0x22 }, /* QUOTATION MARK */
1804 { 0x0023, 0x23 }, /* NUMBER SIGN */
1805 { 0x0024, 0x24 }, /* DOLLAR SIGN */
1806 { 0x0025, 0x25 }, /* PERCENT SIGN */
1807 { 0x0026, 0x26 }, /* AMPERSAND */
1808 { 0x0027, 0x27 }, /* APOSTROPHE */
1809 { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1810 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1811 { 0x002A, 0x2A }, /* ASTERISK */
1812 { 0x002B, 0x2B }, /* PLUS SIGN */
1813 { 0x002C, 0x2C }, /* COMMA */
1814 { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1815 { 0x002E, 0x2E }, /* FULL STOP */
1816 { 0x002F, 0x2F }, /* SOLIDUS */
1817 { 0x0030, 0x30 }, /* DIGIT ZERO */
1818 { 0x0031, 0x31 }, /* DIGIT ONE */
1819 { 0x0032, 0x32 }, /* DIGIT TWO */
1820 { 0x0033, 0x33 }, /* DIGIT THREE */
1821 { 0x0034, 0x34 }, /* DIGIT FOUR */
1822 { 0x0035, 0x35 }, /* DIGIT FIVE */
1823 { 0x0036, 0x36 }, /* DIGIT SIX */
1824 { 0x0037, 0x37 }, /* DIGIT SEVEN */
1825 { 0x0038, 0x38 }, /* DIGIT EIGHT */
1826 { 0x0039, 0x39 }, /* DIGIT NINE */
1827 { 0x003A, 0x3A }, /* COLON */
1828 { 0x003B, 0x3B }, /* SEMICOLON */
1829 { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1830 { 0x003D, 0x3D }, /* EQUALS SIGN */
1831 { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1832 { 0x003F, 0x3F }, /* QUESTION MARK */
1833 { 0x0040, 0x40 }, /* COMMERCIAL AT */
1834 { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1835 { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1836 { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1837 { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1838 { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1839 { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1840 { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1841 { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1842 { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1843 { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1844 { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1845 { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1846 { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1847 { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1848 { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1849 { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1850 { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1851 { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1852 { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1853 { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1854 { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1855 { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1856 { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1857 { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1858 { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1859 { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1860 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1861 { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1862 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1863 { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1864 { 0x005F, 0x5F }, /* LOW LINE */
1865 { 0x0060, 0x60 }, /* GRAVE ACCENT */
1866 { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1867 { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1868 { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1869 { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1870 { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1871 { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1872 { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1873 { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1874 { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1875 { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1876 { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1877 { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1878 { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1879 { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1880 { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1881 { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1882 { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1883 { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1884 { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1885 { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1886 { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1887 { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1888 { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1889 { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1890 { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1891 { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1892 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1893 { 0x007C, 0x7C }, /* VERTICAL LINE */
1894 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1895 { 0x007E, 0x7E }, /* TILDE */
1896 { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1897 { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1898 { 0x00A2, 0xA2 }, /* CENT SIGN */
1899 { 0x00A3, 0xA3 }, /* POUND SIGN */
1900 { 0x00A5, 0xB4 }, /* YEN SIGN */
1901 { 0x00A7, 0xA4 }, /* SECTION SIGN */
1902 { 0x00A8, 0xAC }, /* DIAERESIS */
1903 { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1904 { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1905 { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1906 { 0x00AC, 0xC2 }, /* NOT SIGN */
1907 { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1908 { 0x00AF, 0xF8 }, /* MACRON */
1909 { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1910 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1911 { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1912 { 0x00B5, 0xB5 }, /* MICRO SIGN */
1913 { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1914 { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1915 { 0x00B8, 0xFC }, /* CEDILLA */
1916 { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1917 { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1918 { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1919 { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1920 { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1921 { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1922 { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1923 { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1924 { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1925 { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1926 { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1927 { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1928 { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1929 { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1930 { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1931 { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1932 { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1933 { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1934 { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1935 { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1936 { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1937 { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1938 { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1939 { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1940 { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1941 { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1942 { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1943 { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1944 { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1945 { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1946 { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1947 { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1948 { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1949 { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1950 { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1951 { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1952 { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1953 { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1954 { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1955 { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1956 { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1957 { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1958 { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1959 { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1960 { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1961 { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1962 { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1963 { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1964 { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1965 { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1966 { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1967 { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1968 { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1969 { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1970 { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1971 { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1972 { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1973 { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1974 { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1975 { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1976 { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1977 { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1978 { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1979 { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1980 { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1981 { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1982 { 0x02C7, 0xFF }, /* CARON */
1983 { 0x02D8, 0xF9 }, /* BREVE */
1984 { 0x02D9, 0xFA }, /* DOT ABOVE */
1985 { 0x02DA, 0xFB }, /* RING ABOVE */
1986 { 0x02DB, 0xFE }, /* OGONEK */
1987 { 0x02DC, 0xF7 }, /* SMALL TILDE */
1988 { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1989 { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1990 { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1991 { 0x2013, 0xD0 }, /* EN DASH */
1992 { 0x2014, 0xD1 }, /* EM DASH */
1993 { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1994 { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1995 { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1996 { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1997 { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1998 { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1999 { 0x2020, 0xA0 }, /* DAGGER */
2000 { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
2001 { 0x2022, 0xA5 }, /* BULLET */
2002 { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
2003 { 0x2030, 0xE4 }, /* PER MILLE SIGN */
2004 { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
2005 { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
2006 { 0x2044, 0xDA }, /* FRACTION SLASH */
2007 { 0x20AC, 0xDB }, /* EURO SIGN */
2008 { 0x2122, 0xAA }, /* TRADE MARK SIGN */
2009 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
2010 { 0x2206, 0xC6 }, /* INCREMENT */
2011 { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
2012 { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
2013 { 0x221A, 0xC3 }, /* SQUARE ROOT */
2014 { 0x221E, 0xB0 }, /* INFINITY */
2015 { 0x222B, 0xBA }, /* INTEGRAL */
2016 { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
2017 { 0x2260, 0xAD }, /* NOT EQUAL TO */
2018 { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
2019 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
2020 { 0x25CA, 0xD7 }, /* LOZENGE */
2021 { 0xF8FF, 0xF0 }, /* Apple logo */
2022 { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
2023 { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
2024 };
2025
2026 static const FcCharMap AppleRoman = {
2027 AppleRomanEnt,
2028 sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
2029 };
2030
2031 static const FcCharEnt AdobeSymbolEnt[] = {
2032 { 0x0020, 0x20 }, /* SPACE # space */
2033 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
2034 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
2035 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
2036 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
2037 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
2038 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
2039 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
2040 { 0x002C, 0x2C }, /* COMMA # comma */
2041 { 0x002E, 0x2E }, /* FULL STOP # period */
2042 { 0x002F, 0x2F }, /* SOLIDUS # slash */
2043 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
2044 { 0x0031, 0x31 }, /* DIGIT ONE # one */
2045 { 0x0032, 0x32 }, /* DIGIT TWO # two */
2046 { 0x0033, 0x33 }, /* DIGIT THREE # three */
2047 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
2048 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
2049 { 0x0036, 0x36 }, /* DIGIT SIX # six */
2050 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
2051 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
2052 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
2053 { 0x003A, 0x3A }, /* COLON # colon */
2054 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
2055 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
2056 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
2057 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
2058 { 0x003F, 0x3F }, /* QUESTION MARK # question */
2059 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
2060 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
2061 { 0x005F, 0x5F }, /* LOW LINE # underscore */
2062 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
2063 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
2064 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
2065 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
2066 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
2067 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
2068 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
2069 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
2070 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
2071 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
2072 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
2073 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
2074 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
2075 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
2076 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
2077 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
2078 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
2079 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
2080 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
2081 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
2082 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
2083 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
2084 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
2085 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
2086 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
2087 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
2088 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
2089 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
2090 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
2091 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
2092 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
2093 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
2094 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
2095 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
2096 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
2097 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
2098 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
2099 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
2100 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
2101 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
2102 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
2103 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
2104 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
2105 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
2106 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
2107 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
2108 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
2109 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
2110 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
2111 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
2112 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
2113 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
2114 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
2115 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
2116 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
2117 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
2118 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
2119 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
2120 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
2121 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
2122 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
2123 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
2124 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
2125 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
2126 { 0x2022, 0xB7 }, /* BULLET # bullet */
2127 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
2128 { 0x2032, 0xA2 }, /* PRIME # minute */
2129 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
2130 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
2131 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
2132 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
2133 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
2134 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
2135 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
2136 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
2137 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
2138 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
2139 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
2140 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
2141 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
2142 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
2143 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
2144 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
2145 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
2146 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
2147 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
2148 { 0x2200, 0x22 }, /* FOR ALL # universal */
2149 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
2150 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
2151 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
2152 { 0x2206, 0x44 }, /* INCREMENT # Delta */
2153 { 0x2207, 0xD1 }, /* NABLA # gradient */
2154 { 0x2208, 0xCE }, /* ELEMENT OF # element */
2155 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
2156 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
2157 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
2158 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
2159 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
2160 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
2161 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
2162 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
2163 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
2164 { 0x221E, 0xA5 }, /* INFINITY # infinity */
2165 { 0x2220, 0xD0 }, /* ANGLE # angle */
2166 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
2167 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
2168 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
2169 { 0x222A, 0xC8 }, /* UNION # union */
2170 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
2171 { 0x2234, 0x5C }, /* THEREFORE # therefore */
2172 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
2173 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
2174 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
2175 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
2176 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
2177 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
2178 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
2179 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
2180 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
2181 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
2182 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
2183 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
2184 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
2185 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
2186 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
2187 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
2188 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
2189 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
2190 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
2191 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
2192 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
2193 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
2194 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
2195 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
2196 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
2197 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
2198 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
2199 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
2200 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
2201 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
2202 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
2203 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
2204 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
2205 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
2206 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2207 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
2208 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
2209 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
2210 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
2211 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
2212 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2213 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2214 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
2215 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2216 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
2217 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
2218 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
2219 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
2220 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
2221 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
2222 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
2223 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
2224 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
2225 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
2226 };
2227
2228 static const FcCharMap AdobeSymbol = {
2229 AdobeSymbolEnt,
2230 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2231 };
2232
2233 static const FcFontDecode fcFontDecoders[] = {
2234 { ft_encoding_unicode, 0, (1 << 21) - 1 },
2235 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
2236 { ft_encoding_apple_roman, &AppleRoman, (1 << 16) - 1 },
2237 };
2238
2239 #define NUM_DECODE (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
2240
2241 static const FcChar32 prefer_unicode[] = {
2242 0x20ac, /* EURO SIGN */
2243 };
2244
2245 #define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
2246
2247 FcChar32
2248 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2249 {
2250 int low, high, mid;
2251 FcChar16 bmp;
2252
2253 low = 0;
2254 high = map->nent - 1;
2255 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2256 return ~0;
2257 while (low <= high)
2258 {
2259 mid = (high + low) >> 1;
2260 bmp = map->ent[mid].bmp;
2261 if (ucs4 == bmp)
2262 return (FT_ULong) map->ent[mid].encode;
2263 if (ucs4 < bmp)
2264 high = mid - 1;
2265 else
2266 low = mid + 1;
2267 }
2268 return ~0;
2269 }
2270
2271 FcChar32
2272 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2273 {
2274 int i;
2275
2276 for (i = 0; i < map->nent; i++)
2277 if (map->ent[i].encode == private)
2278 return (FcChar32) map->ent[i].bmp;
2279 return ~0;
2280 }
2281
2282 const FcCharMap *
2283 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2284 {
2285 int i;
2286
2287 for (i = 0; i < NUM_DECODE; i++)
2288 if (fcFontDecoders[i].encoding == encoding)
2289 return fcFontDecoders[i].map;
2290 return 0;
2291 }
2292
2293 #include "../fc-glyphname/fcglyphname.h"
2294
2295 static FcChar32
2296 FcHashGlyphName (const FcChar8 *name)
2297 {
2298 FcChar32 h = 0;
2299 FcChar8 c;
2300
2301 while ((c = *name++))
2302 {
2303 h = ((h << 1) | (h >> 31)) ^ c;
2304 }
2305 return h;
2306 }
2307
2308 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2309 /*
2310 * Use Type1 glyph names for fonts which have reliable names
2311 * and which export an Adobe Custom mapping
2312 */
2313 static FcBool
2314 FcFreeTypeUseNames (FT_Face face)
2315 {
2316 FT_Int map;
2317
2318 if (!FT_Has_PS_Glyph_Names (face))
2319 return FcFalse;
2320 for (map = 0; map < face->num_charmaps; map++)
2321 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
2322 return FcTrue;
2323 return FcFalse;
2324 }
2325
2326 static const FcChar8 *
2327 FcUcs4ToGlyphName (FcChar32 ucs4)
2328 {
2329 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2330 int r = 0;
2331 FcGlyphId gn;
2332
2333 while ((gn = ucs_to_name[i]) != -1)
2334 {
2335 if (glyphs[gn].ucs == ucs4)
2336 return glyphs[gn].name;
2337 if (!r)
2338 {
2339 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2340 if (!r)
2341 r = 1;
2342 }
2343 i += r;
2344 if (i >= FC_GLYPHNAME_HASH)
2345 i -= FC_GLYPHNAME_HASH;
2346 }
2347 return 0;
2348 }
2349
2350 static FcChar32
2351 FcGlyphNameToUcs4 (FcChar8 *name)
2352 {
2353 FcChar32 h = FcHashGlyphName (name);
2354 int i = (int) (h % FC_GLYPHNAME_HASH);
2355 int r = 0;
2356 FcGlyphId gn;
2357
2358 while ((gn = name_to_ucs[i]) != -1)
2359 {
2360 if (!strcmp ((char *) name, (char *) glyphs[gn].name))
2361 return glyphs[gn].ucs;
2362 if (!r)
2363 {
2364 r = (int) (h % FC_GLYPHNAME_REHASH);
2365 if (!r)
2366 r = 1;
2367 }
2368 i += r;
2369 if (i >= FC_GLYPHNAME_HASH)
2370 i -= FC_GLYPHNAME_HASH;
2371 }
2372 return 0xffff;
2373 }
2374
2375 /*
2376 * Work around a bug in some FreeType versions which fail
2377 * to correctly bounds check glyph name buffers and overwrite
2378 * the stack. As Postscript names have a limit of 127 characters,
2379 * this should be sufficient.
2380 */
2381
2382 #if FC_GLYPHNAME_MAXLEN < 127
2383 # define FC_GLYPHNAME_BUFLEN 127
2384 #else
2385 # define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2386 #endif
2387
2388 /*
2389 * Search through a font for a glyph by name. This is
2390 * currently a linear search as there doesn't appear to be
2391 * any defined order within the font
2392 */
2393 static FT_UInt
2394 FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
2395 {
2396 FT_UInt gindex;
2397 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2398
2399 for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
2400 {
2401 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2402 if (!strcmp ((char *) name, (char *) name_buf))
2403 return gindex;
2404 }
2405 return 0;
2406 }
2407 #endif
2408
2409 /*
2410 * Map a UCS4 glyph to a glyph index. Use all available encoding
2411 * tables to try and find one that works. This information is expected
2412 * to be cached by higher levels, so performance isn't critical
2413 */
2414
2415 FT_UInt
2416 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2417 {
2418 int initial, offset, decode;
2419 FT_UInt glyphindex;
2420 FcChar32 charcode;
2421 int p;
2422
2423 initial = 0;
2424
2425 if (!face)
2426 return 0;
2427
2428 /*
2429 * Find the current encoding
2430 */
2431 if (face->charmap)
2432 {
2433 for (; initial < NUM_DECODE; initial++)
2434 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2435 break;
2436 if (initial == NUM_DECODE)
2437 initial = 0;
2438 }
2439 for (p = 0; p < NUM_PREFER_UNICODE; p++)
2440 if (ucs4 == prefer_unicode[p])
2441 {
2442 initial = 0;
2443 break;
2444 }
2445 /*
2446 * Check each encoding for the glyph, starting with the current one
2447 */
2448 for (offset = 0; offset < NUM_DECODE; offset++)
2449 {
2450 decode = (initial + offset) % NUM_DECODE;
2451 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2452 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2453 continue;
2454 if (fcFontDecoders[decode].map)
2455 {
2456 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
2457 if (charcode == ~0U)
2458 continue;
2459 }
2460 else
2461 charcode = ucs4;
2462 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2463 if (glyphindex)
2464 return glyphindex;
2465 }
2466 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2467 /*
2468 * Check postscript name table if present
2469 */
2470 if (FcFreeTypeUseNames (face))
2471 {
2472 const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
2473 if (name)
2474 {
2475 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2476 if (glyphindex)
2477 return glyphindex;
2478 }
2479 }
2480 #endif
2481 return 0;
2482 }
2483
2484 static FcBool
2485 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
2486 FT_UInt glyph, FcBlanks *blanks,
2487 FT_Pos *advance)
2488 {
2489 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2490 FT_GlyphSlot slot;
2491
2492 /*
2493 * When using scalable fonts, only report those glyphs
2494 * which can be scaled; otherwise those fonts will
2495 * only be available at some sizes, and never when
2496 * transformed. Avoid this by simply reporting bitmap-only
2497 * glyphs as missing
2498 */
2499 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2500 load_flags |= FT_LOAD_NO_BITMAP;
2501
2502 if (FT_Load_Glyph (face, glyph, load_flags))
2503 return FcFalse;
2504
2505 slot = face->glyph;
2506 if (!glyph)
2507 return FcFalse;
2508
2509 *advance = slot->metrics.horiAdvance;
2510
2511 switch (slot->format) {
2512 case ft_glyph_format_bitmap:
2513 /*
2514 * Bitmaps are assumed to be reasonable; if
2515 * this proves to be a rash assumption, this
2516 * code can be easily modified
2517 */
2518 return FcTrue;
2519 case ft_glyph_format_outline:
2520 /*
2521 * Glyphs with contours are always OK
2522 */
2523 if (slot->outline.n_contours != 0)
2524 return FcTrue;
2525 /*
2526 * Glyphs with no contours are only OK if
2527 * they're members of the Blanks set specified
2528 * in the configuration. If blanks isn't set,
2529 * then allow any glyph to be blank
2530 */
2531 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2532 return FcTrue;
2533 /* fall through ... */
2534 default:
2535 break;
2536 }
2537 return FcFalse;
2538 }
2539
2540 #define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
2541 #define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
2542 #define FC_ABS(a) ((a) < 0 ? -(a) : (a))
2543 #define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
2544
2545 FcCharSet *
2546 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
2547 {
2548 FcChar32 page, off, ucs4;
2549 #ifdef CHECK
2550 FcChar32 font_max = 0;
2551 #endif
2552 FcCharSet *fcs;
2553 FcCharLeaf *leaf;
2554 const FcCharMap *map;
2555 int o;
2556 int i;
2557 FT_UInt glyph;
2558 FT_Pos advance, advance_one = 0, advance_two = 0;
2559 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
2560
2561 fcs = FcCharSetCreate ();
2562 if (!fcs)
2563 goto bail0;
2564
2565 #ifdef CHECK
2566 printf ("Family %s style %s\n", face->family_name, face->style_name);
2567 #endif
2568 for (o = 0; o < NUM_DECODE; o++)
2569 {
2570 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2571 continue;
2572 map = fcFontDecoders[o].map;
2573 if (map)
2574 {
2575 /*
2576 * Non-Unicode tables are easy; there's a list of all possible
2577 * characters
2578 */
2579 for (i = 0; i < map->nent; i++)
2580 {
2581 ucs4 = map->ent[i].bmp;
2582 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
2583 if (glyph &&
2584 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2585 {
2586 /*
2587 * ignore glyphs with zero advance. They’re
2588 * combining characters, and while their behaviour
2589 * isn’t well defined for monospaced applications in
2590 * Unicode, there are many fonts which include
2591 * zero-width combining characters in otherwise
2592 * monospaced fonts.
2593 */
2594 if (advance)
2595 {
2596 if (!has_advance)
2597 {
2598 has_advance = FcTrue;
2599 advance_one = advance;
2600 }
2601 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2602 {
2603 if (fixed_advance)
2604 {
2605 dual_advance = FcTrue;
2606 fixed_advance = FcFalse;
2607 advance_two = advance;
2608 }
2609 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2610 dual_advance = FcFalse;
2611 }
2612 }
2613
2614 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2615 if (!leaf)
2616 goto bail1;
2617 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2618 #ifdef CHECK
2619 if (ucs4 > font_max)
2620 font_max = ucs4;
2621 #endif
2622 }
2623 }
2624 }
2625 else
2626 {
2627 page = ~0;
2628 leaf = NULL;
2629 ucs4 = FT_Get_First_Char (face, &glyph);
2630 while (glyph != 0)
2631 {
2632 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2633 {
2634 if (advance)
2635 {
2636 if (!has_advance)
2637 {
2638 has_advance = FcTrue;
2639 advance_one = advance;
2640 }
2641 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2642 {
2643 if (fixed_advance)
2644 {
2645 dual_advance = FcTrue;
2646 fixed_advance = FcFalse;
2647 advance_two = advance;
2648 }
2649 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2650 dual_advance = FcFalse;
2651 }
2652 }
2653
2654 if ((ucs4 >> 8) != page)
2655 {
2656 page = (ucs4 >> 8);
2657 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2658 if (!leaf)
2659 goto bail1;
2660 }
2661 off = ucs4 & 0xff;
2662 leaf->map[off >> 5] |= (1 << (off & 0x1f));
2663 #ifdef CHECK
2664 if (ucs4 > font_max)
2665 font_max = ucs4;
2666 #endif
2667 }
2668 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2669 }
2670 #ifdef CHECK
2671 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2672 {
2673 FcBool FT_Has, FC_Has;
2674
2675 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2676 FC_Has = FcCharSetHasChar (fcs, ucs4);
2677 if (FT_Has != FC_Has)
2678 {
2679 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2680 }
2681 }
2682 #endif
2683 }
2684 }
2685 #if HAVE_FT_HAS_PS_GLYPH_NAMES
2686 /*
2687 * Add mapping from PS glyph names if available
2688 */
2689 if (FcFreeTypeUseNames (face))
2690 {
2691 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
2692
2693 for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
2694 {
2695 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
2696 {
2697 ucs4 = FcGlyphNameToUcs4 (name_buf);
2698 if (ucs4 != 0xffff &&
2699 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2700 {
2701 if (advance)
2702 {
2703 if (!has_advance)
2704 {
2705 has_advance = FcTrue;
2706 advance_one = advance;
2707 }
2708 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2709 {
2710 if (fixed_advance)
2711 {
2712 dual_advance = FcTrue;
2713 fixed_advance = FcFalse;
2714 advance_two = advance;
2715 }
2716 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2717 dual_advance = FcFalse;
2718 }
2719 }
2720 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2721 if (!leaf)
2722 goto bail1;
2723 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2724 #ifdef CHECK
2725 if (ucs4 > font_max)
2726 font_max = ucs4;
2727 #endif
2728 }
2729 }
2730 }
2731 }
2732 #endif
2733 #ifdef CHECK
2734 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2735 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2736 {
2737 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
2738 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2739
2740 if (has_char && !has_bit)
2741 {
2742 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2743 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2744 else
2745 printf ("Bitmap missing char 0x%x\n", ucs4);
2746 }
2747 else if (!has_char && has_bit)
2748 printf ("Bitmap extra char 0x%x\n", ucs4);
2749 }
2750 #endif
2751 if (fixed_advance)
2752 *spacing = FC_MONO;
2753 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
2754 *spacing = FC_DUAL;
2755 else
2756 *spacing = FC_PROPORTIONAL;
2757 return fcs;
2758 bail1:
2759 FcCharSetDestroy (fcs);
2760 bail0:
2761 return 0;
2762 }
2763
2764 FcCharSet *
2765 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2766 {
2767 int spacing;
2768
2769 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2770 }
2771
2772
2773 #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2774 #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2775 #define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2776 #define TT_Err_Ok FT_Err_Ok
2777 #define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
2778 #define TTO_Err_Empty_Script 0x1005
2779 #define TTO_Err_Invalid_SubTable 0x1001
2780
2781 #define OTLAYOUT_HEAD "otlayout:"
2782 #define OTLAYOUT_HEAD_LEN 9
2783 #define OTLAYOUT_ID_LEN 4
2784 /* space + head + id */
2785 #define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2786
2787 /*
2788 * This is a bit generous; the registry has only lower case and space
2789 * except for 'DFLT'.
2790 */
2791 #define FcIsSpace(x) (040 == (x))
2792 #define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2793
2794 static void
2795 addtag(FcChar8 *complex, FT_ULong tag)
2796 {
2797 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2798
2799 tagstring[0] = (FcChar8)(tag >> 24),
2800 tagstring[1] = (FcChar8)(tag >> 16),
2801 tagstring[2] = (FcChar8)(tag >> 8),
2802 tagstring[3] = (FcChar8)(tag);
2803 tagstring[4] = '\0';
2804
2805 /* skip tags which aren't alphabetic, under the assumption that
2806 * they're probably broken
2807 */
2808 if (!FcIsValidScript(tagstring[0]) ||
2809 !FcIsValidScript(tagstring[1]) ||
2810 !FcIsValidScript(tagstring[2]) ||
2811 !FcIsValidScript(tagstring[3]))
2812 return;
2813
2814 if (*complex != '\0')
2815 strcat ((char *) complex, " ");
2816 strcat ((char *) complex, "otlayout:");
2817 strcat ((char *) complex, (char *) tagstring);
2818 }
2819
2820 static int
2821 compareulong (const void *a, const void *b)
2822 {
2823 const FT_ULong *ua = (const FT_ULong *) a;
2824 const FT_ULong *ub = (const FT_ULong *) b;
2825 return *ua - *ub;
2826 }
2827
2828
2829 static FT_Error
2830 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
2831 {
2832 FT_ULong cur_offset, new_offset, base_offset;
2833 FT_Stream stream = face->stream;
2834 FT_Error error;
2835 FT_UShort n, p;
2836 FT_Memory memory;
2837
2838 if ( !stream )
2839 return TT_Err_Invalid_Face_Handle;
2840
2841 memory = stream->memory;
2842
2843 if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2844 return error;
2845
2846 base_offset = ftglue_stream_pos ( stream );
2847
2848 /* skip version */
2849
2850 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2851 return error;
2852
2853 new_offset = GET_UShort() + base_offset;
2854
2855 ftglue_stream_frame_exit( stream );
2856
2857 cur_offset = ftglue_stream_pos( stream );
2858
2859 if ( ftglue_stream_seek( stream, new_offset ) != TT_Err_Ok )
2860 return error;
2861
2862 base_offset = ftglue_stream_pos( stream );
2863
2864 if ( ftglue_stream_frame_enter( stream, 2L ) )
2865 return error;
2866
2867 *script_count = GET_UShort ();
2868
2869 ftglue_stream_frame_exit( stream );
2870
2871 *stags = ftglue_alloc(memory, *script_count * sizeof( FT_ULong ), &error);
2872
2873 if (error)
2874 return error;
2875
2876 p = 0;
2877 for ( n = 0; n < *script_count; n++ )
2878 {
2879 if ( ftglue_stream_frame_enter( stream, 6L ) )
2880 goto Fail;
2881
2882 (*stags)[p] = GET_ULong ();
2883 new_offset = GET_UShort () + base_offset;
2884
2885 ftglue_stream_frame_exit( stream );
2886
2887 cur_offset = ftglue_stream_pos( stream );
2888
2889 error = ftglue_stream_seek( stream, new_offset );
2890
2891 if ( error == TT_Err_Ok )
2892 p++;
2893
2894 (void)ftglue_stream_seek( stream, cur_offset );
2895 }
2896
2897 if (!p)
2898 {
2899 error = TTO_Err_Invalid_SubTable;
2900 goto Fail;
2901 }
2902
2903 /* sort the tag list before returning it */
2904 qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
2905
2906 return TT_Err_Ok;
2907
2908 Fail:
2909 *script_count = 0;
2910 ftglue_free( memory, *stags );
2911 *stags = NULL;
2912 return error;
2913 }
2914
2915 static FcChar8 *
2916 FcFontCapabilities(FT_Face face)
2917 {
2918 FcBool issilgraphitefont = 0;
2919 FT_Error err;
2920 FT_ULong len = 0;
2921 FT_ULong *gsubtags=NULL, *gpostags=NULL;
2922 FT_UShort gsub_count=0, gpos_count=0;
2923 FT_ULong maxsize;
2924 FT_Memory memory = face->stream->memory;
2925 FcChar8 *complex = NULL;
2926 int indx1 = 0, indx2 = 0;
2927
2928 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2929 issilgraphitefont = ( err == FT_Err_Ok);
2930
2931 if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
2932 gpos_count = 0;
2933 if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
2934 gsub_count = 0;
2935
2936 if (!issilgraphitefont && !gsub_count && !gpos_count)
2937 goto bail;
2938
2939 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2940 (issilgraphitefont ? 13 : 0));
2941 complex = malloc (sizeof (FcChar8) * maxsize);
2942 if (!complex)
2943 goto bail;
2944
2945 complex[0] = '\0';
2946 if (issilgraphitefont)
2947 strcpy((char *) complex, "ttable:Silf ");
2948
2949 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2950 if (indx1 == gsub_count) {
2951 addtag(complex, gpostags[indx2]);
2952 indx2++;
2953 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2954 addtag(complex, gsubtags[indx1]);
2955 indx1++;
2956 } else if (gsubtags[indx1] == gpostags[indx2]) {
2957 addtag(complex, gsubtags[indx1]);
2958 indx1++;
2959 indx2++;
2960 } else {
2961 addtag(complex, gpostags[indx2]);
2962 indx2++;
2963 }
2964 }
2965 if (FcDebug () & FC_DBG_SCANV)
2966 printf("complex features in this font: %s\n", complex);
2967 bail:
2968 ftglue_free(memory, gsubtags);
2969 ftglue_free(memory, gpostags);
2970 return complex;
2971 }
2972
2973 #define __fcfreetype__
2974 #include "fcaliastail.h"
2975 #undef __fcfreetype__