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