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