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