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